JobRunr Pro

Dynamic Queues

Dynamic Queues - also knows as load-balancing or multi-tenancy support - guarantees some fair-use!

Are you running a multi-tenant application? Or do you have diverse types of jobs where certain types of jobs could potentially trigger peak workloads? Use JobRunr’s built-in dynamic queues to make sure that there is some fair-use and all jobs get a fair amount of resources!

Note: JobRunr Pro supports unlimited dynamic queues and they can be used together with the priority queues.

Example Use Cases

  • In a multi-tenant application where each tenant can initiate their own jobs, JobRunr ensures fair-use processing. Regardless of whether one tenant generates millions of jobs, the system guarantees that jobs from other tenants are also duly processed.
  • In a diverse workload environment, certain jobs, such as mass mailings, could potentially trigger surges by generating millions of subsidiary child jobs that require processing. However, it’s crucial that other types of jobs remain unaffected by these spikes and continue to be processed smoothly.

Load-balancing types

JobRunr supports two different types of load-balancing:

  • Round Robin Dynamic Queues: here, each dynamic queue receives the same amount of resource usage
  • Weighted Round Robin Dynamic Queues: : here, certain dynamic queues can be configured with an optional weight. A queue with a weight of 2 will be checked twice as often as a queue with a weight of 1.

Dashboard

If you’re using this feature, you can also enable an extra Dynamic Queues view in the dashboard. This view gives an immediate overview of the amount of jobs per dynamic queue.

An overview of all the different dynamic queues

Usage

Using dynamic queues is as easy as adding a label to your job!

Configuration

Round Robin Dynamic Queues

Configuring Round Robin Dynamic Queues by means of the Fluent API:
You can configure your round robin dynamic queues easily by means of the Fluent API:

JobRunrPro.configure()
    .useStorageProvider(SqlStorageProviderFactory.using(dataSource))
    .useBackgroundJobServer(usingStandardBackgroundJobServerConfiguration()
            .andWorkerCount(100)
            .andDynamicQueuePolicy(new RoundRobinDynamicQueuePolicy("tenant:")))
    .useDashboard(usingStandardDashboardConfiguration()
            .andDynamicQueueConfiguration("Tenants", "tenant:"))
    .initialize();
Notice the RoundRobinDynamicQueuePolicy where we add the label prefix 'tenant:'.
We also enable the extra Dynamic Queue view in the dashboard and name it 'Tenants'

Configuring Round Robin Dynamic Queues by means of Spring Boot Properties:
You can also enable the round robin dynamic queues easily via Spring properties:

org.jobrunr.jobs.dynamic-queue.round-robin.label-prefix=tenant: 
org.jobrunr.jobs.dynamic-queue.round-robin.title=Tenants
Weighted Round Robin Dynamic Queues

Configuring Weighted Round Robin Dynamic Queues by means of the Fluent API:
You can again easily configure your weighted round robin dynamic queues by means of the Fluent API:

JobRunrPro.configure()
    .useStorageProvider(SqlStorageProviderFactory.using(dataSource))
    .useBackgroundJobServer(usingStandardBackgroundJobServerConfiguration()
            .andWorkerCount(100)
            .andDynamicQueuePolicy(new WeightedRoundRobinDynamicQueuePolicy("tenant:", Map.of("Tenant-A", 5))))
    .useDashboard(usingStandardDashboardConfiguration()
            .andDynamicQueueConfiguration("Tenants", "tenant:"))
    .initialize();
Notice the WeightedRoundRobinDynamicQueuePolicy where we add the label prefix 'tenant:'.
'Tenant-A' is configured with a weight of 5 meaning that it will get 5 times more resources than other tenants.

Configuring Weighted Round Robin Dynamic Queues by means of Spring Boot Properties:
You can also enable the weighted round robin dynamic queues easily via Spring Bean:

@Bean(name = "dynamicQueuePolicy")
public DynamicQueuePolicy weightedRoundRobinDynamicQueuePolicy() {
    return new WeightedRoundRobinDynamicQueuePolicy(labelPrefix, Map.of("Tenant-A", 5));
}
A DynamicQueuePolicy bean is created where we again add the label prefix 'tenant:'.
'Tenant-A' is configured with a weight of 5 meaning that it will get 5 times more resources than other tenants.

Usage

Using dynamic queues could not have been easier thanks to Job Labels:

Using the @Job annotation:

@Job(name = "Job %1 for %0", labels = {"tenant:%0", "slow-job"})
public void runBackgroundWork(String tenant, int index) {
    // business code here
}
We can use the @Job annotation and note how we re-use the previously configured label prefix 'tenant:'.
This can be done both hardcoded or dynamic by means of a placeholder in the label, like in this example.

Using the JobBuilder pattern:

If you prefer the JobBuilder pattern, this is also really easy:

jobScheduler.create(aJob()
    .withName("Job " + i + " for tenant " + tenant)
    .withLabels("tenant:" + tenant)
    .withDetails(() -> myService.runBackgroundWork(input)))
We can use the JobBuilder to create a Job and assign it a label.
Note how we re-use the previously configured label prefix 'tenant:'.