Enqueueing jobs

Fire-and-forget method invocation has never been simpler thanks to JobRunr.

Creating a background job with JobRunr is really easy. On this page you will learn how to:

Enqueueing a single background job

Enqueueing a job using a Java 8 lambda

As you already know from the 5 minute intro, you only need to pass a lambda with the corresponding method and its arguments to enqueue a background job:

JobId jobId = BackgroundJob.enqueue(() -> myService.doWork());
This enqueues a background job using an instance of MyService which is available during enqueueing.
JobId jobId = BackgroundJob.<MyService>enqueue(x -> x.doWork());
This enqueues a background job without a reference to an instance of MyService. During execution of the background job, the IoC container will need to provide an instance of type MyService.

Enqueueing a job using a JobRequest

JobRunr also offers the possibility to enqueue jobs using a JobRequest and a JobRequestHandler.

JobId jobId = BackgroundJobRequest.enqueue(new MyJobRequest());
This enqueues a background job using an implementation of the JobRequest interface. The interface defines a handler that will be used to run the background job. During execution of the background job, the IoC container will need to provide an instance of that handler - in this case an instance of type MyJobRequestHandler.

JobId jobId = BackgroundJob.create(aJob()
    .withName("Generate sales report")
    .<SalesReportService>withDetails(service -> service.generateSalesReport()));
This enqueues a background job using the JobBuilder. All Job properties are properties are configurable when using the JobBuilder, including the name and the amount of retries.

The methods above do not call the target method immediately but instead run the following steps:

  • Either the JobRequest is used or the lambda is analyzed to extract the method information and all its arguments.
  • The method information and all its arguments are serialized to JSON.
  • A new background job is created based on the serialized information.
  • The background job is saved to the configured StorageProvider.
  • After these steps were performed, the BackgroundJob.enqueue or BackgroundJob.create method immediately returns to the caller. Another JobRunr component, called BackgroundJobServer, checks the persistent storage for enqueued background jobs and performs them in a reliable way.

Instead of the static methods on the BackgroundJob class, you can also use the JobScheduler bean. It has exactly the same methods as the BackgroundJob class. To use it, just let your dependency injection framework inject an instance of the JobScheduler bean and continue as before:

@Inject
private JobScheduler jobScheduler;
 
jobScheduler.enqueue(() -> myService.doWork());
Enqueueing background jobs using the JobScheduler bean

As before, you also do not need an instance of the myService available if the MyService class is know by your dependency injection framework.

Enqueueing a job using the JobScheduler and a Java 8 lambda

@Inject
private JobScheduler jobScheduler;
 
jobScheduler.<MyService>enqueue(x -> x.doWork());
Enqueueing background jobs using the JobScheduler bean without a reference to the MyService instance. The MyService instance will be resolved using the IoC framework when the background job is started.

Enqueueing a job using the JobRequestScheduler and a JobRequest

@Inject
private JobRequestScheduler jobRequestScheduler;
 
jobRequestScheduler.enqueue(new MyJobRequest());
Enqueueing background jobs using the JobRequestScheduler bean. The handler for `MyJobRequest` will be resolved using the IoC framework when the background job is started.
@Inject
private JobScheduler jobScheduler;

@Inject
private SalesReportService salesReportService;
 
jobScheduler.create(aJob()
    .withName("Generate sales report")
    .withDetails(() -> salesReportService.generateSalesReport()));
Enqueueing background jobs scheduling using the JobBuilder pattern.

Enqueueing background jobs in bulk

Sometimes you want to enqueue a lot of jobs - for example send an email to all users. JobRunr can process a Java 8 Stream of objects and for each item in that Stream, create a background job. The benefit of this is that it saves these jobs in bulk to the database - resulting in a big performance improvement.

Enqueueing many jobs using a Java 8 lambda

Stream<User> userStream = userRepository.getAllUsers();
BackgroundJob.enqueue(userStream, (user) -> mailService.send(user.getId(), "mail-template-key"));
Enqueueing emails in bulk using the Stream API with an instance of the mailService available
Stream<User> userStream = userRepository.getAllUsers();
BackgroundJob.enqueue<MailService, User>(userStream, (service, user) -> service.send(user.getId(), "mail-template-key"));
Enqueueing emails in bulk using the Stream API with an instance of the mailService not available

Enqueueing many jobs using a JobRequest

Stream<SendMailJobRequest> jobStream = userRepository
    .getAllUsers()
    .map(user -> new SendMailJobRequest(user.getId(), "mail-template-key"));
BackgroundJobRequest.enqueue(jobStream);
Enqueueing emails in bulk using the Stream API with an instance of the mailService not available
Stream<JobBuilder> jobStream = userRepository
    .getAllUsers()
    .map(user -> aJob().withName("Send email").withJobRequest(new SendMailJobRequest(user.getId(), "mail-template-key")));
BackgroundJobRequest.create(jobStream);
Enqueueing emails in bulk using the Stream API by means of the JobBuilder pattern

This allows for nice integration with the Spring Data framework which can return Java 8 Streams - this way, items can be processed incrementally and the entire database must not be put into memory.

Of course the above methods to enqueue jobs can also be done using the JobScheduler bean.

Enqueueing many jobs using the JobScheduler and a Java 8 lambda

@Inject
private JobScheduler jobScheduler;

Stream<User> userStream = userRepository.getAllUsers();
jobScheduler.enqueue(userStream, (user) -> mailService.send(user.getId(), "mail-template-key"));
Enqueueing background job methods in bulk using the JobScheduler bean
@Inject
private JobScheduler jobScheduler;

Stream<User> userStream = userRepository.getAllUsers();
jobScheduler.enqueue<MailService, User>(userStream, (service, user) -> service.send(user.getId(), "mail-template-key"));
Enqueueing background job methods in bulk using the JobScheduler bean

Enqueueing many jobs using the JobRequestScheduler and a JobRequest

Stream<SendMailJobRequest> jobStream = userRepository
    .getAllUsers()
    .map(user -> new SendMailJobRequest(user.getId(), "mail-template-key"));
jobRequestScheduler.enqueue(jobStream);
Enqueueing emails in bulk using the Stream API by means of a JobRequest.
Stream<JobBuilder> jobStream = userRepository
    .getAllUsers()
    .map(user -> aJob()
        .withName("Send email")
        .withJobRequest(new SendMailJobRequest(user.getId(), "mail-template-key")));
jobRequestScheduler.create(jobStream);
Enqueueing emails in bulk using the Stream API by means of the JobBuilder pattern

Prevent duplicate jobs thanks to the JobIdentifier

Sometimes you want to limit how many times a job is created. JobRunr Pro helps you with the JobIdentifier which will only create the job if no job with that identifier exists.

Creating a job only once using a JobIdentifier

@Inject
private JobScheduler jobScheduler;
 

jobScheduler.<MyService>enqueue(JobId.fromIdentifier("my identifier"), x -> x.doWork());
Enqueueing this job will happen only once as it is identified.

Replacing an existing job using a JobIdentifier

If you need to replace an existing job with an identifier, this can be done as follows:

@Inject
private JobScheduler jobScheduler;
 

jobScheduler.<MyService>enqueueOrReplace(JobId.fromIdentifier("my identifier"), x -> x.doWork());
Only the last job identified by 'my identifier' will be kept as previous jobs will be replaced.

You can learn more about replacing and updating jobs here.

Please also see the best practices for more information.