11package incident
22
33import (
4+ "context"
45 "errors"
56 "fmt"
67 "github.com/icinga/icinga-notifications/internal/config"
@@ -75,14 +76,14 @@ func (i *Incident) HasManager() bool {
7576}
7677
7778// ProcessEvent processes the given event for the current incident.
78- func (i * Incident ) ProcessEvent (tx * sqlx.Tx , ev event.Event , created bool ) error {
79+ func (i * Incident ) ProcessEvent (ctx context. Context , tx * sqlx.Tx , ev event.Event , created bool ) error {
7980 i .Lock ()
8081 defer i .Unlock ()
8182
8283 i .runtimeConfig .RLock ()
8384 defer i .runtimeConfig .RUnlock ()
8485
85- err := i .Object .UpdateMetadata (tx , ev .SourceId , ev .Name , utils .ToDBString (ev .URL ), ev .ExtraTags )
86+ err := i .Object .UpdateMetadata (ctx , tx , ev .SourceId , ev .Name , utils .ToDBString (ev .URL ), ev .ExtraTags )
8687 if err != nil {
8788 i .logger .Errorw ("can't update object metadata" , zap .String ("object" , i .Object .DisplayName ()), zap .Error (err ))
8889
@@ -91,7 +92,7 @@ func (i *Incident) ProcessEvent(tx *sqlx.Tx, ev event.Event, created bool) error
9192
9293 if ev .ID == 0 {
9394 eventRow := event .NewEventRow (ev , i .Object .ID )
94- eventID , err := utils .InsertAndFetchId (tx , utils .BuildInsertStmtWithout (i .db , eventRow , "id" ), eventRow )
95+ eventID , err := utils .InsertAndFetchId (ctx , tx , utils .BuildInsertStmtWithout (i .db , eventRow , "id" ), eventRow )
9596 if err != nil {
9697 i .logger .Errorw (
9798 "failed insert event and fetch its ID" , zap .String ("object" , i .ObjectDisplayName ()),
@@ -105,13 +106,13 @@ func (i *Incident) ProcessEvent(tx *sqlx.Tx, ev event.Event, created bool) error
105106 }
106107
107108 if created {
108- err := i .processIncidentOpenedEvent (tx , ev )
109+ err := i .processIncidentOpenedEvent (ctx , tx , ev )
109110 if err != nil {
110111 return err
111112 }
112113 }
113114
114- if err := i .AddEvent (tx , & ev ); err != nil {
115+ if err := i .AddEvent (ctx , tx , & ev ); err != nil {
115116 i .logger .Errorw (
116117 "can't insert incident event to the database" , zap .String ("object" , i .ObjectDisplayName ()),
117118 zap .String ("incident" , i .String ()), zap .Error (err ),
@@ -121,28 +122,39 @@ func (i *Incident) ProcessEvent(tx *sqlx.Tx, ev event.Event, created bool) error
121122 }
122123
123124 if ev .Type == event .TypeAcknowledgement {
124- return i .processAcknowledgementEvent (tx , ev )
125+ // The current request has been processed successfully, so update the in-memory objects cache.
126+ i .Object .UpdateCache ()
127+
128+ return i .processAcknowledgementEvent (ctx , tx , ev )
125129 }
126130
127- causedBy , err := i .processSeverityChangedEvent (tx , ev )
131+ causedBy , err := i .processSeverityChangedEvent (ctx , tx , ev )
128132 if err != nil {
129133 return err
130134 }
131135
132136 // Check if any (additional) rules match this object. Filters of rules that already have a state don't have
133137 // to be checked again, these rules already matched and stay effective for the ongoing incident.
134- causedBy , err = i .evaluateRules (tx , ev .ID , causedBy )
138+ causedBy , err = i .evaluateRules (ctx , tx , ev .ID , causedBy )
135139 if err != nil {
136140 return err
137141 }
138142
139143 // Re-evaluate escalations based on the newly evaluated rules.
140144 i .evaluateEscalations ()
141145
142- return i .notifyContacts (tx , & ev , causedBy )
146+ err = i .notifyContacts (ctx , tx , & ev , causedBy )
147+ if err != nil {
148+ return err
149+ }
150+
151+ // The current request has been processed successfully, so update the in-memory objects cache.
152+ i .Object .UpdateCache ()
153+
154+ return nil
143155}
144156
145- func (i * Incident ) processSeverityChangedEvent (tx * sqlx.Tx , ev event.Event ) (types.Int , error ) {
157+ func (i * Incident ) processSeverityChangedEvent (ctx context. Context , tx * sqlx.Tx , ev event.Event ) (types.Int , error ) {
146158 oldIncidentSeverity := i .Severity ()
147159 oldSourceSeverity := i .SeverityBySource [ev .SourceId ]
148160 if oldSourceSeverity == event .SeverityNone {
@@ -169,7 +181,7 @@ func (i *Incident) processSeverityChangedEvent(tx *sqlx.Tx, ev event.Event) (typ
169181 OldSeverity : oldSourceSeverity ,
170182 Message : utils .ToDBString (ev .Message ),
171183 }
172- causedByHistoryId , err := i .AddHistory (tx , history , true )
184+ causedByHistoryId , err := i .AddHistory (ctx , tx , history , true )
173185 if err != nil {
174186 i .logger .Errorw (
175187 "can't insert source severity changed history to the database" , zap .String ("object" , i .ObjectDisplayName ()),
@@ -179,7 +191,7 @@ func (i *Incident) processSeverityChangedEvent(tx *sqlx.Tx, ev event.Event) (typ
179191 return types.Int {}, errors .New ("can't insert source severity changed history to the database" )
180192 }
181193
182- if err = i .AddSourceSeverity (tx , ev .Severity , ev .SourceId ); err != nil {
194+ if err = i .AddSourceSeverity (ctx , tx , ev .Severity , ev .SourceId ); err != nil {
183195 i .logger .Errorw (
184196 "failed to upsert source severity" , zap .String ("object" , i .ObjectDisplayName ()), zap .String ("incident" , i .String ()),
185197 zap .Error (err ),
@@ -199,7 +211,7 @@ func (i *Incident) processSeverityChangedEvent(tx *sqlx.Tx, ev event.Event) (typ
199211 zap .String ("object" , i .ObjectDisplayName ()), zap .String ("incident" , i .String ()),
200212 )
201213
202- if err = i .Sync (tx ); err != nil {
214+ if err = i .Sync (ctx , tx ); err != nil {
203215 i .logger .Errorw (
204216 "failed to update incident severity" , zap .String ("object" , i .ObjectDisplayName ()), zap .String ("incident" , i .String ()),
205217 zap .Error (err ),
@@ -216,7 +228,7 @@ func (i *Incident) processSeverityChangedEvent(tx *sqlx.Tx, ev event.Event) (typ
216228 OldSeverity : oldIncidentSeverity ,
217229 CausedByIncidentHistoryID : causedByHistoryId ,
218230 }
219- if causedByHistoryId , err = i .AddHistory (tx , history , true ); err != nil {
231+ if causedByHistoryId , err = i .AddHistory (ctx , tx , history , true ); err != nil {
220232 i .logger .Errorw (
221233 "failed to insert incident severity changed history" , zap .String ("object" , i .ObjectDisplayName ()),
222234 zap .String ("incident" , i .String ()), zap .Error (err ),
@@ -233,7 +245,7 @@ func (i *Incident) processSeverityChangedEvent(tx *sqlx.Tx, ev event.Event) (typ
233245 RemoveCurrent (i .Object )
234246
235247 incidentRow := & IncidentRow {ID : i .incidentRowID , RecoveredAt : types .UnixMilli (i .RecoveredAt )}
236- _ , err = tx .NamedExec ( `UPDATE "incident" SET "recovered_at" = :recovered_at WHERE id = :id` , incidentRow )
248+ _ , err = tx .NamedExecContext ( ctx , `UPDATE "incident" SET "recovered_at" = :recovered_at WHERE id = :id` , incidentRow )
237249 if err != nil {
238250 i .logger .Errorw (
239251 "failed to close incident" , zap .String ("object" , i .ObjectDisplayName ()), zap .String ("incident" , i .String ()),
@@ -249,7 +261,7 @@ func (i *Incident) processSeverityChangedEvent(tx *sqlx.Tx, ev event.Event) (typ
249261 Type : Closed ,
250262 }
251263
252- _ , err = i .AddHistory (tx , history , false )
264+ _ , err = i .AddHistory (ctx , tx , history , false )
253265 if err != nil {
254266 i .logger .Errorw (
255267 "can't insert incident closed history to the database" , zap .String ("object" , i .ObjectDisplayName ()),
@@ -263,9 +275,9 @@ func (i *Incident) processSeverityChangedEvent(tx *sqlx.Tx, ev event.Event) (typ
263275 return causedByHistoryId , nil
264276}
265277
266- func (i * Incident ) processIncidentOpenedEvent (tx * sqlx.Tx , ev event.Event ) error {
278+ func (i * Incident ) processIncidentOpenedEvent (ctx context. Context , tx * sqlx.Tx , ev event.Event ) error {
267279 i .StartedAt = ev .Time
268- if err := i .Sync (tx ); err != nil {
280+ if err := i .Sync (ctx , tx ); err != nil {
269281 i .logger .Errorw (
270282 "can't insert incident to the database" , zap .String ("incident" , i .String ()),
271283 zap .String ("object" , i .ObjectDisplayName ()), zap .Error (err ),
@@ -281,7 +293,7 @@ func (i *Incident) processIncidentOpenedEvent(tx *sqlx.Tx, ev event.Event) error
281293 EventID : utils .ToDBInt (ev .ID ),
282294 }
283295
284- if _ , err := i .AddHistory (tx , historyRow , false ); err != nil {
296+ if _ , err := i .AddHistory (ctx , tx , historyRow , false ); err != nil {
285297 i .logger .Errorw (
286298 "can't insert incident opened history event" , zap .String ("object" , i .ObjectDisplayName ()),
287299 zap .String ("incident" , i .String ()), zap .Error (err ),
@@ -296,7 +308,7 @@ func (i *Incident) processIncidentOpenedEvent(tx *sqlx.Tx, ev event.Event) error
296308// evaluateRules evaluates all the configured rules for this *incident.Object and
297309// generates history entries for each matched rule.
298310// Returns error on database failure.
299- func (i * Incident ) evaluateRules (tx * sqlx.Tx , eventID int64 , causedBy types.Int ) (types.Int , error ) {
311+ func (i * Incident ) evaluateRules (ctx context. Context , tx * sqlx.Tx , eventID int64 , causedBy types.Int ) (types.Int , error ) {
300312 if i .Rules == nil {
301313 i .Rules = make (map [int64 ]struct {})
302314 }
@@ -333,7 +345,7 @@ func (i *Incident) evaluateRules(tx *sqlx.Tx, eventID int64, causedBy types.Int)
333345 Type : RuleMatched ,
334346 CausedByIncidentHistoryID : causedBy ,
335347 }
336- insertedID , err := i .AddRuleMatchedHistory (tx , r , history )
348+ insertedID , err := i .AddRuleMatchedHistory (ctx , tx , r , history )
337349 if err != nil {
338350 i .logger .Errorw (
339351 "failed to add incident rule matched history" , zap .String ("rule" , r .Name ), zap .String ("object" , i .ObjectDisplayName ()),
@@ -403,7 +415,7 @@ func (i *Incident) evaluateEscalations() {
403415// notifyContacts evaluates the incident.EscalationState and checks if escalations need to be triggered
404416// as well as builds the incident recipients along with their channel types and sends notifications based on that.
405417// Returns error on database failure.
406- func (i * Incident ) notifyContacts (tx * sqlx.Tx , ev * event.Event , causedBy types.Int ) error {
418+ func (i * Incident ) notifyContacts (ctx context. Context , tx * sqlx.Tx , ev * event.Event , causedBy types.Int ) error {
407419 managed := i .HasManager ()
408420
409421 contactChannels := make (map [* recipient.Contact ]map [string ]struct {})
@@ -438,7 +450,7 @@ func (i *Incident) notifyContacts(tx *sqlx.Tx, ev *event.Event, causedBy types.I
438450 CausedByIncidentHistoryID : causedBy ,
439451 }
440452
441- causedByHistoryId , err := i .AddEscalationTriggered (tx , state , history )
453+ causedByHistoryId , err := i .AddEscalationTriggered (ctx , tx , state , history )
442454 if err != nil {
443455 i .logger .Errorw (
444456 "failed to add escalation triggered history" , zap .String ("incident" , i .String ()),
@@ -451,7 +463,7 @@ func (i *Incident) notifyContacts(tx *sqlx.Tx, ev *event.Event, causedBy types.I
451463
452464 causedBy = causedByHistoryId
453465
454- err = i .AddRecipient (tx , escalation , ev .ID )
466+ err = i .AddRecipient (ctx , tx , escalation , ev .ID )
455467 if err != nil {
456468 i .logger .Errorw (
457469 "failed to add incident recipients" , zap .String ("object" , i .ObjectDisplayName ()), zap .String ("incident" , i .String ()),
@@ -512,44 +524,53 @@ func (i *Incident) notifyContacts(tx *sqlx.Tx, ev *event.Event, causedBy types.I
512524 CausedByIncidentHistoryID : causedBy ,
513525 }
514526
515- for chType := range channels {
516- i .logger .Infow (
517- fmt .Sprintf ("Notify contact %q via %q" , contact .FullName , chType ), zap .String ("object" , i .ObjectDisplayName ()),
518- zap .String ("incident" , i .String ()),
519- )
527+ select {
528+ case <- ctx .Done ():
529+ return ctx .Err ()
530+ default :
531+ for chType := range channels {
532+ i .logger .Infow (
533+ fmt .Sprintf ("Notify contact %q via %q" , contact .FullName , chType ), zap .String ("object" , i .ObjectDisplayName ()),
534+ zap .String ("incident" , i .String ()),
535+ )
520536
521- hr .ChannelType = utils .ToDBString (chType )
537+ hr .ChannelType = utils .ToDBString (chType )
522538
523- _ , err := i .AddHistory (tx , hr , false )
524- if err != nil {
525- i .logger .Errorln (err )
526- }
539+ _ , err := i .AddHistory (ctx , tx , hr , false )
540+ if err != nil {
541+ i .logger .Errorw (
542+ "failed to insert contact notified incident history" , zap .String ("type" , chType ),
543+ zap .String ("contact" , contact .String ()), zap .String ("object" , i .ObjectDisplayName ()),
544+ zap .String ("incident" , i .String ()),
545+ )
546+ }
527547
528- chConf := i .runtimeConfig .Channels [chType ]
529- if chConf == nil {
530- i .logger .Errorw (
531- "could not find config for channel" , zap .String ("type" , chType ), zap .String ("object" , i .ObjectDisplayName ()),
532- zap .String ("incident" , i .String ()),
533- )
534- continue
535- }
548+ chConf := i .runtimeConfig .Channels [chType ]
549+ if chConf == nil {
550+ i .logger .Errorw (
551+ "could not find config for channel" , zap .String ("type" , chType ), zap .String ("object" , i .ObjectDisplayName ()),
552+ zap .String ("incident" , i .String ()),
553+ )
554+ continue
555+ }
536556
537- plugin , err := chConf .GetPlugin ()
538- if err != nil {
539- i .logger .Errorw (
540- "couldn't initialize channel" , zap .String ("type" , chType ), zap .String ("object" , i .ObjectDisplayName ()),
541- zap .String ("incident" , i .String ()), zap .Error (err ),
542- )
543- continue
544- }
557+ plugin , err := chConf .GetPlugin ()
558+ if err != nil {
559+ i .logger .Errorw (
560+ "couldn't initialize channel" , zap .String ("type" , chType ), zap .String ("object" , i .ObjectDisplayName ()),
561+ zap .String ("incident" , i .String ()), zap .Error (err ),
562+ )
563+ continue
564+ }
545565
546- err = plugin .Send (contact , i , ev , i .configFile .Icingaweb2URL )
547- if err != nil {
548- i .logger .Errorw (
549- "failed to send via channel" , zap .String ("type" , chType ), zap .String ("object" , i .ObjectDisplayName ()),
550- zap .String ("incident" , i .String ()), zap .Error (err ),
551- )
552- continue
566+ err = plugin .Send (contact , i , ev , i .configFile .Icingaweb2URL )
567+ if err != nil {
568+ i .logger .Errorw (
569+ "failed to send via channel" , zap .String ("type" , chType ), zap .String ("object" , i .ObjectDisplayName ()),
570+ zap .String ("incident" , i .String ()), zap .Error (err ),
571+ )
572+ continue
573+ }
553574 }
554575 }
555576 }
@@ -560,7 +581,7 @@ func (i *Incident) notifyContacts(tx *sqlx.Tx, ev *event.Event, causedBy types.I
560581// processAcknowledgementEvent processes the given ack event.
561582// Promotes the ack author to incident.RoleManager if it's not already the case and generates a history entry.
562583// Returns error on database failure.
563- func (i * Incident ) processAcknowledgementEvent (tx * sqlx.Tx , ev event.Event ) error {
584+ func (i * Incident ) processAcknowledgementEvent (ctx context. Context , tx * sqlx.Tx , ev event.Event ) error {
564585 contact := i .runtimeConfig .GetContact (ev .Username )
565586 if contact == nil {
566587 i .logger .Warnw (
@@ -601,7 +622,7 @@ func (i *Incident) processAcknowledgementEvent(tx *sqlx.Tx, ev event.Event) erro
601622 Message : utils .ToDBString (ev .Message ),
602623 }
603624
604- _ , err := i .AddHistory (tx , hr , false )
625+ _ , err := i .AddHistory (ctx , tx , hr , false )
605626 if err != nil {
606627 i .logger .Errorw (
607628 "failed to add recipient role changed history" , zap .String ("recipient" , contact .String ()),
@@ -614,7 +635,7 @@ func (i *Incident) processAcknowledgementEvent(tx *sqlx.Tx, ev event.Event) erro
614635 cr := & ContactRow {IncidentID : hr .IncidentID , Key : recipientKey , Role : newRole }
615636
616637 stmt , _ := i .db .BuildUpsertStmt (cr )
617- _ , err = tx .NamedExec ( stmt , cr )
638+ _ , err = tx .NamedExecContext ( ctx , stmt , cr )
618639 if err != nil {
619640 i .logger .Errorw (
620641 "failed to upsert incident contact" , zap .String ("contact" , contact .String ()), zap .String ("object" , i .ObjectDisplayName ()),
0 commit comments