oncall

package
v1.9.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Index

Constants

View Source
const (
	AckViaDashboard = "dashboard"
	AckViaLink      = "link"
)
View Source
const (
	MaxPolicySteps       = 10
	MaxTargetsPerStep    = 10
	MinStepDelayMinutes  = 1
	MaxStepDelayMinutes  = 1440
	MaxPolicyRepeatCount = 5
)
View Source
const (
	TargetSchedule = "schedule"
	TargetUser     = "user"
	TargetTeam     = "team"
	TargetChannel  = "channel"
)
View Source
const (
	RestrictionDaily  = "daily"
	RestrictionWeekly = "weekly"
)
View Source
const (
	RotationDaily  = "daily"
	RotationWeekly = "weekly"
	RotationCustom = "custom"
)
View Source
const (
	MaxLayersPerSchedule    = 20
	MaxUsersPerLayer        = 50
	MaxRestrictionsPerLayer = 10
	MaxCustomIntervalDays   = 365
	MaxTimelineRangeDays    = 62
	MaxOverrideDurationDays = 30
)
View Source
const SchemaVersion = 1
View Source
const UrgencyAuto = "auto"

Variables

This section is empty.

Functions

func AckLink(page *models.Page) string

AckLink builds the absolute dashboard link that acknowledges a page. The project id is included so the dashboard can switch to the page's project — pages are resolved against the viewer's selected project.

func AcknowledgePage

func AcknowledgePage(tx *sql.Tx, pageId int, userId *int, via string, now time.Time) (bool, error)

AcknowledgePage transitions open -> acknowledged and cancels every queued or retrying delivery under the page's cancel key (mirroring their delivery log rows). Returns false when the page was not open. The single home for ack-side cancellation: used by the dashboard controller and the tokenized ack endpoint alike. userId is nil for anonymous link-acks.

func AutoResolveByDedupKey added in v1.9.13

func AutoResolveByDedupKey(ruleId int, dedupToken string) error

AutoResolveByDedupKey is the transaction-owning variant, registered as the notifications page resolver in cmd/run.go (that caller holds no transaction; nesting one would deadlock the single-connection SQLite main DB).

func AutoResolveByDedupKeyTx added in v1.9.13

func AutoResolveByDedupKeyTx(tx *sql.Tx, ruleId int, dedupToken string, now time.Time) (bool, error)

AutoResolveByDedupKeyTx resolves the unresolved page holding the rule-scoped dedup key with no resolving user (a system resolve, e.g. a synthetic check recovering), cancelling its queued deliveries. Runs in the caller's transaction. Returns whether a page was resolved.

func CurrentAndNext

func CurrentAndNext(def *models.OncallScheduleDefinition, tz *time.Location, overrides []*models.OncallOverride, now time.Time) (current *Shift, next *Shift)

CurrentAndNext gives the UI "on call until X, next up Y". The lookahead is bounded so sparse schedules terminate.

func CurrentOnCallForSchedule

func CurrentOnCallForSchedule(tx *sql.Tx, scheduleId int, at time.Time) ([]int, error)

CurrentOnCallForSchedule resolves who is on call for a schedule at the given instant, filtered to current members of the schedule's organization. A missing schedule resolves to nobody rather than an error, so dangling references never abort a caller.

func EmailDeliveryFor

func EmailDeliveryFor(accountEmail string, override string) (json.RawMessage, string)

EmailDeliveryFor builds the email adapter config (and display description) for a recipient, applying the override when present. Overrides are masked in the delivery log; the account email is not.

func EscalationChannelPolicyId

func EscalationChannelPolicyId(configJSON json.RawMessage) int

EscalationChannelPolicyId extracts the policyId from an escalation channel's config; 0 means the config is missing or malformed.

func LoadTimezone

func LoadTimezone(name string) (*time.Location, error)

LoadTimezone validates an IANA timezone name, returning a user-facing error.

func MarshalDefinition

func MarshalDefinition(def *models.OncallScheduleDefinition) ([]byte, error)

func MarshalPolicyDefinition

func MarshalPolicyDefinition(def *PolicyDefinition) ([]byte, error)

func NewLayerId

func NewLayerId() string

func OpenPageFromDispatch

func OpenPageFromDispatch(configJSON json.RawMessage, rule *models.NotificationRuleWithChannel, msg notifications.Message) (bool, error)

OpenPageFromDispatch is registered as the notifications package's page opener (see notifications.RegisterPageOpener). It runs inside dispatch for rules targeting an escalation channel: instead of sending anything, it opens (or dedups into) a page; the escalator worker does all notifying.

func OpenTestPage

func OpenTestPage(policyId int, projectId uuid.UUID, channelId int, channelName string) (bool, error)

OpenTestPage opens a real page for the channel test endpoint, exercising the full escalation loop. Reports false when the fire deduped into a previous test page that is still unresolved.

func ParseDefinition

func ParseDefinition(raw []byte) (*models.OncallScheduleDefinition, error)

ParseDefinition parses and validates a schedule definition, assigning ids to layers that lack one. Validation errors are user-facing (422) messages.

func ParseEmailOverride

func ParseEmailOverride(config []byte) string

ParseEmailOverride extracts the optional email override from an email contact-method config; "" means the account email is used.

func PoliciesReferencing

func PoliciesReferencing(tx *sql.Tx, organizationId int, targetType string, targetIds ...int) ([]string, error)

PoliciesReferencing returns the names of the organization's escalation policies that target any of the given ids of a type; it backs the delete guards on schedules and teams.

func RemoveUserFromOrgSchedules

func RemoveUserFromOrgSchedules(tx *sql.Tx, organizationId int, userId int) error

RemoveUserFromOrgSchedules scrubs a removed member from the organization's on-call data: their overrides are deleted and they are dropped from every schedule layer (a layer left with no members is dropped with them, keeping stored definitions valid). Resolution already filters to current org members; this keeps schedules and timelines from showing phantom coverage.

func ResolveAt

func ResolveAt(def *models.OncallScheduleDefinition, tz *time.Location, overrides []*models.OncallOverride, at time.Time) []int

ResolveAt answers "who is on call at t" with the same stacking ResolveRange renders: a later layer replaces the layers under it and an override replaces everything, so at most one person is on call. Returning every covering user instead would page the person an override was meant to relieve, and page one person per layer on a stacked schedule. Empty means nobody is on call.

func ResolvePage

func ResolvePage(tx *sql.Tx, pageId int, userId int, now time.Time) (bool, error)

ResolvePage transitions open/acknowledged -> resolved and cancels queued deliveries. Returns false when the page was already resolved.

func ResolveUrgency

func ResolveUrgency(policyUrgency string, severity string) string

ResolveUrgency maps a policy's urgency setting and a message severity to the page urgency. Auto: critical pages are high urgency, everything else low. An empty severity counts as critical, mirroring buildPageMessage.

func SMSPhoneNumber

func SMSPhoneNumber(config []byte) string

SMSPhoneNumber extracts the phoneNumber from an sms contact-method config, or "" when missing or malformed.

func StartEscalator

func StartEscalator(ctx context.Context)

StartEscalator runs the ack-based escalation loop. Each tick is purely transactional: due pages advance a level and their deliveries are enqueued into the notification outbox, which owns sending, retries, and crash recovery. Ack/resolve cancels queued deliveries via outbox.CancelByKey.

func Wake

func Wake()

Wake nudges the escalator so a freshly opened page notifies its first level immediately instead of waiting for the next tick. Non-blocking.

Types

type OncallUser

type OncallUser struct {
	UserId int    `json:"userId"`
	Name   string `json:"name"`
	Email  string `json:"email"`
}

type PolicyDefinition

type PolicyDefinition struct {
	SchemaVersion int          `json:"schemaVersion"`
	Steps         []PolicyStep `json:"steps"`
	RepeatCount   int          `json:"repeatCount"`
	// Urgency picks which of each responder's notification-rule chains runs:
	// ""|"auto" derives from severity, "high"/"low" force it. Optional so
	// stored snapshots and old policies keep parsing (schemaVersion stays 1).
	Urgency string `json:"urgency,omitempty"`
}

func ParsePolicyDefinition

func ParsePolicyDefinition(raw []byte) (*PolicyDefinition, error)

ParsePolicyDefinition parses without target-existence checks; used for stored snapshots where dangling targets are tolerated at run time.

func ValidatePolicyDefinition

func ValidatePolicyDefinition(tx *sql.Tx, organizationId int, raw []byte) (*PolicyDefinition, error)

ValidatePolicyDefinition parses and fully validates a policy definition for the organization, including target existence. Errors are user-facing 422 messages.

type PolicyStep

type PolicyStep struct {
	Targets      []StepTarget `json:"targets"`
	DelayMinutes int          `json:"delayMinutes"`
}

type ProjectOnCall

type ProjectOnCall struct {
	Team      *models.Team  `json:"team"`
	Schedules []ScheduleRef `json:"schedules"`
	Oncall    []OncallUser  `json:"oncall"`
}

ProjectOnCall is the ownership seam: the team owning a project and who is on call for it right now.

func CurrentOnCallForProject

func CurrentOnCallForProject(tx *sql.Tx, projectId uuid.UUID, at time.Time) (*ProjectOnCall, error)

CurrentOnCallForProject resolves the owning team's current on-call across all of its schedules (schedule creation order), filtered to current org members. Returns nil when the project has no owning team.

type ScheduleRef

type ScheduleRef struct {
	Id   int    `json:"id"`
	Name string `json:"name"`
}

type Shift

type Shift struct {
	UserId     int       `json:"userId"`
	LayerId    string    `json:"layerId"`
	Start      time.Time `json:"start"`
	End        time.Time `json:"end"`
	IsOverride bool      `json:"isOverride"`
}

Shift is one contiguous stretch of a single person being on call. Times are UTC.

func ResolveLayerRange

func ResolveLayerRange(layer *models.OncallLayer, tz *time.Location, from, to time.Time) []Shift

ResolveLayerRange renders one layer's coverage for [from, to) without stacking or overrides: rotation periods intersected with the layer's restriction windows.

func ResolveRange

func ResolveRange(def *models.OncallScheduleDefinition, tz *time.Location, overrides []*models.OncallOverride, from, to time.Time) []Shift

ResolveRange renders the final schedule for [from, to): per-layer coverage, stacked so that a later layer's coverage replaces earlier layers where they overlap (PagerDuty "higher layer number takes precedence"), with overrides on top of everything.

type StepTarget

type StepTarget struct {
	Type string `json:"type"`
	Id   int    `json:"id"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL