heartbeat

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 13, 2026 License: AGPL-3.0 Imports: 6 Imported by: 0

Documentation

Overview

Package heartbeat implements the worker's periodic liveness signal to sqi-server.

Overview

A Publisher ticks on a configurable interval and publishes a protocol.HeartbeatMsg to the bus.SubjectWorkerHeartbeat NATS subject. Each message carries the worker's current runtime state (active task count, active task IDs, uptime, last assignment time) so the server can detect stale assignments without additional store queries.

Watchdog

Publisher.Run also spawns an internal watchdog goroutine that polls the NATS connection status every [watchdogPollInterval]. When it observes a transition from a non-connected state back to connected it calls Registrar.Register — but only if the reconnect callback installed by [registration.Registrar.SetupReconnectHook] did not already succeed (as indicated by Registrar.LastRegisteredAt). This guards against the case where the callback's publish fails or is lost without producing a duplicate registration on every normal reconnect.

Latency warning

After publishing a heartbeat the Publisher calls [nats.Conn.FlushTimeout] to drain the NATS outbound buffer to the TCP layer. If the flush does not complete within half the configured interval the Publisher logs a warning, indicating that the NATS server or network connection is under strain and backpressure is building in the write buffer.

StateSource

StateSource is the interface through which the Publisher reads live task state. It is satisfied by the executor. Until the executor exists, callers pass a NoopStateSource which reports zero active tasks.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type NoopStateSource

type NoopStateSource struct{}

NoopStateSource is a StateSource that always reports zero active tasks. Use it before the executor is available.

func (NoopStateSource) ActiveTaskCount

func (NoopStateSource) ActiveTaskCount() int

ActiveTaskCount always returns 0.

func (NoopStateSource) ActiveTaskIDs

func (NoopStateSource) ActiveTaskIDs() []string

ActiveTaskIDs always returns nil.

func (NoopStateSource) LastAssignmentAt

func (NoopStateSource) LastAssignmentAt() *time.Time

LastAssignmentAt always returns nil.

type Publisher

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

Publisher periodically publishes protocol.HeartbeatMsg to bus.SubjectWorkerHeartbeat and runs an internal watchdog goroutine that triggers re-registration when the NATS connection is restored after a drop and the reconnect callback did not already succeed.

Obtain one with New and call Publisher.Run in a goroutine; it blocks until ctx is canceled.

func New

func New(
	nc natsConn,
	workerID string,
	maxConcurrentTasks int,
	interval time.Duration,
	state StateSource,
	registrar Registrar,
	logger *slog.Logger,
) *Publisher

New creates a Publisher. nc and registrar must be non-nil.

  • workerID: the stable worker identity string published in each message.
  • maxConcurrentTasks: the worker's configured concurrency ceiling, included in each heartbeat for server-side capacity tracking.
  • interval: how often to publish; must be > 0.
  • state: provides live task counts and IDs; pass NoopStateSource until the executor is wired in.
  • registrar: called by the watchdog when a reconnect is detected and the callback did not already re-register.

func (*Publisher) Run

func (p *Publisher) Run(ctx context.Context)

Run starts the heartbeat ticker and the NATS watchdog goroutine. It blocks until ctx is canceled. Callers should invoke Run in a goroutine.

The watchdog and the ticker share the same parent context; canceling ctx stops both cleanly.

type Registrar

type Registrar interface {
	// Register publishes a registration message to the server. Safe to call
	// multiple times; the server upserts based on worker ID.
	Register(ctx context.Context) error
	// LastRegisteredAt returns the time of the most recent successful Register
	// call, or the zero time if Register has never been called successfully.
	// The watchdog uses this to avoid re-registering when the reconnect callback
	// already handled it.
	LastRegisteredAt() time.Time
}

Registrar is the subset of [registration.Registrar] used by the watchdog to trigger re-registration when a NATS reconnect is detected.

Defined as an interface so that tests can substitute a lightweight stub without constructing a full Registrar.

type StateSource

type StateSource interface {
	// ActiveTaskCount returns the number of task processes currently running.
	ActiveTaskCount() int
	// ActiveTaskIDs returns a snapshot of the IDs of all currently running
	// tasks. Implementations must return a value that is safe for the caller
	// to hold across concurrent mutations of the underlying task set — either
	// a snapshot copy or an immutable slice.
	ActiveTaskIDs() []string
	// LastAssignmentAt returns the time of the most recent task assignment,
	// or nil if the worker has not yet received any assignment in this process
	// lifetime.
	LastAssignmentAt() *time.Time
}

StateSource provides the Publisher with live task-execution state. Implemented by the executor package; use NoopStateSource until then.

Jump to

Keyboard shortcuts

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