Skip to content

Commit d4712f4

Browse files
committed
Fix heartbeat events
1 parent c867859 commit d4712f4

4 files changed

Lines changed: 115 additions & 25 deletions

File tree

api/pkg/events/phone_heartbeat_check_event.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ type PhoneHeartbeatCheckPayload struct {
1616
UserID entities.UserID `json:"user_id"`
1717
ScheduledAt time.Time `json:"scheduled_at"`
1818
Owner string `json:"owner"`
19+
MonitorID uuid.UUID `json:"monitor_id"`
1920
}

api/pkg/events/phone_heartbeat_dead_event.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ type PhoneHeartbeatDeadPayload struct {
1515
PhoneID uuid.UUID `json:"phone_id"`
1616
UserID entities.UserID `json:"user_id"`
1717
Timestamp time.Time `json:"timestamp"`
18+
MonitorID uuid.UUID `json:"monitor_id"`
1819
Owner string `json:"owner"`
1920
}

api/pkg/listeners/heartbeat_listener.go

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package listeners
22

33
import (
4+
"context"
45
"fmt"
56

7+
cloudevents "github.com/cloudevents/sdk-go/v2"
8+
"github.com/davecgh/go-spew/spew"
9+
"github.com/palantir/stacktrace"
10+
611
"github.com/NdoleStudio/httpsms/pkg/events"
712
"github.com/NdoleStudio/httpsms/pkg/services"
813
"github.com/NdoleStudio/httpsms/pkg/telemetry"
@@ -27,5 +32,81 @@ func NewHeartbeatListener(
2732
service: service,
2833
}
2934

30-
return l, map[string]events.EventListener{}
35+
return l, map[string]events.EventListener{
36+
events.EventTypePhoneUpdated: l.onPhoneUpdated,
37+
events.EventTypePhoneDeleted: l.onPhoneDeleted,
38+
events.EventTypePhoneHeartbeatCheck: l.onPhoneHeartbeatCheck,
39+
}
40+
}
41+
42+
// onPhoneUpdated handles the events.EventTypePhoneUpdated event
43+
func (listener *HeartbeatListener) onPhoneUpdated(ctx context.Context, event cloudevents.Event) error {
44+
ctx, span := listener.tracer.Start(ctx)
45+
defer span.End()
46+
47+
var payload events.PhoneUpdatedPayload
48+
if err := event.DataAs(&payload); err != nil {
49+
msg := fmt.Sprintf("cannot decode [%s] into [%T]", event.Data(), payload)
50+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
51+
}
52+
53+
storeParams := &services.HeartbeatMonitorStoreParams{
54+
Owner: payload.Owner,
55+
PhoneID: payload.PhoneID,
56+
UserID: payload.UserID,
57+
Source: event.Source(),
58+
}
59+
60+
if _, err := listener.service.StoreMonitor(ctx, storeParams); err != nil {
61+
msg := fmt.Sprintf("cannot store heartbeat monitor with params [%s] for event with ID [%s]", spew.Sdump(storeParams), event.ID())
62+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
63+
}
64+
65+
return nil
66+
}
67+
68+
// onPhoneDeleted handles the events.EventTypePhoneDeleted event
69+
func (listener *HeartbeatListener) onPhoneDeleted(ctx context.Context, event cloudevents.Event) error {
70+
ctx, span := listener.tracer.Start(ctx)
71+
defer span.End()
72+
73+
var payload events.PhoneDeletedPayload
74+
if err := event.DataAs(&payload); err != nil {
75+
msg := fmt.Sprintf("cannot decode [%s] into [%T]", event.Data(), payload)
76+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
77+
}
78+
79+
if err := listener.service.DeleteMonitor(ctx, payload.UserID, payload.Owner); err != nil {
80+
msg := fmt.Sprintf("cannot delete heartbeat monitor with userID [%s] and owner [%s] for event with ID [%s]", payload.UserID, payload.Owner, event.ID())
81+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
82+
}
83+
84+
return nil
85+
}
86+
87+
// onPhoneHeartbeatCheck handles the events.EventTypePhoneHeartbeatCheck event
88+
func (listener *HeartbeatListener) onPhoneHeartbeatCheck(ctx context.Context, event cloudevents.Event) error {
89+
ctx, span := listener.tracer.Start(ctx)
90+
defer span.End()
91+
92+
var payload events.PhoneHeartbeatCheckPayload
93+
if err := event.DataAs(&payload); err != nil {
94+
msg := fmt.Sprintf("cannot decode [%s] into [%T]", event.Data(), payload)
95+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
96+
}
97+
98+
monitorParams := &services.HeartbeatMonitorParams{
99+
Owner: payload.Owner,
100+
PhoneID: payload.PhoneID,
101+
MonitorID: payload.MonitorID,
102+
UserID: payload.UserID,
103+
Source: event.Source(),
104+
}
105+
106+
if err := listener.service.Monitor(ctx, monitorParams); err != nil {
107+
msg := fmt.Sprintf("cannot monitor heartbeats for userID [%s] and owner [%s] for event with ID [%s]", payload.UserID, payload.Owner, event.ID())
108+
return listener.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
109+
}
110+
111+
return nil
31112
}

api/pkg/services/heartbeat_service.go

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,12 @@ func (service *HeartbeatService) Store(ctx context.Context, params HeartbeatStor
9999
type HeartbeatMonitorStoreParams struct {
100100
Owner string
101101
PhoneID uuid.UUID
102+
Source string
102103
UserID entities.UserID
103104
}
104105

105106
// StoreMonitor a new entities.HeartbeatMonitor
106-
func (service *HeartbeatService) StoreMonitor(ctx context.Context, params HeartbeatMonitorStoreParams) (*entities.HeartbeatMonitor, error) {
107+
func (service *HeartbeatService) StoreMonitor(ctx context.Context, params *HeartbeatMonitorStoreParams) (*entities.HeartbeatMonitor, error) {
107108
ctx, span := service.tracer.Start(ctx)
108109
defer span.End()
109110

@@ -132,7 +133,20 @@ func (service *HeartbeatService) StoreMonitor(ctx context.Context, params Heartb
132133
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
133134
}
134135

135-
ctxLogger.Info(fmt.Sprintf("heartbeat monitor saved with id [%s] for wner [%s] and user [%s]", heartbeatMonitor.ID, heartbeatMonitor.Owner, heartbeatMonitor.UserID))
136+
ctxLogger.Info(fmt.Sprintf("heartbeat monitor saved with id [%s] for owner [%s] and user [%s]", heartbeatMonitor.ID, heartbeatMonitor.Owner, heartbeatMonitor.UserID))
137+
138+
monitorParams := &HeartbeatMonitorParams{
139+
Owner: heartbeatMonitor.Owner,
140+
PhoneID: heartbeatMonitor.PhoneID,
141+
UserID: heartbeatMonitor.UserID,
142+
MonitorID: heartbeatMonitor.ID,
143+
Source: params.Source,
144+
}
145+
if err = service.scheduleHeartbeatCheck(ctx, time.Now().UTC(), monitorParams); err != nil {
146+
msg := fmt.Sprintf("cannot schedule healthcheck for monitor with owner [%s] and userID [%s]", params.Owner, params.UserID)
147+
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
148+
}
149+
136150
return heartbeatMonitor, nil
137151
}
138152

@@ -154,14 +168,15 @@ func (service *HeartbeatService) DeleteMonitor(ctx context.Context, userID entit
154168

155169
// HeartbeatMonitorParams are parameters for monitoring the heartbeat
156170
type HeartbeatMonitorParams struct {
157-
Owner string
158-
PhoneID uuid.UUID
159-
UserID entities.UserID
160-
Source string
171+
Owner string
172+
MonitorID uuid.UUID
173+
PhoneID uuid.UUID
174+
UserID entities.UserID
175+
Source string
161176
}
162177

163178
// Monitor the heartbeats of an owner and phone number
164-
func (service *HeartbeatService) Monitor(ctx context.Context, params HeartbeatMonitorParams) error {
179+
func (service *HeartbeatService) Monitor(ctx context.Context, params *HeartbeatMonitorParams) error {
165180
ctx, span := service.tracer.Start(ctx)
166181
defer span.End()
167182

@@ -191,36 +206,27 @@ func (service *HeartbeatService) Monitor(ctx context.Context, params HeartbeatMo
191206
return service.handleFailedMonitor(ctx, params, true)
192207
}
193208

194-
return service.handlePassingMonitor(ctx, heartbeat, params)
209+
return service.scheduleHeartbeatCheck(ctx, heartbeat.Timestamp, params)
195210
}
196211

197-
func (service *HeartbeatService) handleFailedMonitor(ctx context.Context, params HeartbeatMonitorParams, raiseEvent bool) error {
212+
func (service *HeartbeatService) handleFailedMonitor(ctx context.Context, params *HeartbeatMonitorParams, raiseEvent bool) error {
198213
ctx, span := service.tracer.Start(ctx)
199214
defer span.End()
200215

201-
event, err := service.createPhoneHeartbeatCheckEvent(params.Source, &events.PhoneHeartbeatCheckPayload{
202-
PhoneID: params.PhoneID,
203-
UserID: params.UserID,
204-
ScheduledAt: time.Now().UTC().Add(heartbeatCheckInterval),
205-
Owner: params.Owner,
206-
})
216+
err := service.scheduleHeartbeatCheck(ctx, time.Now().UTC(), params)
207217
if err != nil {
208-
msg := fmt.Sprintf("cannot create event when phone monitor failed")
209-
return service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
210-
}
211-
212-
if err = service.dispatcher.DispatchWithTimeout(ctx, event, heartbeatCheckInterval); err != nil {
213-
msg := fmt.Sprintf("cannot dispatch event [%s] for heartbeat monitor with phone id [%s]", event.Type(), params.PhoneID)
218+
msg := fmt.Sprintf("canot schedule healthcheck for monitor with owner [%s] and userID [%s]", params.Owner, params.UserID)
214219
return service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
215220
}
216221

217222
if !raiseEvent {
218223
return nil
219224
}
220225

221-
event, err = service.createPhoneHeartbeatDeadEvent(params.Source, &events.PhoneHeartbeatDeadPayload{
226+
event, err := service.createPhoneHeartbeatDeadEvent(params.Source, &events.PhoneHeartbeatDeadPayload{
222227
PhoneID: params.PhoneID,
223228
UserID: params.UserID,
229+
MonitorID: params.MonitorID,
224230
Timestamp: time.Now().UTC(),
225231
Owner: params.Owner,
226232
})
@@ -237,14 +243,15 @@ func (service *HeartbeatService) handleFailedMonitor(ctx context.Context, params
237243
return nil
238244
}
239245

240-
func (service *HeartbeatService) handlePassingMonitor(ctx context.Context, heartbeat *entities.Heartbeat, params HeartbeatMonitorParams) error {
246+
func (service *HeartbeatService) scheduleHeartbeatCheck(ctx context.Context, lastTimestamp time.Time, params *HeartbeatMonitorParams) error {
241247
ctx, span := service.tracer.Start(ctx)
242248
defer span.End()
243249

244250
event, err := service.createPhoneHeartbeatCheckEvent(params.Source, &events.PhoneHeartbeatCheckPayload{
245251
PhoneID: params.PhoneID,
246252
UserID: params.UserID,
247-
ScheduledAt: heartbeat.Timestamp.Add(heartbeatCheckInterval),
253+
MonitorID: params.MonitorID,
254+
ScheduledAt: lastTimestamp.Add(heartbeatCheckInterval),
248255
Owner: params.Owner,
249256
})
250257
if err != nil {

0 commit comments

Comments
 (0)