Open-source project
gresrun/jesque avatar
gresrun/jesque

Jesque is a Resque implementation for Java with real interoperability

An implementation of Resque in Java.

629 stars133 forksJavaApache-2.0

At a glance

What is it?
Jesque speaks the same Redis protocol as the Ruby and Node.js Resque implementations, so a Java service and a Ruby service can share one queue, while jobs stay plain Runnable or Callable classes. Version 3 moved the whole project to Java 17, Jedis 7 and Jackson 3, and its delayed job implementation is explicitly not compatible with resque-scheduler.
Who is it for?
Jesque fits a Java team that must consume a queue shared with Resque workers, or that wants Resque semantics with plain Runnable job classes, and it does not fit a project already committed to another Java queue library or a team that needs the resque-scheduler plugin semantics, since the README states the delayed job implementation is not compatible with it.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 29 days 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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Interoperability is the feature, and it constrains the design

Jesque is an implementation of Resque in Java, and the README is specific about what that means: it is fully interoperable with the Ruby and the Node.js implementations, the latter being Coffee-Resque.

That word fully is doing a lot of work. A job queue protocol is not a private API between one client and one worker. If a Java service enqueues a job that a Ruby worker must pick up, then the queue names, the payload encoding, the job class identifier and the worker bookkeeping all have to match what Resque does. The interoperability claim therefore constrains the format, and any temptation to extend the payload format is limited by the requirement that other implementations can still read it.

The implementation choices reflect that. Jesque is a Maven project, and it depends on Jedis to connect to Redis, Jackson to map to and from JSON, and SLF4J for logging. Jackson is worth noting in particular: the job payload is JSON, so the argument types have to survive a JSON round trip, which is exactly why the job class in the example is constructed with a list of simple values.

The project ships two halves, a client implementation and a worker implementation that supports listeners. That split is the Resque model rather than a Java library convention, and it is why a Java producer and a Ruby consumer can coexist without either side knowing about the other.

Jobs are plain Runnable and Callable classes

The design decisions section explains the job model, and it is the part of the API you will touch first.

Jobs are implemented as classes that implement java.lang.Runnable or java.util.concurrent.Callable. If a job requires arguments, which most do, there must be a constructor that matches the supplied arguments. The stated reason for that choice is that it was the most flexible option and did not require jobs to inherit from or implement a special Jesque class. The consequence is that the jobs do not even need to know about Jesque at all.

There is a second consequence that matters for a distributed queue. The client does not need the job's Class in its VM. It only needs to know the class name and the Class objects of all the parameters. Only the workers realize the job and then run it. In other words, the producing side and the consuming side can have different classpaths, which is what makes a mixed Ruby and Java deployment possible in either direction.

The argument passing is by constructor, not by setter, and the values are serialized as JSON, so the types in the constructor have to be ones the JSON mapping can handle. The quickstart passes an int, a double, a boolean, a String and a List of mixed values, which is a good indication of the practical limits.

The other design note in that section is the reason for choosing Jedis: it is simple to use, it fully supports Redis 2.0, and it uses the new unified protocol.

The quickstart shows a client, a worker and a shutdown sequence

The quickstart is compact enough to read as the whole life of a job.

Configuration is built with a builder that takes a host and port and an optional password. A job is created with a name, which is the action class name, and the arguments as an array. A client is created from the config, the job is enqueued onto a named queue, and the client is closed:

java
var client = new ClientImpl(config);
client.enqueue("foo", job);
client.end();

The worker side needs three things: the list of queues to listen on, a job factory that maps an action name to a class, and the worker itself. The factory in the example is a MapBasedJobFactory built from a map of TestAction to the TestAction class. The worker is then run in its own thread.

Shutdown is explicit and worth copying. The worker is ended, and the thread is joined:

java
worker.end(true);
try {
  workerThread.join();
} catch (Exception e){
  e.printStackTrace();
}

For throughput, the client offers a batch API for enqueueing several jobs at once, described as an optimized way to do it, which matters because each enqueue is a network round trip to Redis.

There is also a pooled client for multi-threaded applications, constructed with a Jedis pool from the same config, and it exposes the same enqueue call.

Delayed and recurring jobs, and the compatibility hole between them

Jesque supports two scheduling features on top of plain enqueueing, and they come with an important caveat.

Delayed jobs take an Instant in the future and are enqueued with a delayed enqueue call against a named queue. Recurring jobs take a start Instant plus a Duration interval, so a job can begin at a specific time and then repeat at a fixed frequency. Both are cancelled with matching remove calls that take the job and the queue name.

The caveat is stated in a single line and deserves more attention than it gets: the delayed jobs implementation is not compatible with resque-scheduler. Resque's scheduling is normally done by a separate Ruby project called resque-scheduler, and it works by moving jobs between Redis lists and a scheduled set. If Jesque writes delayed jobs in a different arrangement, a resque-scheduler instance and a Jesque client disagree about where the pending job lives, and the job is either run early, run never, or picked up twice.

So the feature works, but only within a world where all the scheduling is done through Jesque. That is a reasonable constraint for a Java-only deployment, and a trap for a mixed one, and it is the kind of detail that is invisible until the day the two systems meet.

The recurring feature is described in the same terms, with no compatibility note attached, and the same question applies to it: the README documents the Resque interoperability claim for the queue protocol, not for the scheduling extensions, and it makes exactly one exception explicit for delayed jobs.

Eight worker events, and a listener for each

The worker supports custom callbacks on specific events, registered through an event emitter on the worker.

The listener example is a lambda that receives the event, the worker, the queue, the job, the runner, the result and a throwable, and it can act on the runner before or during execution. The event it is registered for is JOB_EXECUTE, which the README describes as about to execute a materialized job, and the example uses that moment to set a variable on the runner instance.

Eight events are listed, and they divide cleanly into lifecycle and job outcomes. WORKER_START is finished starting up and about to start running, WORKER_POLL is polling the queue, and WORKER_STOP is finished running and about to shut down. WORKER_ERROR is an exception caught during normal operation.

The job-level events are JOB_PROCESS for processing a job, JOB_EXECUTE for about to execute a materialized job, JOB_SUCCESS for a successfully executed materialized job, and JOB_FAILURE for an exception caught during the execution of a materialized job. The distinction between WORKER_ERROR and JOB_FAILURE is the one to get right when wiring monitoring: a job failure is an expected outcome the queue records, while a worker error means the worker itself hit a problem.

For visibility, the README points to the resque-web application to see the status of jobs and workers, and to Jesque-Web as a Java alternative. That last point matters for interoperability: if the Ruby tool works, it works on a Jesque deployment, which is a quick way to confirm the interoperability claim.

Java 17, Jedis 7 and Jackson 3 in version 3, with a 2.x line behind it

The 3.0 release is a platform upgrade, and the README devotes a section to it.

Jesque requires Java 17 or newer. If you are running Java 8 through 16, the README says you can still use the 2.x versions, the latest of which is 2.3.0. That is an explicit maintenance line, which is more than most libraries in this position offer.

Starting with 3.0.0 the project requires Java 17 and has been modernized to use the latest Jedis client, 7.2.x, and Jackson 3.x. The Jedis change requires minor refactoring if you were constructing pooled connections manually, and Jackson 3 has a comprehensive migration guide covering the exception types and the ObjectMapper class. Jesque itself has some minor breaking API changes, including how Config objects are constructed and the types of durations and future times.

Those last two are the ones that will bite you in your own code rather than in a dependency. If your application builds a Config directly, or passes durations and future instants, the compile errors are yours, not Jedis's or Jackson's.

Configuration of the Redis connection is shown with a snippet that reads a system property named REDIS_PROVIDER, parses it as a URI, and applies the host, port and password from the user info portion when present. The default value of that property is 127.0.0.1.

The release record shows a long gap that has now closed. Version 2.2.0 was published on 2021-12-30, 2.3.0 on 2025-12-28 and 3.0.0 on 2026-01-19, and the last push was on 2026-09-25. The project is not archived, is Apache-2.0 licensed and is published to Maven Central under the group net.greghaines with the artifact id jesque.

Editorial conclusion

Jesque fits a Java team that must consume a queue shared with Resque workers, or that wants Resque semantics with plain Runnable job classes, and it does not fit a project already committed to another Java queue library or a team that needs the resque-scheduler plugin semantics, since the README states the delayed job implementation is not compatible with it. Before you upgrade, plan for the 3.0 changes, because Config construction, duration types and future times all changed along with the Jedis and Jackson upgrades, and keep using the 2.x line if you are still on Java 8 through 16. The project is Apache-2.0 licensed, version 3.0.0 was released on 2026-01-19, and the last push was on 2026-09-25.

Frequently asked questions

How do I add Jesque to a Maven project?

Add the dependency with groupId net.greghaines, artifactId jesque and version 3.0.0. The README notes that version 3.0.0 requires Java 17 or newer, and that the 2.x line, whose latest is 2.3.0, still works on Java 8 through 16.

What class should a Jesque job extend?

None. The design notes say jobs are implemented as classes implementing java.lang.Runnable or java.util.concurrent.Callable, with a constructor matching the supplied arguments, so the jobs do not need to know about Jesque at all.

Is Jesque's delayed job support compatible with resque-scheduler?

No. The README states that Jesque's delayed jobs implementation is not compatible with resque-scheduler, so scheduling needs to be handled on one side of the system rather than split between the two.

How do I monitor worker activity in Jesque?

You register listeners on the worker event emitter. The available events are WORKER_START, WORKER_POLL, JOB_PROCESS, JOB_EXECUTE, JOB_SUCCESS, JOB_FAILURE, WORKER_ERROR and WORKER_STOP, and the README also points to the resque-web application or Jesque-Web to see the status of jobs and workers.

Official sources

  1. gresrun/jesque on GitHub
  2. License: Apache-2.0
  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/gresrun-jesque.svg)](https://hysenlabs.com/projects/gresrun-jesque)

Was this useful?