Skip to main content

Go Worker

The flare-go module ships a background-job worker runtime in the /worker subpackage. It turns the thin REST client into a full worker host: it announces itself to Zeridion Flare, long-polls for jobs, dispatches each to a typed Go handler with bounded concurrency, sends liveness heartbeats with progress, honours server-side cancellation, reports the outcome, and drains in-flight jobs gracefully on shutdown.

import (
flare "github.com/zeridion/flare-go"
"github.com/zeridion/flare-go/worker"
)

The worker lives in the same module as the client (no second dependency) and reuses the client you already build as its transport. Importing the worker is opt-in, so thin-client programs stay lean.

Requires: Go 1.22+

A complete worker

package main

import (
"context"
"time"

flare "github.com/zeridion/flare-go"
"github.com/zeridion/flare-go/worker"
)

type WelcomeEmail struct {
UserID string `json:"user_id"`
Email string `json:"email"`
}

func main() {
// Build the client the worker reuses as transport. Timeout: 0 keeps the
// long-poll from being aborted by a total request deadline.
client, _ := flare.NewClient(flare.WithHTTPClient(worker.NewPollHTTPClient()))

w := worker.NewWorker(client, worker.Options{
Queues: []string{"default", "maintenance"},
Concurrency: 5,
})

worker.Handle(w, "SendWelcomeEmail",
worker.JobConfig{Queue: "default", MaxAttempts: 5, Timeout: 60 * time.Second},
func(ctx context.Context, p WelcomeEmail, jc worker.JobContext) error {
jc.ReportProgress(0.5)
return sendEmail(ctx, p.Email)
})

worker.HandleRecurring(w, "NightlyCleanup",
worker.RecurringConfig{Cron: "0 3 * * *", Queue: "maintenance", Timezone: "UTC"},
func(ctx context.Context, jc worker.JobContext) error {
return cleanup(ctx)
})

// Blocks until SIGINT/SIGTERM, then drains and returns.
_ = w.Run(context.Background())
}

What the worker does for you

ConcernHandled by the runtime
IdentityA unique worker id is generated per process and announced on startup.
PollingLong-polls each configured queue and respects free-slot capacity.
DispatchDecodes the JSON payload into your handler's type and calls it.
ConcurrencyCaps simultaneous jobs at Concurrency; reports remaining capacity so the server never overfills the worker.
LivenessSends a heartbeat on claim and on a steady cadence while a job runs.
ProgressSurfaces jc.ReportProgress(...) on the next heartbeat.
CancellationA server cancel directive cancels the job's context.
TimeoutsEach job runs under a per-job deadline.
OutcomeReports success or a structured failure when the handler returns.
ShutdownStops polling on SIGINT/SIGTERM, waits for in-flight jobs, then returns.

How handlers run

  • A handler receives a context.Context that is cancelled when the job times out, the host shuts down, or the server asks to cancel. Pass it to every blocking call you make.
  • Cancellation is cooperative: Go cannot safely stop a running goroutine, so a handler that never checks its context keeps running until the server reclaims the job. Always honour the context.
  • Outcome reporting is best-effort, so a job can be delivered more than once (for example, a crash after the work finished but before the outcome was recorded). Handlers must be idempotent — guard side effects on jc.JobID.

Pages