Skip to content

Commit 3a268bb

Browse files
AchoArnoldCopilot
andcommitted
fix(api): keep heartbeat storage successful if check restart fails
Log restart failures without rejecting an already stored heartbeat. Continue processing online status after a restart failure. Move the empty queue marker check into HeartbeatMonitor.RequiresCheck. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f27d8f52-9620-4ee2-a564-ec4870a5f840
1 parent a82cfd0 commit 3a268bb

3 files changed

Lines changed: 41 additions & 3 deletions

File tree

‎api/pkg/entities/heartbeat_monitor.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type HeartbeatMonitor struct {
2020

2121
// RequiresCheck returns true if the heartbeat monitor requires a check
2222
func (h *HeartbeatMonitor) RequiresCheck() bool {
23-
return h.UpdatedAt.Add(2 * time.Hour).Before(time.Now())
23+
return h.QueueID == "" || h.UpdatedAt.Add(2*time.Hour).Before(time.Now())
2424
}
2525

2626
// PhoneIsOffline returns true if the phone is offline

‎api/pkg/services/heartbeat_service.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,15 @@ func (service *HeartbeatService) Store(ctx context.Context, params HeartbeatStor
124124
return heartbeat, nil
125125
}
126126

127-
if monitor.QueueID == "" || monitor.RequiresCheck() {
127+
if monitor.RequiresCheck() {
128128
if err = service.scheduleHeartbeatCheck(ctx, heartbeat.Timestamp, &HeartbeatMonitorParams{
129129
Owner: monitor.Owner,
130130
PhoneID: monitor.PhoneID,
131131
UserID: monitor.UserID,
132132
MonitorID: monitor.ID,
133133
Source: params.Source,
134134
}); err != nil {
135-
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagatef(err, "cannot restart heartbeat check for monitor [%s]", monitor.ID))
135+
ctxLogger.Error(service.tracer.WrapErrorSpan(span, stacktrace.Propagatef(err, "cannot restart heartbeat check for monitor [%s]", monitor.ID)))
136136
}
137137
}
138138

‎api/pkg/services/heartbeat_service_test.go‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,13 @@ func (repository *heartbeatServiceMonitorRepository) UpdatePhoneOnline(_ context
5454

5555
type heartbeatServiceQueue struct {
5656
phoneNotificationEventQueue
57+
err error
5758
}
5859

5960
func (queue *heartbeatServiceQueue) Enqueue(ctx context.Context, task *PushQueueTask, timeout time.Duration) (string, error) {
61+
if queue.err != nil {
62+
return "", queue.err
63+
}
6064
if _, err := queue.phoneNotificationEventQueue.Enqueue(ctx, task, timeout); err != nil {
6165
return "", err
6266
}
@@ -160,3 +164,37 @@ func TestHeartbeatServiceMonitor_StopsCheckingDeletedMonitor(t *testing.T) {
160164
}))
161165
assert.Empty(t, queue.events)
162166
}
167+
168+
func TestHeartbeatServiceStore_ReturnsHeartbeatWhenRestartFails(t *testing.T) {
169+
for _, test := range []struct {
170+
name string
171+
online bool
172+
}{
173+
{name: "online phone", online: true},
174+
{name: "offline phone"},
175+
} {
176+
t.Run(test.name, func(t *testing.T) {
177+
logger := &phoneNotificationLogger{}
178+
tracer := telemetry.NewOtelLogger("test", logger)
179+
queue := &heartbeatServiceQueue{err: stacktrace.NewError("queue unavailable")}
180+
repository := &heartbeatServiceRepository{}
181+
monitor := &entities.HeartbeatMonitor{
182+
ID: uuid.New(), PhoneID: uuid.New(), UserID: entities.UserID("user-1"),
183+
Owner: "+18005550199", UpdatedAt: time.Now().UTC(), PhoneOnline: test.online,
184+
}
185+
service := NewHeartbeatService(logger, tracer, repository,
186+
&heartbeatServiceMonitorRepository{monitor: monitor},
187+
NewEventDispatcher(logger, tracer, nil, queue, PushQueueConfig{}))
188+
189+
heartbeat, err := service.Store(context.Background(), HeartbeatStoreParams{
190+
UserID: monitor.UserID, Owner: monitor.Owner, Source: "https://example.com", Timestamp: time.Now().UTC(),
191+
})
192+
193+
require.NoError(t, err)
194+
require.NotNil(t, heartbeat)
195+
assert.Same(t, repository.heartbeat, heartbeat)
196+
assert.Empty(t, monitor.QueueID)
197+
assert.True(t, monitor.PhoneOnline)
198+
})
199+
}
200+
}

0 commit comments

Comments
 (0)