check / check (push) Waiting to run
Every reference from a model to the record it belongs to (a target's or entrypoint's webhook, a webhook's or API key's user, an event's webhook and entrypoint, a delivery's event and target, a delivery result's delivery) is now tagged json:"-", so a preloaded model can be marshalled without the encoder recursing between parent and child. References to child records stay. Tests marshal each of the nine references set, preloaded where it matters, and check the parent's id is absent, so deleting or restoring any one tag fails a test; preloading still fills each reference. Model: opus-5-5
66 lines
2.3 KiB
Go
66 lines
2.3 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. No model marshals the record it belongs to:
|
|
// Event.Deliveries and Target.Deliveries lead back here, and the
|
|
// JSON could loop.
|
|
Event Event `json:"-"`
|
|
Target Target `json:"-"`
|
|
DeliveryResults []DeliveryResult `json:"deliveryResults,omitempty"`
|
|
}
|