[feat](alarm): add a durable per-device delivery ledger
pg_notify and the socket fan-out are not durable, so an offline phone used to miss a trigger forever and no-auto-stop would leave it ringing at nobody. Write one ledger row per enabled subscription in the trigger transaction, replay what a subscription still owes on every socket connect, and clear a row only on an explicit ack (live socket ack or ackAlarm); alarmStatus is a read-only check-in that answers 409 ERR_ALARM_TRIGGERED_OFFLINE with the missed frame. Ack is idempotent, and a destroyed alert cascades its debt away so a client is never told it missed an alarm that no longer exists.
This commit is contained in:
+12
-14
@@ -36,26 +36,24 @@ const NotifyChannel = "alarm_events"
|
||||
// the one that served the trigger request — fans the event out to its own
|
||||
// subscribers.
|
||||
type NotifyPayload struct {
|
||||
AlertID string `json:"alertId"`
|
||||
EventID string `json:"eventId"`
|
||||
Action string `json:"action"`
|
||||
Message string `json:"message"`
|
||||
AutoStopSeconds int `json:"autoStopSeconds"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
AlertID string `json:"alertId"`
|
||||
EventID string `json:"eventId"`
|
||||
Action string `json:"action"`
|
||||
Message string `json:"message"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
}
|
||||
|
||||
// Frame converts the transport payload into the wire frame. ServerTime is the
|
||||
// EVENT time, not the delivery time, so every instance and every client agrees
|
||||
// on when the alarm started (and therefore on the auto-stop countdown).
|
||||
// on when the alarm started.
|
||||
func (p NotifyPayload) Frame() AlarmFrame {
|
||||
return AlarmFrame{
|
||||
Type: "alarm",
|
||||
AlertID: p.AlertID,
|
||||
EventID: p.EventID,
|
||||
Action: p.Action,
|
||||
Message: p.Message,
|
||||
ServerTime: time.UnixMilli(p.CreatedAtMs).UTC().Format(time.RFC3339Nano),
|
||||
AutoStopSeconds: p.AutoStopSeconds,
|
||||
Type: "alarm",
|
||||
AlertID: p.AlertID,
|
||||
EventID: p.EventID,
|
||||
Action: p.Action,
|
||||
Message: p.Message,
|
||||
ServerTime: time.UnixMilli(p.CreatedAtMs).UTC().Format(time.RFC3339Nano),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user