@@ -338,18 +338,39 @@ For `processingStrategy=STORE_ONLY` events, the platform connector should:
3383382 . Not create node conditions
3393393 . Not create Kubernetes events
340340
341- File: ` platform-connectors/pkg/connectors/kubernetes/process_node_events.go `
341+ ** Normalization:** Platform connector normalizes ` processingStrategy ` in the gRPC server handler before any processing or enqueuing. If the field is missing or set to ` UNSPECIFIED ` (e.g., from custom monitors), it defaults to ` EXECUTE_REMEDIATION ` . This ensures all events in the database have an explicit strategy, providing consistent behavior across all modules.
342+
343+ File: ` platform-connectors/pkg/server/platform_connector_server.go `
342344
343- Add skip logic in ` processHealthEvents ()` method to skip adding node condition/event :
345+ Add normalization in ` HealthEventOccurredV1 ()` method before enqueuing to ring buffers :
344346
345347``` go
346- func (r *K8sConnector ) processHealthEvents (ctx context .Context , healthEvents *protos .HealthEvents ) error {
347- var nodeConditions []corev1.NodeCondition
348+ func (p *PlatformConnectorServer ) HealthEventOccurredV1 (ctx context.Context,
349+ he *pb.HealthEvents) (*empty.Empty, error) {
350+ slog.Info (" Health events received" , " events" , he)
351+
352+ healthEventsReceived.Add (float64 (len (he.Events )))
353+
354+ // Custom monitors that don't set processingStrategy will default to EXECUTE_REMEDIATION.
355+ for _ , event := range he.Events {
356+ if event.ProcessingStrategy == pb.ProcessingStrategy_UNSPECIFIED {
357+ event.ProcessingStrategy = pb.ProcessingStrategy_EXECUTE_REMEDIATION
358+ }
359+ }
360+
361+ // ... pipeline processing and enqueuing to ring buffers
362+ }
363+ ```
364+
365+ File: ` platform-connectors/pkg/connectors/kubernetes/process_node_events.go `
366+
367+ Add skip logic for ` STORE_ONLY ` events in ` filterProcessableEvents() ` method:
348368
349- // NEW: Filter out STORE_ONLY events - they should not modify node conditions or create K8s events
369+ ``` go
370+ func filterProcessableEvents (healthEvents *protos .HealthEvents ) []*protos .HealthEvent {
350371 var processableEvents []*protos.HealthEvent
351372 for _ , healthEvent := range healthEvents.Events {
352- if healthEvent.ProcessingStrategy == protos.STORE_ONLY {
373+ if healthEvent.ProcessingStrategy == protos.ProcessingStrategy_STORE_ONLY {
353374 slog.Info (" Skipping STORE_ONLY event - no node conditions or K8s events will be created" ,
354375 " node" , healthEvent.NodeName ,
355376 " checkName" , healthEvent.CheckName )
@@ -358,7 +379,7 @@ func (r *K8sConnector) processHealthEvents(ctx context.Context, healthEvents *pr
358379 processableEvents = append (processableEvents, healthEvent)
359380 }
360381
361- // ... existing code
382+ return processableEvents
362383}
363384```
364385---
@@ -404,35 +425,49 @@ We need new methods in mongodb and postgres pipeline builder:
404425File: ` store-client/pkg/client/mongodb_pipeline_builder.go `
405426
406427``` go
407- // BuildProcessableHealthEventInsertsPipeline creates a pipeline that watches for all processable health event inserts.
428+ // BuildProcessableHealthEventInsertsPipeline creates a pipeline that watches for
429+ // all EXECUTE_REMEDIATION health event inserts.
430+ //
431+ // Backward Compatibility: This pipeline uses $or to match events where processingstrategy is either:
432+ // - EXECUTE_REMEDIATION (new events from NVSentinel health monitors)
433+ // - Missing/null (old events created before update, custom monitors, or circuit breaker backlog)
408434func (b *MongoDBPipelineBuilder ) BuildProcessableHealthEventInsertsPipeline () datastore .Pipeline {
409435 return datastore.ToPipeline (
410436 datastore.D (
411437 datastore.E (" $match" , datastore.D (
412438 datastore.E (" operationType" , datastore.D (
413439 datastore.E (" $in" , datastore.A (" insert" )),
414440 )),
415- datastore.E (" fullDocument.healthevent.processingstrategy" , " EXECUTE_REMEDIATION" ),
441+ // Exclude STORE_ONLY events, but include EXECUTE_REMEDIATION and missing field
442+ datastore.E (" $or" , datastore.A (
443+ datastore.D (datastore.E (" fullDocument.healthevent.processingstrategy" , int32 (protos.ProcessingStrategy_EXECUTE_REMEDIATION ))),
444+ datastore.D (datastore.E (" fullDocument.healthevent.processingstrategy" , datastore.D (datastore.E (" $exists" , false )))),
445+ )),
416446 )),
417447 ),
418448 )
419449}
420450
421- // BuildProcessableNonFatalUnhealthyInsertsPipeline creates a pipeline for non-fatal unhealthy events
422- // excluding STORE_ONLY events.
451+ // BuildProcessableNonFatalUnhealthyInsertsPipeline creates a pipeline for non-fatal, unhealthy event inserts
452+ // excluding STORE_ONLY events. This is used by health-events-analyzer for pattern analysis.
453+ //
454+ // Backward Compatibility: Uses $or to include EXECUTE_REMEDIATION and missing field.
423455func (b *MongoDBPipelineBuilder ) BuildProcessableNonFatalUnhealthyInsertsPipeline () datastore .Pipeline {
424456 return datastore.ToPipeline (
425457 datastore.D (
426458 datastore.E (" $match" , datastore.D (
427459 datastore.E (" operationType" , " insert" ),
428460 datastore.E (" fullDocument.healthevent.agent" , datastore.D (datastore.E (" $ne" , " health-events-analyzer" ))),
429461 datastore.E (" fullDocument.healthevent.ishealthy" , false ),
430- datastore.E (" fullDocument.healthevent.processingstrategy" , " EXECUTE_REMEDIATION" ),
462+ // Exclude STORE_ONLY events, but include EXECUTE_REMEDIATION and missing field
463+ datastore.E (" $or" , datastore.A (
464+ datastore.D (datastore.E (" fullDocument.healthevent.processingstrategy" , int32 (protos.ProcessingStrategy_EXECUTE_REMEDIATION ))),
465+ datastore.D (datastore.E (" fullDocument.healthevent.processingstrategy" , datastore.D (datastore.E (" $exists" , false )))),
466+ )),
431467 )),
432468 ),
433469 )
434470}
435-
436471```
437472
438473Same method required in postgres builder
@@ -441,35 +476,46 @@ File: `store-client/pkg/client/postgresql_pipeline_builder.go`
441476
442477``` go
443478// BuildProcessableHealthEventInsertsPipeline creates a pipeline that watches for health event inserts
444- // excluding STORE_ONLY events.
479+ // with processingStrategy=EXECUTE_REMEDIATION
480+ //
481+ // Backward Compatibility: Uses $or to include EXECUTE_REMEDIATION and missing field.
445482func (b *PostgreSQLPipelineBuilder ) BuildProcessableHealthEventInsertsPipeline () datastore .Pipeline {
446483 return datastore.ToPipeline (
447484 datastore.D (
448485 datastore.E (" $match" , datastore.D (
449486 datastore.E (" operationType" , datastore.D (
450487 datastore.E (" $in" , datastore.A (" insert" )),
451488 )),
452- datastore.E (" fullDocument.healthevent.processingstrategy" , " EXECUTE_REMEDIATION" ),
489+ // Exclude STORE_ONLY events, but include EXECUTE_REMEDIATION and missing field
490+ datastore.E (" $or" , datastore.A (
491+ datastore.D (datastore.E (" fullDocument.healthevent.processingstrategy" , int32 (protos.ProcessingStrategy_EXECUTE_REMEDIATION ))),
492+ datastore.D (datastore.E (" fullDocument.healthevent.processingstrategy" , datastore.D (datastore.E (" $exists" , false )))),
493+ )),
453494 )),
454495 ),
455496 )
456497}
457498
458- // BuildProcessableNonFatalUnhealthyInsertsPipeline creates a pipeline for non-fatal unhealthy events
459- // excluding STORE_ONLY events.
499+ // BuildProcessableNonFatalUnhealthyInsertsPipeline creates a pipeline for non-fatal, unhealthy event inserts
500+ // excluding STORE_ONLY events. For PostgreSQL, handles both INSERT and UPDATE operations.
501+ //
502+ // Backward Compatibility: Uses $or to include EXECUTE_REMEDIATION and missing field.
460503func (b *PostgreSQLPipelineBuilder ) BuildProcessableNonFatalUnhealthyInsertsPipeline () datastore .Pipeline {
461504 return datastore.ToPipeline (
462505 datastore.D (
463506 datastore.E (" $match" , datastore.D (
464507 datastore.E (" operationType" , datastore.D (datastore.E (" $in" , datastore.A (" insert" , " update" )))),
465508 datastore.E (" fullDocument.healthevent.agent" , datastore.D (datastore.E (" $ne" , " health-events-analyzer" ))),
466509 datastore.E (" fullDocument.healthevent.ishealthy" , false ),
467- datastore.E (" fullDocument.healthevent.processingstrategy" , " EXECUTE_REMEDIATION" ),
510+ // Exclude STORE_ONLY events, but include EXECUTE_REMEDIATION and missing field
511+ datastore.E (" $or" , datastore.A (
512+ datastore.D (datastore.E (" fullDocument.healthevent.processingstrategy" , int32 (protos.ProcessingStrategy_EXECUTE_REMEDIATION ))),
513+ datastore.D (datastore.E (" fullDocument.healthevent.processingstrategy" , datastore.D (datastore.E (" $exists" , false )))),
514+ )),
468515 )),
469516 ),
470517 )
471518}
472-
473519```
474520
475521---
@@ -532,6 +578,8 @@ func createPipeline() interface{} {
532578
533579Update the default pipeline query to exclude ` processingStrategy=STORE_ONLY ` events. We need this condition for every rule that's why we are adding it at code level instead of keeping it at config file level.
534580
581+ ** Backward Compatibility Note:** Historical events in the database (created before this feature) won't have the ` processingstrategy ` field. These old events should be treated as ` EXECUTE_REMEDIATION ` (they were meant to be processed). We use ` $or ` to explicitly match both ` EXECUTE_REMEDIATION ` and a missing field to ensure backward compatibility. Other modules and health monitors do not require changes since they only act on newly inserted events, which will already have the ` processingStrategy ` field set (all health monitors run in ` EXECUTE_REMEDIATION ` mode by default).
582+
535583File: ` health-events-analyzer/pkg/reconciler/reconciler.go `
536584
537585``` go
@@ -542,11 +590,18 @@ func (r *Reconciler) getPipelineStages(
542590 // CRITICAL: Always start with agent filter to exclude events from health-events-analyzer itself
543591 // This prevents the analyzer from matching its own generated events, which would cause
544592 // infinite loops and incorrect rule evaluations
593+ //
594+ // Backward Compatibility: Use $or to include events where processingstrategy is either
595+ // EXECUTE_REMEDIATION or missing (old events created before this feature was added).
596+ // Old events without this field should be treated as EXECUTE_REMEDIATION.
545597 pipeline := []map [string ]interface {}{
546598 {
547599 " $match" : map [string ]interface {}{
548- " healthevent.agent" : map [string ]interface {}{" $ne" : " health-events-analyzer" },
549- " healthevent.processingstrategy" : map [string ]interface {}{" $eq" : " EXECUTE_REMEDIATION" }, // Exclude STORE_ONLY by default
600+ " healthevent.agent" : map [string ]interface {}{" $ne" : " health-events-analyzer" },
601+ " $or" : []map [string ]interface {}{
602+ {" healthevent.processingstrategy" : " EXECUTE_REMEDIATION" },
603+ {" healthevent.processingstrategy" : map [string ]interface {}{" $exists" : false }},
604+ },
550605 },
551606 },
552607 }
0 commit comments