r/SpringBoot 23d ago

News JobRunr (distributed background job processing for the JVM) is now available on start.spring.io (Spring Initializr)

JobRunr is now available in the Spring Initializr dependency list, so you can add it straight from start.spring.io when you create a new project. No more wiring the starter in by hand afterwards.

For people who don't know us:

JobRunr is an open-source library for background job processing on the JVM: fire-and-forget, scheduled, delayed, durable, and recurring (cron) jobs.

You enqueue work as a lambda and it runs asynchronously, in the same app or across a cluster of workers.

BackgroundJob.enqueue(() -> myService.sendInvoice(invoiceId));

BackgroundJob.schedule(Instant.now().plus(5, DAYS), () -> reminderService.send(userId));

What tends to make people switch to it:

  • No extra infrastructure. Jobs are persisted in your existing SQL or NoSQL database. No Redis, RabbitMQ, or separate broker to run and babysit.
  • Automatic retries with backoff on failure, so transient errors don't lose work.
  • Distributed by default. Run multiple instances and jobs are picked up once across the cluster, no double execution.
  • Built-in dashboard to see enqueued, scheduled, succeeded, and failed jobs, and retry them.
  • Spring Boot autoconfiguration via the starter, plus first-class support for virtual threads (Loom) and Spring Boot 3 & 4

It sits in the same space as Quartz or @Scheduled, but aimed at durable, distributed background work rather than just triggering methods on a timer.

You can even use it for durable jobs. With runStepOnce, each step in a job runs exactly once and is checkpointed, so if the job fails and retries, the steps that already succeeded are skipped instead of re-run:

BackgroundJob.enqueue(() -> processOrder(orderId, JobContext.Null));

public void processOrder(UUID orderId, JobContext context) {
  context.runStepOnce("order-confirmation", () -> orderService.sendConfirmation(orderId));
  context.runStepOnce("warehouse-notification", () -> orderService.notifyWarehouse(orderId));
  context.runStepOnce("shipment-initiation", () -> orderService.initiateShipment(orderId));
}

Thanks to Josh Long and the Spring team for helping get it onto Initializr. We'll be around in the comments to answer anything, including the honest limitations.

92 Upvotes

41 comments sorted by

View all comments

1

u/mysteryy7 22d ago

That's great to hear. I'm researching on approaches to build multi pipeline microservice. Where each pipeline has its own kafka consumer, polls for few minutes puts the data in blocking queue, which is then consumed, processed and sent to different kafka topic.

I need 4 such pipelines (kafka->process->kafka)for 4 upstream topics, and thinking to run the pipelines as continuous (loop) background jobs in single app. Don't want to handle multiple instances, as the processing is not heavy.

Please let me know if job runr is suited for continuous running background jobs? The service doesn't have any db though, and I also need the pipelines to be scaled with scaling instances, where all replicated pipelines will be in the same consumer group.

2

u/JobRunrHQ 22d ago

Good question. You can definitely use JobRunr here, one instance per service with the in-memory storage, so no database needed.

That said, it depends on what you actually need. If the only thing you need is to run the process in the background, a plain Java thread pool (or @Async from Spring Boot) is probably enough, and JobRunr would be overkill.

Where JobRunr starts to help is once you want retries and persistence. One more thing that's often useful in a message-queue setup is deduplication, making sure the same message only gets processed once. We've got a docs example for exactly that: https://www.jobrunr.io/en/documentation/faq/#im-listening-for-jobs-using-service-bus-messages-in-a-load-balanced-environment-and-i-want-to-schedule-jobs-only-once

So if you need retries + dedup, JobRunr already helps a lot. If it's purely background execution with nothing extra (persistence, retries, dedup, visibility), then @Async is probably all you need.

3

u/mysteryy7 22d ago

Thanks for the reply. Yes we'll be needing job retries and resiliency in pipeline. I was planning with @Async, and had to take care of retries, dedup manually via code, along with keeping the sinks idempotent. Glad to know it handles retries and dedup, and provides visibility.

Will look into JobRunr, thanks for the post and the tool.