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
92 lines
2.8 KiB
Go
92 lines
2.8 KiB
Go
package database
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// The running totals in a webhook's event database keep the webhook
|
|
// page's lifetime figures right after retention has removed the rows
|
|
// they count, and let the page show them without counting every row.
|
|
// Each total changes in the transaction that writes or deletes the
|
|
// rows it counts.
|
|
|
|
// EventTotals is the single row counting a webhook's events: every
|
|
// event ever stored, and how many of them retention has deleted.
|
|
type EventTotals struct {
|
|
ID int64 `gorm:"primaryKey"`
|
|
|
|
Events int64 `gorm:"not null"`
|
|
EventsRemoved int64 `gorm:"not null"`
|
|
}
|
|
|
|
// TableName names the table AddEventTotals updates.
|
|
func (EventTotals) TableName() string {
|
|
return "event_totals"
|
|
}
|
|
|
|
// TargetTotals is one row per target counting its deliveries: every
|
|
// delivery ever created, how many became delivered and how many
|
|
// failed, and how many deliveries and failed deliveries retention has
|
|
// deleted. The webhook's delivery figures are these rows summed.
|
|
type TargetTotals struct {
|
|
TargetID string `gorm:"type:uuid;primaryKey"`
|
|
|
|
Deliveries int64 `gorm:"not null"`
|
|
Delivered int64 `gorm:"not null"`
|
|
Failed int64 `gorm:"not null"`
|
|
|
|
DeliveriesRemoved int64 `gorm:"not null"`
|
|
FailedRemoved int64 `gorm:"not null"`
|
|
}
|
|
|
|
// TableName names the table AddTargetTotals updates.
|
|
func (TargetTotals) TableName() string {
|
|
return "target_totals"
|
|
}
|
|
|
|
// AddEventTotals adds each count in add to the webhook's event totals.
|
|
// Call it on the transaction that writes or deletes the events it
|
|
// counts.
|
|
func AddEventTotals(tx *gorm.DB, add EventTotals) error {
|
|
err := tx.Exec(
|
|
`UPDATE event_totals SET
|
|
events = events + ?,
|
|
events_removed = events_removed + ?`,
|
|
add.Events, add.EventsRemoved,
|
|
).Error
|
|
if err != nil {
|
|
return fmt.Errorf("adding to event totals: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AddTargetTotals adds each count in add to the totals of the target
|
|
// add.TargetID names, creating its row the first time. Call it on the
|
|
// transaction that writes or deletes the deliveries it counts.
|
|
func AddTargetTotals(tx *gorm.DB, add TargetTotals) error {
|
|
err := tx.Exec(
|
|
`INSERT INTO target_totals (target_id, deliveries, delivered,
|
|
failed, deliveries_removed, failed_removed)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT (target_id) DO UPDATE SET
|
|
deliveries = deliveries + excluded.deliveries,
|
|
delivered = delivered + excluded.delivered,
|
|
failed = failed + excluded.failed,
|
|
deliveries_removed =
|
|
deliveries_removed + excluded.deliveries_removed,
|
|
failed_removed = failed_removed + excluded.failed_removed`,
|
|
add.TargetID, add.Deliveries, add.Delivered,
|
|
add.Failed, add.DeliveriesRemoved, add.FailedRemoved,
|
|
).Error
|
|
if err != nil {
|
|
return fmt.Errorf(
|
|
"adding to totals of target %s: %w", add.TargetID, err,
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|