@@ -164,11 +164,6 @@ func (i *Incident) ProcessEvent(ctx context.Context, ev *event.Event) error {
164164 return err
165165 }
166166
167- if err := i .handleMuteUnmute (ctx , tx , ev ); err != nil {
168- i .logger .Errorw ("Cannot insert incident muted history" , zap .String ("event" , ev .String ()), zap .Error (err ))
169- return err
170- }
171-
172167 switch ev .Type {
173168 case baseEv .TypeState :
174169 if ! isNew {
@@ -202,12 +197,27 @@ func (i *Incident) ProcessEvent(ctx context.Context, ev *event.Event) error {
202197 }
203198 }
204199
200+ // The unmute history entry, on the other hand, must be inserted first, so that the notifications generated
201+ // below appear logically after the unmute event. This way, when viewing the incident history in the UI, the
202+ // unmute event will appear before the notifications that were sent after unmuting.
203+ if err := i .handleUnmute (ctx , tx , ev ); err != nil {
204+ i .logger .Errorw ("Cannot insert incident muted history" , zap .String ("event" , ev .String ()), zap .Error (err ))
205+ return err
206+ }
207+
205208 var notifications []* NotificationEntry
206209 notifications , err = i .generateNotifications (ctx , tx , ev , i .getRecipientsChannel (ev .Time ))
207210 if err != nil {
208211 return err
209212 }
210213
214+ // So that the incident muted history appears logically after the just generated notifications, we must insert
215+ // the muted history last. This way, the history entries will make sense when viewed in chronological order.
216+ if err := i .handleMute (ctx , tx , ev ); err != nil {
217+ i .logger .Errorw ("Cannot insert incident muted history" , zap .Stringer ("event" , ev ), zap .Error (err ))
218+ return err
219+ }
220+
211221 if err = tx .Commit (); err != nil {
212222 i .logger .Errorw ("Cannot commit db transaction" , zap .Error (err ))
213223 return err
@@ -368,28 +378,48 @@ func (i *Incident) processIncidentOpenedEvent(ctx context.Context, tx *sqlx.Tx,
368378 return nil
369379}
370380
371- // handleMuteUnmute generates an incident Muted or Unmuted history based on the Object state.
381+ // handleUnmute generates the corresponding Unmuted history if the incident is going to be unmuted now.
382+ //
383+ // If the incident is already unmuted, or the object is still muted, this is a no-op.
372384// Returns an error if fails to insert the generated history to the database.
373- func (i * Incident ) handleMuteUnmute (ctx context.Context , tx * sqlx.Tx , ev * event.Event ) error {
374- if i .isMuted == i .Object .IsMuted () {
385+ func (i * Incident ) handleUnmute (ctx context.Context , tx * sqlx.Tx , ev * event.Event ) error {
386+ if ! i .isMuted || i .Object .IsMuted () {
375387 return nil
376388 }
377389
378- hr := & HistoryRow {IncidentID : i .Id , EventID : types .MakeInt (ev .ID , types .TransformZeroIntToNull ), Time : types .UnixMilli (time .Now ())}
379- logger := i .logger .With (zap .String ("event" , ev .String ()))
380- if i .Object .IsMuted () {
381- hr .Type = Muted
382- // Since the object may have already been muted with previous events before this incident even
383- // existed, we have to use the mute reason from this object and not from the ongoing event.
384- hr .Message = i .Object .MuteReason
385- logger .Infow ("Muting incident" , zap .String ("reason" , i .Object .MuteReason .String ))
386- } else {
387- hr .Type = Unmuted
390+ i .logger .Infow ("Unmuting incident" , zap .Stringer ("event" , ev ), zap .String ("reason" , i .Object .MuteReason .String ))
391+
392+ hr := & HistoryRow {
393+ IncidentID : i .Id ,
394+ EventID : types .MakeInt (ev .ID , types .TransformZeroIntToNull ),
395+ Time : types .UnixMilli (time .Now ()),
396+ Type : Unmuted ,
388397 // On the other hand, if an object is unmuted, its mute reason is already reset, and we can't access it anymore.
389- hr .Message = types .MakeString (ev .MuteReason , types .TransformEmptyStringToNull )
390- logger .Infow ("Unmuting incident" , zap .String ("reason" , ev .MuteReason ))
398+ Message : types .MakeString (ev .MuteReason , types .TransformEmptyStringToNull ),
399+ }
400+ return hr .Sync (ctx , i .db , tx )
401+ }
402+
403+ // handleMute generates the corresponding Muted history if the incident is not yet muted but is going to be muted now.
404+ //
405+ // If the incident is already muted, or the object is not muted at all, this is a no-op.
406+ // Returns an error if fails to insert the generated history to the database.
407+ func (i * Incident ) handleMute (ctx context.Context , tx * sqlx.Tx , ev * event.Event ) error {
408+ if i .isMuted || ! i .Object .IsMuted () {
409+ return nil
391410 }
392411
412+ i .logger .Infow ("Muting incident" , zap .Stringer ("event" , ev ), zap .String ("reason" , i .Object .MuteReason .String ))
413+
414+ hr := & HistoryRow {
415+ IncidentID : i .Id ,
416+ EventID : types .MakeInt (ev .ID , types .TransformZeroIntToNull ),
417+ Time : types .UnixMilli (time .Now ()),
418+ Type : Muted ,
419+ // Since the object may have already been muted with previous events before this incident even
420+ // existed, we have to use the mute reason from this object and not from the ongoing event.
421+ Message : i .Object .MuteReason ,
422+ }
393423 return hr .Sync (ctx , i .db , tx )
394424}
395425
0 commit comments