Help us shape the future of Go! Take the 2026 Go Developer Survey

worker

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Oct 28, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DrainMode

func DrainMode() bool

DrainMode reports whether the WORKER_DRAIN env var instructs the scheduler to skip starting background worker loops on this process. Used during destructive DB migrations (e.g. Path B multi-tenancy strip) to prevent the worker fleet from racing the DDL by writing to tables mid-ALTER.

Accepted truthy values: "1", "true", "yes", "on" (case-insensitive). Anything else (including unset) returns false. Read once at Start(); to toggle, set the WORKER_DRAIN env var in the deployment's env file and restart the API process.

func JobParent

func JobParent(ctx context.Context) context.Context

JobParent returns the uncapped context behind a job context, or ctx itself.

func WithJobParent

func WithJobParent(ctx, parent context.Context) context.Context

WithJobParent records parent, the scheduler's uncapped context, on a job's context. A job that must outlive the 10 minute cap but still stop on shutdown follows JobParent instead of its own (capped) context.

Types

type AgentHitsMaintenanceWorker

type AgentHitsMaintenanceWorker struct {
	// contains filtered or unexported fields
}

AgentHitsMaintenanceWorker truncates stored client IPs after 30 days, in bounded batches so a backlog never holds a long lock.

func NewAgentHitsMaintenanceWorker

func NewAgentHitsMaintenanceWorker(db *database.DB, batchSize int, logger *slog.Logger) *AgentHitsMaintenanceWorker

func (*AgentHitsMaintenanceWorker) Run

Run truncates until a short batch signals the backlog is empty. A nil worker or database is a no-op.

type EntityVersionWorker

type EntityVersionWorker struct {
	// contains filtered or unexported fields
}

EntityVersionWorker coalesces identical-consecutive entity versions and keeps only the newest N per entity, so hatamoto_entity_versions stays bounded.

func NewEntityVersionWorker

func NewEntityVersionWorker(repo entity.EntityRepository, keep int, logger *slog.Logger) *EntityVersionWorker

func (*EntityVersionWorker) Run

type PartitionWorker

type PartitionWorker struct {
	// contains filtered or unexported fields
}

PartitionWorker keeps a monthly RANGE-partitioned table's partitions ahead of the write boundary and drops aged ones. The parent table carries PARTITIONED indexes, so CREATE TABLE ... PARTITION OF auto-creates the matching child indexes: no manual index DDL needed. parent is always a package constant, never user input; it is also what keeps the DROP guard (nameRe) honest.

func NewAgentHitsPartitionWorker

func NewAgentHitsPartitionWorker(db *database.DB, aheadMonths, retentionMonths int, logger *slog.Logger) *PartitionWorker

NewAgentHitsPartitionWorker maintains hatamoto_agent_hits. retentionMonths=3 keeps at least 90 days of hits (month granularity: up to ~120 days).

func (*PartitionWorker) EnsureCurrentAndNext

func (w *PartitionWorker) EnsureCurrentAndNext(ctx context.Context)

EnsureCurrentAndNext synchronously creates the current and next month's partitions and warns when the DEFAULT partition holds rows. It is meant for server startup, independent of the scheduler (HATAMOTO_WORKER=off is the default), so hits never land in DEFAULT where retention cannot drop them. Errors are logged, never returned: startup must not depend on it.

func (*PartitionWorker) Run

func (w *PartitionWorker) Run(ctx context.Context) error

Run ensures the current + next `ahead` partitions exist, then drops any YYYY_MM partition whose month ended more than `retention` months ago.

type PruneWorker

type PruneWorker struct {
	// contains filtered or unexported fields
}

PruneWorker performs batched DELETEs on high-churn tables so they don't grow unbounded. Each delete is done in bounded LIMIT batches (via ctid) so a large backlog never takes a long lock.

func NewPruneWorker

func NewPruneWorker(db *database.DB, batchSize int, logger *slog.Logger) *PruneWorker

func (*PruneWorker) Run

func (w *PruneWorker) Run(ctx context.Context) error

type PublishEventSink

type PublishEventSink interface {
	EntityPublished(ctx context.Context, id uuid.UUID, schemaSlug, slug, name string, version int)
}

PublishEventSink is told about each entity the worker promotes so the plugin host can fire entity.published. Defined here (primitives only) to keep this package free of entity/pluginhost imports.

type PublishWorker

type PublishWorker struct {
	// contains filtered or unexported fields
}

PublishWorker promotes scheduled entities to published once their published_at falls due.

Why a status rather than a date filter: the public repository (internal/entity/public_repository.go) selects on status = 'published' across eight query sites with no date guard. Adding "AND published_at <= NOW()" to each would work until someone adds a ninth and leaks a post early. A distinct 'scheduled' status is excluded by every one of those queries for free, and this worker is the single place the transition happens.

The UPDATE deliberately does not touch published_at: the scheduled instant is the publication date. entity.UpdateStatus only stamps time.Now() when published_at is NULL or still in the future (a post published early by hand), so it keeps a past date, but the worker stays a separate, explicit path.

func NewPublishWorker

func NewPublishWorker(db *database.DB, logger *slog.Logger) *PublishWorker

NewPublishWorker constructs the worker.

func (*PublishWorker) Run

Run executes one tick: promote every scheduled entity whose published_at has passed. Returns the rows promoted.

Each promoted entity goes through the events sink, which clears the page cache (the server's sink does so synchronously) so the page and listings are live as soon as Run returns, whatever HATAMOTO_PAGE_CACHE_TTL is.

func (*PublishWorker) SetEvents

func (w *PublishWorker) SetEvents(s PublishEventSink)

SetEvents installs the sink; nil disables notification.

type PublishedEntity

type PublishedEntity struct {
	ID         uuid.UUID
	Slug       string
	Name       string
	SchemaSlug string
	Version    int
}

PublishedEntity identifies one row this worker promoted.

type RetentionPurgeWorker

type RetentionPurgeWorker struct {
	// contains filtered or unexported fields
}

RetentionPurgeWorker deletes expired server-side sessions once per day. session.Store.PurgeExpired already existed but had no scheduled caller.

func NewRetentionPurgeWorker

func NewRetentionPurgeWorker(sessions *session.Store, logger *slog.Logger) *RetentionPurgeWorker

NewRetentionPurgeWorker constructs the worker. sessions may be nil (purge skipped).

func (*RetentionPurgeWorker) AddPurge

func (w *RetentionPurgeWorker) AddPurge(name string, fn func(context.Context) (int64, error))

AddPurge registers another purge to run on every tick; its error is logged, never fatal.

func (*RetentionPurgeWorker) Run

Run executes one purge tick.

type Scheduler

type Scheduler struct {
	// contains filtered or unexported fields
}

Scheduler manages background job scheduling.

The scheduler is a small core-only host for core maintenance jobs (publishing, retention, pruning, agent-hit upkeep). Plugin workloads run in the plugin via the plugin.Starter contract, not here.

func NewScheduler

func NewScheduler(db *database.DB, logger *slog.Logger) *Scheduler

NewScheduler creates a new scheduler instance.

func (*Scheduler) Schedule

func (s *Scheduler) Schedule(id string, every time.Duration, fn func(context.Context) error) error

Schedule runs fn every `every` (at least a minute; the first run is one period from now) under id, replacing a job with the same id. Jobs added before Start begin with it; in drain mode they never run. It is how plugin cron registrations reach the scheduler.

func (*Scheduler) ScheduleJitter

func (s *Scheduler) ScheduleJitter(id string, every, jitter, firstDelay time.Duration, fn func(context.Context) error) error

ScheduleJitter is Schedule with a first run after firstDelay and a wait between runs of every plus a uniform offset in [-jitter, +jitter]. A job with the same id is replaced. The 10 minute cap per run still applies.

func (*Scheduler) SetAgentHitsMaintenanceWorker

func (s *Scheduler) SetAgentHitsMaintenanceWorker(worker *AgentHitsMaintenanceWorker)

SetAgentHitsMaintenanceWorker registers the 30-day client-IP truncation job.

func (*Scheduler) SetAgentHitsPartitionWorker

func (s *Scheduler) SetAgentHitsPartitionWorker(worker *PartitionWorker)

SetAgentHitsPartitionWorker registers the hatamoto_agent_hits partition job.

func (*Scheduler) SetAgentRangesRefreshWorker

func (s *Scheduler) SetAgentRangesRefreshWorker(worker *agents.VerifyWorker)

SetAgentRangesRefreshWorker registers the daily operator IP range download.

func (*Scheduler) SetAgentVerifyWorker

func (s *Scheduler) SetAgentVerifyWorker(worker *agents.VerifyWorker)

SetAgentVerifyWorker registers the 5-minute pending-hit verification job.

func (*Scheduler) SetEntityVersionInterval

func (s *Scheduler) SetEntityVersionInterval(d time.Duration)

SetEntityVersionInterval makes the entity-version job run every d (after a minute) instead of daily. The public demo uses it so old versions cannot pile up between two resets.

func (*Scheduler) SetEntityVersionWorker

func (s *Scheduler) SetEntityVersionWorker(worker *EntityVersionWorker)

SetEntityVersionWorker registers the entity-version coalesce/retention job.

func (*Scheduler) SetPruneWorker

func (s *Scheduler) SetPruneWorker(worker *PruneWorker)

SetPruneWorker registers the batched high-churn-table prune job.

func (*Scheduler) SetPublishWorker

func (s *Scheduler) SetPublishWorker(worker *PublishWorker)

SetPublishWorker registers the scheduled-publish worker (optional). When set, the scheduler promotes due `scheduled` entities once a minute.

func (*Scheduler) SetRetentionPurgeWorker

func (s *Scheduler) SetRetentionPurgeWorker(worker *RetentionPurgeWorker)

SetRetentionPurgeWorker registers the daily session + remember-token purge.

func (*Scheduler) Start

func (s *Scheduler) Start(ctx context.Context)

Start begins the scheduler loops.

When WORKER_DRAIN=true in the environment, all worker loops are skipped. The scheduler comes up but does nothing. This is the safety hook used before running destructive DB migrations: set the env, restart the API process, wait for any in-flight work (claimed before drain) to finish, verify the queue is empty, then run the migration.

func (*Scheduler) Stop

func (s *Scheduler) Stop()

Stop gracefully shuts down the scheduler.

func (*Scheduler) Unschedule

func (s *Scheduler) Unschedule(prefix string)

Unschedule stops every job added with Schedule whose id starts with prefix.

Jump to

Keyboard shortcuts

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