Library / SDK
jobrunr/jobrunr avatar
jobrunr/jobrunr

JobRunr: background jobs in Java as a lambda, stored in your own database

An extremely easy way to perform background processing in Java. Backed by persistent storage. Open and free for commercial use.

3,092 stars324 forksJavaNOASSERTION

At a glance

What is it?
JobRunr turns Java 8 lambdas into persistent, distributed background jobs on top of a database you already run. Here is how its mechanism works, how to install it, and where it stops being the right tool.
Who is it for?
Adopt JobRunr when you already run Postgres, MySQL, MongoDB or another supported store, want fire-and-forget, delayed and recurring jobs from lambdas, and need a dashboard without adding a broker. Do not adopt it when your workloads are event streaming with high fan-out, or when you cannot add the JobRunr tables and the polling traffic to your database.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem JobRunr solves for Java teams

Most Java applications reach a point where a request should return before the work finishes. Sending a batch of notifications, generating a document, importing a CSV, or updating a search index all take longer than a user will wait. The usual answers are an in-process ExecutorService, which loses work when the JVM restarts, or a message broker plus a consumer, which adds a service to operate.

JobRunr targets the middle ground. The README describes it as a library to perform background processing on the JVM, embeddable in existing applications, with persistent storage via an RDBMS (Postgres, MariaDB/MySQL, Oracle, SQL Server, DB2, SQLite) or MongoDB. The audience is a Java team that already runs one of those databases and does not want another moving part. The README lists the usage scenarios it was written for: returning an HTTP response immediately while a long job runs, mass notifications, batch imports, image and video processing, recurring reports, database maintenance.

The API is the selling point, and it is genuinely small. One lambda, one static call. Whether that simplicity survives contact with your failure modes is the question the rest of this article addresses.

How JobRunr stores and executes a job

Enqueueing a lambda does not run it. The README states that persistent jobs are stored using either a RDBMS (four tables and a view) or a NoSQL data store. So the call writes a job record into your database, and a background job server polls that storage, picks up work, and executes it. The lambda is serialized rather than held in memory, which is why the storage layer is not optional.

Distribution is handled with optimistic locking. The README says JobRunr is "distributed & cluster-friendly: guarantees execution by single scheduler instance using optimistic locking." In practice that means several application instances can run background job servers against the same database, and the lock decides which one takes a given job. You scale horizontally by adding instances, and the README states JobRunr distributes the load across them.

Failure handling is built in. The README states that if an external web service is down, the job is automatically retried 10 times with a back-off policy. That is a default, not a guarantee that suits every workload, and it is worth reading the retry configuration before you rely on it for jobs with side effects.

The dependency footprint is deliberately small: ASM, slf4j, and one JSON library (Jackson with jackson-datatype-jsr310, Gson, or a JSON-B compliant library). There is no broker, no separate scheduler process, and no network hop beyond your own database.

Installing JobRunr from Maven Central and scheduling your first job

The README shows the artifact on Maven Central as org.jobrunr:jobrunr. Add that dependency to your build, then use the API exactly as the README demonstrates. The three examples below are copied from the README's overview and usage sections.

Fire-and-forget work: dedicated worker pool threads execute queued background jobs as soon as possible, shortening the request's processing time.

java
BackgroundJob.enqueue(() -> System.out.println("This is all you need for distributed jobs!"));

Delayed work: scheduled background jobs are executed only after a given amount of time.

java
BackgroundJob.schedule(Instant.now().plusHours(5), () -> System.out.println("Reliable!"));

Recurring work: the README calls this method with a job id and a CRON expression.

java
BackgroundJob.scheduleRecurrently("my-recurring-job", Cron.daily(), () -> service.doWork());

After the first enqueue, what you should see is a row in the JobRunr tables and, once a background job server is running, the job moving to a succeeded state. The README excerpt does not spell out the server bootstrap, and it points to the documentation site for background method details and for Spring support. Treat the dashboard as the fastest way to confirm the job actually ran rather than trusting the enqueue call.

Where JobRunr is the wrong choice

The storage model is the constraint. Every job is a database row, and background job servers poll that database. If your workload is millions of short tasks per hour, you are paying for a write, a poll, a lock and a status update per task on a database that is also serving your application. The README positions JobRunr for CPU and I/O intensive work, long-running and short-running jobs, not for high-throughput event streams. For that shape of problem a log-based broker is a better fit, and the README itself names Kafka-adjacent territory only indirectly by listing Celery, Resque and Sidekiq as the equivalents it replaces.

Second, the lambda has to be serializable in a way the storage layer can reconstruct. JobRunr's model is a method call captured from a lambda, executed later, possibly on another JVM. Jobs that close over large in-memory state, or that depend on something only present in the request thread, do not fit that model cleanly.

Third, the licensing is not a single answer. The repository root contains License.md, License-lgpl.md, License-royaltyfree.md and License-standard.md, and the README badge says LGPLv3. The repository's licence field is recorded as NOASSERTION. If your organisation has rules about LGPL or about which of those files governs commercial use, resolve that before writing code, not after.

JobRunr compared with Quartz and Spring's scheduler

Quartz is the closest comparison, and the README acknowledges it directly: JobRunr is "similar to Quartz and Spring Task Scheduler." The difference in approach is what you write. Quartz makes you implement a Job interface and register it with a trigger and a scheduler; the unit of work is a class. JobRunr makes the unit of work a lambda, so the code that enqueues and the code that runs can be the same line, and the job definition is not a separate artifact to keep in sync.

The second difference is failure semantics. Quartz gives you triggers, misfire instructions and a JobStore you configure yourself. JobRunr ships a retry default of 10 attempts with back-off and a dashboard as part of the library, and it decides the persistence schema for you (the README's four tables and a view). That is less control and less setup.

Against Spring's Task Scheduler the split is scheduling versus execution. Spring's scheduler is in-process: a restart loses the pending work, and multiple instances each run their own copy of a scheduled method. JobRunr's persistent store and optimistic locking exist precisely to avoid that duplication across instances. If you run a single instance and can tolerate losing a scheduled tick on restart, Spring's scheduler is fewer moving parts.

The README also places JobRunr alongside Hangfire, Resque, Sidekiq, delayed_job and Celery, which are the same idea in other runtimes. If your team already knows one of those, JobRunr is the JVM translation of that mental model, with your existing database playing the role of Redis.

Maintenance, releases and what upgrading costs

The project is not archived, and the last push was on 2026-09-23. Releases are frequent: v8.8.0 on 2026-07-30, v8.8.1 on 2026-08-07, and v8.8.2 on 2026-08-21. That cadence means patch releases arrive quickly, and it also means you should pin a version rather than float one.

The upgrade cost sits in two places. First, the storage schema. Because JobRunr owns four tables and a view in your database, a major version can change what those tables look like, and the README does not document rollback in the excerpt available. Check the release notes for schema migrations before upgrading in production, and take a database backup first.

Second, the serialized job payloads. Jobs are persisted as data, so a job enqueued under one version is read back by whatever version is running when it executes. Upgrading a cluster is not atomic, which is the same constraint any persistent job store has.

On licensing, the repository carries multiple licence files and the README badge reads LGPLv3 while the repository's licence field is NOASSERTION. The README states the project is open and free for commercial use, and separately there is a Pro offering referenced in the project's search footprint. Which file applies to your use is a question for your own legal review; the repository is the source to read, and this article is not legal advice.

Editorial conclusion

Adopt JobRunr when you already run Postgres, MySQL, MongoDB or another supported store, want fire-and-forget, delayed and recurring jobs from lambdas, and need a dashboard without adding a broker. Do not adopt it when your workloads are event streaming with high fan-out, or when you cannot add the JobRunr tables and the polling traffic to your database. Before committing, verify which licence file applies to your intended use, confirm your storage engine is on the supported list, and check whether the Pro-only features you need are actually present in the open source build.

Frequently asked questions

What is JobRunr?

JobRunr is a Java library for performing background processing on the JVM, using Java 8 lambdas to define fire-and-forget, delayed, scheduled and recurring jobs. It is embeddable in existing applications and backed by persistent storage in an RDBMS or MongoDB.

Is JobRunr free and open source?

The README states the project is open and free for commercial use, and the badge shows LGPLv3. The repository root also contains License-lgpl.md, License-royaltyfree.md, License-standard.md and License.md, and the repository's licence field is recorded as NOASSERTION, so confirm which file governs your use.

JobRunr vs Quartz: what is the difference?

The README describes JobRunr as similar to Quartz. With Quartz the unit of work is a Job class registered with a trigger; with JobRunr it is a lambda passed to a static call such as BackgroundJob.enqueue, and the persistence schema and retry behaviour come with the library rather than being configured separately.

JobRunr vs Spring Scheduler: which should I use?

Spring's Task Scheduler runs in-process, so pending work is lost on restart and each instance runs its own copy of a scheduled method. JobRunr persists jobs and uses optimistic locking so a single scheduler instance takes each job, which is what makes it cluster-friendly.

How do I use a scheduler in Java with JobRunr?

The README shows three entry points: BackgroundJob.enqueue for fire-and-forget work, BackgroundJob.schedule with an Instant for delayed work, and BackgroundJob.scheduleRecurrently with a job id and a CRON expression for recurring work. All three take a Java 8 lambda.

JobRunr vs Kafka: are they alternatives?

The README does not present Kafka as an alternative; it lists Hangfire, Resque, Sidekiq, delayed_job and Celery as the equivalents it replaces. JobRunr persists jobs as rows in a database and polls them, which is a different model from a log-based event stream.

Official sources

  1. Issues
  2. jobrunr/jobrunr on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jobrunr-jobrunr.svg)](https://hysenlabs.com/projects/jobrunr-jobrunr)