@@ -2,6 +2,7 @@ package services
22
33import (
44 "context"
5+ "errors"
56 "fmt"
67 "time"
78
@@ -50,6 +51,8 @@ type NotificationSendParams struct {
5051 UserID entities.UserID
5152 PhoneID uuid.UUID
5253 PhoneNotificationID uuid.UUID
54+ Source string
55+ ScheduledAt time.Time
5356 MessageID uuid.UUID
5457}
5558
@@ -58,19 +61,15 @@ func (service *NotificationService) Send(ctx context.Context, params *Notificati
5861 ctx , span := service .tracer .Start (ctx )
5962 defer span .End ()
6063
61- ctxLogger := service .tracer .CtxLogger (service .logger , span )
62-
6364 phone , err := service .phoneRepository .LoadByID (ctx , params .PhoneID )
6465 if err != nil {
65- service .updateStatus (ctx , params .PhoneNotificationID , entities .PhoneNotificationStatusFailed )
6666 msg := fmt .Sprintf ("cannot load phone with userID [%s] and phoneID [%s]" , params .UserID , params .PhoneID )
67- return service .tracer . WrapErrorSpan ( span , stacktrace . Propagate ( err , msg ))
67+ return service .handleNotificationFailed ( ctx , errors . New ( msg ), params )
6868 }
6969
7070 if phone .FcmToken == nil {
71- service .updateStatus (ctx , params .PhoneNotificationID , entities .PhoneNotificationStatusFailed )
7271 msg := fmt .Sprintf ("phone with id [%s] has no FCM token" , phone .ID )
73- return service .tracer . WrapErrorSpan ( span , stacktrace . NewError (msg ))
72+ return service .handleNotificationFailed ( ctx , errors . New (msg ), params )
7473 }
7574
7675 result , err := service .messagingClient .Send (ctx , & messaging.Message {
@@ -80,14 +79,9 @@ func (service *NotificationService) Send(ctx context.Context, params *Notificati
8079 Token : * phone .FcmToken ,
8180 })
8281 if err != nil {
83- service .updateStatus (ctx , params .PhoneNotificationID , entities .PhoneNotificationStatusFailed )
84- msg := fmt .Sprintf ("cannot send notification for message [%s] to phone [%s]" , params .MessageID , phone .ID )
85- return service .tracer .WrapErrorSpan (span , stacktrace .Propagate (err , msg ))
82+ return service .handleNotificationFailed (ctx , err , params )
8683 }
87-
88- ctxLogger .Info (fmt .Sprintf ("sent notification [%s] for message [%s] to phone [%s]" , result , params .MessageID , phone .ID ))
89- service .updateStatus (ctx , params .PhoneNotificationID , entities .PhoneNotificationStatusSent )
90- return nil
84+ return service .handleNotificationSent (ctx , result , params )
9185}
9286
9387// NotificationScheduleParams are parameters for sending a notification
@@ -140,6 +134,49 @@ func (service *NotificationService) Schedule(ctx context.Context, params *Notifi
140134 return nil
141135}
142136
137+ func (service * NotificationService ) handleNotificationFailed (ctx context.Context , err error , params * NotificationSendParams ) error {
138+ ctx , span := service .tracer .Start (ctx )
139+ defer span .End ()
140+
141+ ctxLogger := service .tracer .CtxLogger (service .logger , span )
142+
143+ msg := fmt .Sprintf ("cannot send notification for message [%s] to phone [%s]" , params .MessageID , params .PhoneNotificationID )
144+ ctxLogger .Warn (stacktrace .Propagate (err , msg ))
145+
146+ event , err := service .createMessageNotificationFailedEvent (params .Source , err .Error (), params )
147+ if err != nil {
148+ return stacktrace .Propagate (err , fmt .Sprintf ("cannot create [%s] event for notification [%s]" , events .EventTypeMessageNotificationFailed , params .PhoneNotificationID ))
149+ }
150+
151+ if err = service .eventDispatcher .Dispatch (ctx , event ); err != nil {
152+ return stacktrace .Propagate (err , fmt .Sprintf ("cannot dispatch event [%s] for notification [%s]" , event .Type (), params .PhoneNotificationID ))
153+ }
154+
155+ service .updateStatus (ctx , params .PhoneNotificationID , entities .PhoneNotificationStatusFailed )
156+ return nil
157+ }
158+
159+ func (service * NotificationService ) handleNotificationSent (ctx context.Context , result string , params * NotificationSendParams ) error {
160+ ctx , span := service .tracer .Start (ctx )
161+ defer span .End ()
162+
163+ ctxLogger := service .tracer .CtxLogger (service .logger , span )
164+
165+ ctxLogger .Info (fmt .Sprintf ("sent notification [%s] for message [%s] to phone [%s]" , result , params .MessageID , params .PhoneID ))
166+
167+ event , err := service .createMessageNotificationSentEvent (params .Source , result , params )
168+ if err != nil {
169+ return stacktrace .Propagate (err , fmt .Sprintf ("cannot create [%s] event for notification [%s]" , events .EventTypeMessageNotificationSent , params .PhoneNotificationID ))
170+ }
171+
172+ if err = service .eventDispatcher .Dispatch (ctx , event ); err != nil {
173+ return stacktrace .Propagate (err , fmt .Sprintf ("cannot dispatch event [%s] for notification [%s]" , event .Type (), params .PhoneNotificationID ))
174+ }
175+
176+ service .updateStatus (ctx , params .PhoneNotificationID , entities .PhoneNotificationStatusSent )
177+ return nil
178+ }
179+
143180func (service * NotificationService ) createEvent (source string , notification * entities.PhoneNotification ) (cloudevents.Event , error ) {
144181 event := cloudevents .NewEvent ()
145182
@@ -164,6 +201,57 @@ func (service *NotificationService) createEvent(source string, notification *ent
164201 return event , nil
165202}
166203
204+ func (service * NotificationService ) createMessageNotificationSentEvent (source string , fcmMessageID string , params * NotificationSendParams ) (cloudevents.Event , error ) {
205+ event := cloudevents .NewEvent ()
206+
207+ event .SetSource (source )
208+ event .SetType (events .EventTypeMessageNotificationSent )
209+ event .SetTime (time .Now ().UTC ())
210+ event .SetID (uuid .New ().String ())
211+
212+ payload := events.MessageNotificationSentPayload {
213+ MessageID : params .MessageID ,
214+ UserID : params .UserID ,
215+ PhoneID : params .PhoneID ,
216+ ScheduledAt : params .ScheduledAt ,
217+ FcmMessageID : fcmMessageID ,
218+ NotificationSentAt : time .Now ().UTC (),
219+ NotificationID : params .PhoneNotificationID ,
220+ }
221+
222+ if err := event .SetData (cloudevents .ApplicationJSON , payload ); err != nil {
223+ msg := fmt .Sprintf ("cannot encode %T [%#+v] as JSON" , payload , payload )
224+ return event , stacktrace .Propagate (err , msg )
225+ }
226+
227+ return event , nil
228+ }
229+
230+ func (service * NotificationService ) createMessageNotificationFailedEvent (source string , errorMessage string , params * NotificationSendParams ) (cloudevents.Event , error ) {
231+ event := cloudevents .NewEvent ()
232+
233+ event .SetSource (source )
234+ event .SetType (events .EventTypeMessageNotificationFailed )
235+ event .SetTime (time .Now ().UTC ())
236+ event .SetID (uuid .New ().String ())
237+
238+ payload := events.MessageNotificationFailedPayload {
239+ MessageID : params .MessageID ,
240+ UserID : params .UserID ,
241+ PhoneID : params .PhoneID ,
242+ ErrorMessage : errorMessage ,
243+ NotificationFailedAt : time .Now ().UTC (),
244+ NotificationID : params .PhoneNotificationID ,
245+ }
246+
247+ if err := event .SetData (cloudevents .ApplicationJSON , payload ); err != nil {
248+ msg := fmt .Sprintf ("cannot encode %T [%#+v] as JSON" , payload , payload )
249+ return event , stacktrace .Propagate (err , msg )
250+ }
251+
252+ return event , nil
253+ }
254+
167255func (service * NotificationService ) updateStatus (ctx context.Context , notificationID uuid.UUID , status entities.PhoneNotificationStatus ) {
168256 ctx , span := service .tracer .Start (ctx )
169257 defer span .End ()
@@ -174,7 +262,6 @@ func (service *NotificationService) updateStatus(ctx context.Context, notificati
174262 if err != nil {
175263 msg := fmt .Sprintf ("cannot update status of notificaiton with id [%s] to [%s]" , notificationID , status )
176264 ctxLogger .Error (stacktrace .Propagate (err , msg ))
177- return
178265 }
179266
180267 ctxLogger .Info (fmt .Sprintf ("updated status of notificaiton with id [%s] to [%s]" , notificationID , status ))
0 commit comments