check / check (push) Waiting to run
Each webhook's event database keeps running totals: one row for its events, and one row per target for that target's deliveries, delivered and failed, each with what retention removed. Every write to them shares the transaction of the rows it counts. Deliveries get a finished_at column; it and target_id end the status index, so each target's deliveries finished in a window come from one index-range query grouped by target. Retention deletes 1000 expired events per transaction. The pane is its own template, its figures in tables. The schema changes in place with nothing back-filled, so an existing database must be recreated. Model: opus-5-5
64 lines
2.2 KiB
Go
64 lines
2.2 KiB
Go
package database
|
|
|
|
import (
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// DeliveryStatus represents the status of a delivery
|
|
type DeliveryStatus string
|
|
|
|
// Delivery status values.
|
|
const (
|
|
DeliveryStatusPending DeliveryStatus = "pending"
|
|
DeliveryStatusDelivered DeliveryStatus = "delivered"
|
|
DeliveryStatusFailed DeliveryStatus = "failed"
|
|
DeliveryStatusRetrying DeliveryStatus = "retrying"
|
|
)
|
|
|
|
// Terminal reports whether a delivery in this status has finished, so
|
|
// the delivery engine will make no further attempt of its own.
|
|
//
|
|
// It is what decides which deliveries the event log offers to replay:
|
|
// a pending or retrying delivery is still the engine's, and replaying
|
|
// one would race it.
|
|
func (s DeliveryStatus) Terminal() bool {
|
|
switch s {
|
|
case DeliveryStatusDelivered, DeliveryStatusFailed:
|
|
return true
|
|
case DeliveryStatusPending, DeliveryStatusRetrying:
|
|
return false
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// Delivery represents a delivery attempt for an event to a target
|
|
//
|
|
//nolint:lll // a struct tag cannot wrap
|
|
type Delivery struct {
|
|
BaseModel
|
|
|
|
EventID string `gorm:"type:uuid;not null;index:idx_deliveries_event_id,priority:1" json:"eventId"`
|
|
TargetID string `gorm:"type:uuid;not null;index:idx_deliveries_status,priority:4" json:"targetId"`
|
|
Status DeliveryStatus `gorm:"not null;default:'pending';index:idx_deliveries_status,priority:1" json:"status"`
|
|
|
|
// DeletedAt repeats the BaseModel field only to be the second column
|
|
// of the event_id and status indexes, for the reason DeliveryResult
|
|
// gives.
|
|
DeletedAt gorm.DeletedAt `gorm:"index:idx_deliveries_event_id,priority:2;index:idx_deliveries_status,priority:2" json:"deletedAt,omitzero"`
|
|
|
|
// FinishedAt is when the delivery became delivered or failed, and
|
|
// nil while it is pending or retrying. It and then TargetID end the
|
|
// status index, so the webhook page counts each target's deliveries
|
|
// that finished in a recent window by reading just that window from
|
|
// the index.
|
|
FinishedAt *time.Time `gorm:"index:idx_deliveries_status,priority:3" json:"finishedAt,omitempty"`
|
|
|
|
// Relations
|
|
Event Event `json:"event,omitzero"`
|
|
Target Target `json:"target,omitzero"`
|
|
DeliveryResults []DeliveryResult `json:"deliveryResults,omitempty"`
|
|
}
|