Skip to main content

Java worker

The com.zeridion:flare package ships a built-in background-worker runtime in the opt-in com.zeridion.flare.worker package. Thin-client users who only enqueue jobs pay nothing for it; importing the worker package turns the same artifact into a full worker host.

A worker:

  1. registers itself with Flare (its id, served queues, job types, and any recurring schedules),
  2. long-polls for jobs on its queues,
  3. dispatches each job to your handler with bounded concurrency,
  4. heartbeats while a job runs (carrying progress, and reacting if Flare asks to cancel),
  5. acks the outcome (succeeded or failed), and
  6. drains gracefully on SIGTERM/SIGINT — finishing in-flight jobs before it exits.

It reuses the FlareClient transport (authentication, timeouts, the response cap) and adds no new mandatory dependency.

Requirements

  • Java 17+ (LTS).
  • A FlareClient (the worker reuses its transport).
<dependency>
<groupId>com.zeridion</groupId>
<artifactId>flare</artifactId>
<version>0.2.1</version>
</dependency>

Quick start

Define a job, register it on a worker, and run:

import com.zeridion.flare.FlareClient;
import com.zeridion.flare.worker.*;

@FlareJob(name = "SendWelcomeEmail", queue = "default", maxAttempts = 5, timeoutSeconds = 60)
public final class SendWelcomeEmail implements Job<NewUserEvent> {
public void execute(NewUserEvent payload, JobContext ctx) {
if (ctx.isCancellationRequested()) return;
mailer.send(payload.email); // make this idempotent (see below)
ctx.reportProgress(1.0);
}
}
FlareClient client = FlareClient.builder().build(); // FLARE_API_KEY from env

FlareWorker worker = FlareWorker.builder(client)
.options(WorkerOptions.builder().concurrency(5).build())
.register(SendWelcomeEmail.class, NewUserEvent.class, SendWelcomeEmail::new)
.build();

worker.run(); // blocks until SIGTERM/SIGINT, then drains

run() installs a shutdown hook and blocks. For embedded control, use start() (returns immediately) and stop() (idempotent; drains). The worker is also AutoCloseable, so it works in a try-with-resources block.

The one rule: idempotent handlers

Acks are best-effort, so delivery is at-least-once: if a process dies after the work completes but before the ack reaches Flare, the job is delivered again. Write every handler so that running it twice for the same job is safe — guard side effects on ctx.jobId():

public void execute(NewUserEvent payload, JobContext ctx) {
if (alreadyProcessed(ctx.jobId())) return; // dedupe on the job id
mailer.send(payload.email);
markProcessed(ctx.jobId());
}

Worker identity

Each worker generates a stable id of the form wrk_<host>_<pid>_<random>. The host is sanitised to the characters Flare accepts and the random suffix comes from a secure generator, so two workers on the same machine (or sharing a container hostname) never collide.

Next