Documentation
¶
Index ¶
- func PublishAndMarkBusDispatched(ctx context.Context, bus Bus, store *Store, events ...Event)
- func StartIngestRetentionPruner(ctx context.Context, store *IngestStore, retention time.Duration)
- func StartWebhookEventRetentionPruner(ctx context.Context, store *WebhookEventStore, retention time.Duration)
- func WithDeferredBusDispatch(ctx context.Context) context.Context
- type Bus
- type BusDispatcher
- type BusDispatcherOption
- type Event
- type Filter
- type IngestStore
- func (s *IngestStore) Create(ctx context.Context, evt *models.IngestedEvent) error
- func (s *IngestStore) CreateTx(tx *gorm.DB, evt *models.IngestedEvent) error
- func (s *IngestStore) Prune(ctx context.Context, retention time.Duration) (int, error)
- func (s *IngestStore) RecordMatchesTx(tx *gorm.DB, matches []*models.EventTriggerMatch) error
- type Store
- func (s *Store) AppendBatchTx(tx *gorm.DB, evts []*Event) error
- func (s *Store) AppendTx(tx *gorm.DB, evt *Event) error
- func (s *Store) LatestSequence(ctx context.Context) (uint64, error)
- func (s *Store) ListPendingBusDispatch(ctx context.Context, limit int) ([]Event, error)
- func (s *Store) ListSince(ctx context.Context, after uint64, limit int, filter Filter) ([]Event, error)
- func (s *Store) MarkBusDispatched(ctx context.Context, events ...Event) error
- type Type
- type WebhookEventStore
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func StartIngestRetentionPruner ¶
func StartIngestRetentionPruner(ctx context.Context, store *IngestStore, retention time.Duration)
func StartWebhookEventRetentionPruner ¶
func StartWebhookEventRetentionPruner(ctx context.Context, store *WebhookEventStore, retention time.Duration)
func WithDeferredBusDispatch ¶
WithDeferredBusDispatch marks ctx so that PublishAndMarkBusDispatched skips the immediate in-memory publish for events emitted within it.
Use it around a transaction. Events are still written to the store transactionally (AppendTx) with bus_dispatch_pending=true; once the transaction commits, the BusDispatcher delivers each pending event to the bus exactly once and marks it dispatched, using its own live connection. If the transaction rolls back or is retried, the event rows never commit, so nothing is published — which avoids the orphan events (on rollback) and duplicate events (on retry) that an immediate, tx-scoped publish would cause.
Types ¶
type Bus ¶
type Bus interface {
Publish(e Event)
Subscribe(ctx context.Context, filter Filter) (<-chan Event, error)
}
Bus defines the event bus interface.
type BusDispatcher ¶
type BusDispatcher struct {
// contains filtered or unexported fields
}
func NewBusDispatcher ¶
func NewBusDispatcher(store *Store, bus Bus, opts ...BusDispatcherOption) *BusDispatcher
func (*BusDispatcher) DispatchOnce ¶
func (d *BusDispatcher) DispatchOnce(ctx context.Context) error
type BusDispatcherOption ¶
type BusDispatcherOption func(*BusDispatcher)
func WithBusDispatcherBatchSize ¶
func WithBusDispatcherBatchSize(batch int) BusDispatcherOption
func WithBusDispatcherInterval ¶
func WithBusDispatcherInterval(interval time.Duration) BusDispatcherOption
type Event ¶
type Event struct {
Sequence uint64 `json:"sequence,omitempty"`
Type Type `json:"type"`
JobID uuid.UUID `json:"job_id,omitempty"`
RunID uuid.UUID `json:"run_id,omitempty"`
TaskID uuid.UUID `json:"task_id,omitempty"`
Timestamp time.Time `json:"timestamp"`
Payload json.RawMessage `json:"payload,omitempty"`
Quarantine bool `json:"quarantine,omitempty"`
}
Event represents a system event.
type IngestStore ¶
type IngestStore struct {
// contains filtered or unexported fields
}
func NewIngestStore ¶
func NewIngestStore(db *gorm.DB) *IngestStore
func (*IngestStore) Create ¶
func (s *IngestStore) Create(ctx context.Context, evt *models.IngestedEvent) error
func (*IngestStore) CreateTx ¶
func (s *IngestStore) CreateTx(tx *gorm.DB, evt *models.IngestedEvent) error
func (*IngestStore) RecordMatchesTx ¶
func (s *IngestStore) RecordMatchesTx(tx *gorm.DB, matches []*models.EventTriggerMatch) error
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
func (*Store) AppendBatchTx ¶
AppendBatchTx inserts multiple events in a single INSERT statement and back-fills Sequence and Timestamp on each Event from the inserted rows. The slice must be non-empty; callers should call AppendTx for single events.
func (*Store) ListPendingBusDispatch ¶
type Type ¶
type Type string
EventType represents the type of event.
const ( TypeJobCreated Type = "job_created" TypeJobDeleted Type = "job_deleted" TypeRunStarted Type = "run_started" TypeRunCompleted Type = "run_completed" TypeRunFailed Type = "run_failed" TypeRunCancelled Type = "run_cancelled" TypeRunTerminal Type = "run_terminal" TypeTaskStarted Type = "task_started" TypeTaskSucceeded Type = "task_succeeded" TypeTaskFailed Type = "task_failed" TypeTaskSkipped Type = "task_skipped" TypeTaskRetrying Type = "task_retrying" TypeTaskReady Type = "task_ready" TypeTaskCached Type = "task_cached" TypeTaskClaimed Type = "task_claimed" TypeTaskLeaseExpired Type = "task_lease_expired" TypeLogChunk Type = "log_chunk" TypeJobPaused Type = "job_paused" TypeJobUnpaused Type = "job_unpaused" TypeBackfillStarted Type = "backfill_started" TypeBackfillComplete Type = "backfill_completed" TypeBackfillFailed Type = "backfill_failed" TypeBackfillCancelled Type = "backfill_cancelled" TypeRunRetried Type = "run_retried" TypeRunTimedOut Type = "run_timed_out" TypeSLAMissed Type = "sla_missed" TypeFreshnessViolated Type = "freshness_violated" TypeDatasetFreshnessAtRisk Type = "dataset_freshness_at_risk" // TypeDatasetAdvanced fires after a dataset's watermark is advanced or // verify-refreshed — by the run-completion capturer or the arrival observer — // carrying {namespace, name} in its payload. The freshness evaluator // subscribes to it to reactively re-derive downstream consumers off // POST-advance state. Reacting to run_completed instead would race the // capturer's own Advance (the bus fans out to subscribers unordered), so the // evaluator could read pre-advance state and derive a redundant producer run. TypeDatasetAdvanced Type = "dataset_advanced" // TypeSchemaViolationRecorded is emitted when a task's output violates its // declared schema in "warn" mode — the task does NOT fail, so the incident // manager would otherwise never see the violation. In "fail" mode the task // failure already carries the violations, so no separate event is emitted. TypeSchemaViolationRecorded Type = "schema_violation_recorded" // TypeContractBreakDeclared is emitted when an operator intentionally // acknowledges a breaking cross-job data contract for a bounded // deprecation window. TypeContractBreakDeclared Type = "contract_break_declared" // Incident lifecycle events (agent-in-the-loop D2). Emitted on the existing // /events stream so the Console incidents surface (Stream U) can live-update // the feed, timeline, and approval inbox without polling. TypeIncidentOpened Type = "incident_opened" TypeIncidentStatusChanged Type = "incident_status_changed" TypeAgentActionRecorded Type = "agent_action_recorded" TypeApprovalRequested Type = "approval_requested" // TypeAgentActionExecuted is emitted when an approved tier-3 action actually // RUNS (trust-the-substrate C8). It is deliberately distinct from // TypeAgentActionRecorded, which the approvals controller emits at DECISION // time and which therefore says nothing about whether the action executed or // what it did. This one carries the decider, the action type/tier, and the // result summary, so "approved by X at T, executed at T'" is reconstructable // from the event stream alone. TypeAgentActionExecuted Type = "agent_action_executed" // TypeIncidentEscalated is emitted when a remediation ESCALATES — an agent or // a deterministic rule handed the incident to a human, either directly // (the `escalate` action) or because an approved change could not be applied // where it was approved (a git-synced job's jobdef patch, which degrades to an // escalation carrying the rendered diff). // // It exists because escalation must be DELIVERED, not merely recorded. An // escalation that only writes an AgentAction row and a log line contacts // nobody, which is the one outcome an escalation cannot have. Routing it as an // event puts it through the ordinary NotificationPolicy → channel machinery, // so a team pages or Slacks on it with no new plumbing, and it stays queryable // from /v1/events afterwards. The payload carries the incident, the requested // channel, and the rendered summary/diff. TypeIncidentEscalated Type = "incident_escalated" )
type WebhookEventStore ¶
type WebhookEventStore struct {
// contains filtered or unexported fields
}
func NewWebhookEventStore ¶
func NewWebhookEventStore(db *gorm.DB) *WebhookEventStore
func (*WebhookEventStore) Create ¶
func (s *WebhookEventStore) Create(ctx context.Context, evt *models.WebhookEvent) error
func (*WebhookEventStore) CreateTx ¶
func (s *WebhookEventStore) CreateTx(tx *gorm.DB, evt *models.WebhookEvent) error