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.
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();
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();
'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));
}
'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
}
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)))
Note how we re-use the previously configured label prefix 'tenant:'.