asyncqueue

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package asyncqueue is packtrail's durable asynchronous Invoker: it makes any ordinary synchronous Invoker run off the engine's critical path with at-least-once delivery. The Invoker contract's StatusPending + Server.CompleteActivity is the seam — asyncqueue supplies the machinery the engine deliberately leaves out, so embedding apps with slow nodes (an agent call, an HTTP request, a shell-exec) do not block an engine slot.

It has two halves:

  • Dispatcher is the parking side. It implements invoker.Invoker: instead of running the node inline it publishes a durable job to a JetStream work-queue and returns StatusPending, so the engine parks the execution (waiting) and frees its slot.
  • Worker is the execution side. It consumes those jobs, runs the embedder's own synchronous Invoker, and settles the result via Completer (CompleteActivity). A job is acked only after the completion is handed back, so a crashed worker's job is redelivered (at-least-once).

It is ecosystem-agnostic: the executor is a plain invoker.Invoker, so asyncqueue knows nothing about what the slow work actually is. Like invoker/natstask it depends on nothing beyond NATS.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EnsureStream

func EnsureStream(ctx context.Context, js jetstream.JetStream, prefix, kind string, opts ...Option) error

EnsureStream creates (idempotently) the JetStream work-queue stream that carries jobs for kind, with a dedup window so a redelivered dispatch does not double-enqueue. Call it once before publishing or consuming.

func StreamName

func StreamName(prefix, kind string) string

StreamName derives the work-queue stream name for an async invoker kind.

func Subject

func Subject(prefix, kind string) string

Subject derives the job subject for an async invoker kind.

Types

type Completer

type Completer interface {
	CompleteActivity(ctx context.Context, execID, node string, attempt int, res invoker.Result) error
}

Completer settles an asynchronous activity back on the packtrail engine. *packtrail.Server satisfies it; workers use its generation-aware completion method when the concrete completer exposes one.

type DeadLetterSink

type DeadLetterSink func(ctx context.Context, key, reason string, deliveries uint64)

DeadLetterSink records a job a Worker gave up on (Term'd). key is "<exec>/<node>", reason is the completion error, deliveries is the message's delivery count.

type Dispatcher

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

Dispatcher implements invoker.Invoker by publishing a durable job and reporting it as pending, so the engine parks the execution and frees its slot for the node's whole runtime. The job's dedup id is exec.node.generation.attempt, so a redelivered dispatch of the same attempt is collapsed; a genuine retry, Resume, or legal cycle revisit is not.

func NewDispatcher

func NewDispatcher(js jetstream.JetStream, prefix, kind string) *Dispatcher

NewDispatcher returns a Dispatcher publishing to the job subject for kind.

func (*Dispatcher) Invoke

func (d *Dispatcher) Invoke(ctx context.Context, req invoker.Request) (invoker.Result, error)

Invoke publishes the job and reports it as pending.

type Option

type Option func(*config)

Option configures a Worker and/or the work-queue stream. The same options are accepted by EnsureStream, NewWorker and packtrail's WithAsyncInvoker.

func WithAckWait

func WithAckWait(d time.Duration) Option

WithAckWait sets the job ack window, extended by heartbeats while a job runs (default 30s). A worker that dies mid-job has its job redelivered after this.

func WithActivityTimeout

func WithActivityTimeout(d time.Duration) Option

WithActivityTimeout sets the ceiling/backstop for each invocation the Worker runs (default 5m). A node's own per-call timeout tightens this when shorter; the effective bound is min(node timeout, activityTimeout). A node timeout longer than this ceiling is capped at it, so raise this when nodes legitimately need longer calls. The ack window is extended by heartbeats for the whole duration.

func WithConcurrency

func WithConcurrency(n int) Option

WithConcurrency caps how many jobs a Worker runs at once (default 64).

func WithDeadLetterSink

func WithDeadLetterSink(sink DeadLetterSink) Option

WithDeadLetterSink registers a callback invoked just before a Worker Terms a job it gave up on (a terminal completion error or an exhausted delivery cap), so the caller can record a durable trace of the dropped job. packtrail wires this to the dead-letter stream automatically.

func WithDedupWindow

func WithDedupWindow(d time.Duration) Option

WithDedupWindow sets the JetStream dedup window on the work-queue stream (default 2m). It only affects EnsureStream.

func WithDrainTimeout

func WithDrainTimeout(d time.Duration) Option

WithDrainTimeout sets how long a graceful Worker shutdown waits for in-flight jobs to settle before aborting the stragglers (default 30s). Within the window a clean shutdown lets running invocations finish and settle via CompleteActivity instead of abandoning them to redelivery.

func WithMaxDeliver

func WithMaxDeliver(n int) Option

WithMaxDeliver caps how many times a job is delivered before the Worker dead-letters it (Term, no redelivery) rather than Nak-looping on a persistent completion failure (default 10). A terminal completion error (e.g. the engine no longer knows the flow) is dead-lettered immediately, regardless of this cap. A non-positive value disables the cap (only terminal errors dead-letter).

func WithMaxQueuedBytes

func WithMaxQueuedBytes(n int64) Option

WithMaxQueuedBytes caps the total bytes retained in the durable work queue (default 1GiB). When full, new distinct jobs are rejected at publish time so the engine can retry dispatch instead of silently growing infrastructure storage without bound. Non-positive values keep the bounded default.

func WithMaxQueuedJobs

func WithMaxQueuedJobs(n int64) Option

WithMaxQueuedJobs caps the number of jobs retained in the durable work queue (default 10,000). When full, new distinct jobs are rejected at publish time so the engine can retry dispatch instead of silently growing infrastructure storage without bound. Non-positive values keep the bounded default.

type Worker

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

Worker consumes jobs for one async invoker kind and runs the embedder's synchronous Invoker off the engine's critical path, reporting completion via Completer. It is the durability boundary: a job is acked only after the completion is handed back, so a crashed worker's job is redelivered (at-least-once). Many Workers (in or out of process) can share a kind's work-queue stream to scale horizontally.

func NewWorker

func NewWorker(
	js jetstream.JetStream, prefix, kind string,
	exec invoker.Invoker, completer Completer, opts ...Option,
) *Worker

NewWorker builds a Worker that runs exec for jobs of kind and settles them via completer. prefix and kind must match the Dispatcher's. EnsureStream must have been called for the same kind (packtrail's WithAsyncInvoker does both).

func (*Worker) Run

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

Run consumes jobs until ctx is cancelled.

Jump to

Keyboard shortcuts

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