Workers
Loco provides the following options for background jobs:
- Redis backed (powered by
sidekiq-rs
) - Postgres backed (own implementation)
- SQLite backed (own implementation)
- Tokio-async based (same-process, evented thread based background jobs)
You enqueue and perform jobs without knowledge of the actual background queue implementation, similar to Rails' ActiveJob, so you can switch with a simple change of configuration and no code change.
Async vs Queue
When you generated a new app, you might have selected the default async
configuration for workers. This means workers spin off jobs in Tokio's async pool, which gives you proper background processes in the same running server.
You might want to configure jobs to run in a separate process backed by a queue, in order to distribute the load across servers.
First, switch to BackgroundQueue
:
# Worker Configuration
workers:
# specifies the worker mode. Options:
# - BackgroundQueue - Workers operate asynchronously in the background, processing queued.
# - ForegroundBlocking - Workers operate in the foreground and block until tasks are completed.
# - BackgroundAsync - Workers operate asynchronously in the background, processing tasks with async capabilities.
mode: BackgroundQueue
Then, configure a Redis based queue backend:
queue:
kind: Redis
# Redis connection URI
uri: ""
dangerously_flush: false
Or a Postgres based queue backend:
queue:
kind: Postgres
# Postgres Queue connection URI
uri: ""
dangerously_flush: false
Or a SQLite based queue backend:
queue:
kind: Sqlite
# SQLite Queue connection URI
uri: ""
dangerously_flush: false
Running the worker process
You can run in two ways, depending on which setting you chose for background workers:
Usage: demo_app start [OPTIONS]
Options:
-w, --worker start worker
-s, --server-and-worker start same-process server and worker
Choose --worker
when you configured a real Redis queue and you want a process for doing just background jobs. You can use a single process per server. In this case, you can run your main Web or API server using just cargo loco start
.
Choose -s
when you configured async
background workers, and jobs will execute as part of the current running server process.
For example, running --server-and-worker
:
Creating background jobs in code
To use a worker, we mainly think about adding a job to the queue, so you use
the worker and perform later:
// .. in your controller ..
perform_later
.await
Unlike Rails and Ruby, with Rust you can enjoy strongly typed job arguments which gets serialized and pushed into the queue.
Using shared state from a worker
See How to have global state, but generally you use a single shared state by using something like lazy_static
and then simply refer to it from the worker.
If this state can be serializable, strongly prefer to pass it through the WorkerArgs
.
Creating a new worker
Adding a worker meaning coding the background job logic to take the arguments and perform a job. We also need to let loco
know about it and register it into the global job processor.
Add a worker to workers/
:
And register it in app.rs
:
Generate a Worker
To automatically add a worker using loco generate
, execute the following command:
The worker generator creates a worker file associated with your app and generates a test template file, enabling you to verify your worker.
Configuring Workers
In your config/<environment>.yaml
you can specify the worker mode. BackgroundAsync and BackgroundQueue will process jobs in a non-blocking manner, while ForegroundBlocking will process jobs in a blocking manner.
The main difference between BackgroundAsync and BackgroundQueue is that the latter will use Redis/Postgres/SQLite to store the jobs, while the former does not require Redis/Postgres/SQLite and will use async in memory within the same process.
# Worker Configuration
workers:
# specifies the worker mode. Options:
# - BackgroundQueue - Workers operate asynchronously in the background, processing queued.
# - ForegroundBlocking - Workers operate in the foreground and block until tasks are completed.
# - BackgroundAsync - Workers operate asynchronously in the background, processing tasks with async capabilities.
mode: BackgroundQueue
Manage a Workers From UI
You can manage the jobs queue with the Loco admin job project.
Managing Job Queues via CLI
The job queue management feature provides a powerful and flexible way to handle the lifecycle of jobs in your application. It allows you to cancel, clean up, remove outdated jobs, export job details, and import jobs, ensuring efficient and organized job processing.
Features Overview
- Cancel Jobs
Provides the ability to cancel specific jobs by name, updating their status tocancelled
. This is useful for stopping jobs that are no longer needed, relevant, or if you want to prevent them from being processed when a bug is detected. - Clean Up Jobs
Enables the removal of jobs that have already been completed or cancelled. This helps maintain a clean and efficient job queue by eliminating unnecessary entries. - Purge Outdated Jobs
Allows you to delete jobs based on their age, measured in days. This is particularly useful for maintaining a lean job queue by removing older, irrelevant jobs.
Note: You can use the--dump
option to export job details to a file, manually modify the job parameters in the exported file, and then use theimport
feature to reintroduce the updated jobs into the system. - Export Job Details
Supports exporting the details of all jobs to a specified location in file format. This feature is valuable for backups, audits, or further analysis. - Import Jobs
Facilitates importing jobs from external files, making it easy to restore or add new jobs to the system. This ensures seamless integration of external job data into your application's workflow.
To access the job management commands, use the following CLI structure:
)
Testing a Worker
You can easily test your worker background jobs using Loco
. Ensure that your worker is set to the ForegroundBlocking
mode, which blocks the job, ensuring it runs synchronously. When testing the worker, the test will wait until your worker is completed, allowing you to verify if the worker accomplished its intended tasks.
It's recommended to implement tests in the tests/workers
directory to consolidate all your worker tests in one place.
Additionally, you can leverage the worker generator, which automatically creates tests, saving you time on configuring tests in the library.
Here's an example of how the test should be structured:
use *;
async