Job processing
Modal can be used as a scalable job queue to handle asynchronous tasks submitted from a web app or any other Python application. This allows you to offload up to 1 million long-running or resource-intensive tasks to Modal, while your main application remains responsive.
Creating jobs with .spawn()
The basic pattern for using Modal as a job queue involves three key steps:
- Defining and deploying the job processing function using
modal deploy. - Submitting a job using
modal.Function.spawn() - Polling for the job’s result using
modal.FunctionCall.get()
Here’s a simple example that you can run with modal run my_job_queue.py:
In this example:
process_jobis the Modal function that performs the actual job processing. To deploy theprocess_jobfunction on Modal, runmodal deploy my_job_queue.py.submit_jobsubmits a new job by first looking up the deployedprocess_jobfunction, then calling.spawn()with the job data. It returns the unique ID of the spawned function call.get_job_resultattempts to retrieve the result of a previously submitted job usingFunctionCall.from_id()andFunctionCall.get().FunctionCall.get()waits indefinitely by default. It takes an optional timeout argument that specifies the maximum number of seconds to wait, which can be set to 0 to poll for an output immediately. Here, if the job hasn’t completed yet, we return a pending response.- The results of a
.spawn()are accessible viaFunctionCall.get()for up to 7 days after completion. After this period, we return an expired response.
Document OCR Web App is an example that uses this pattern.
Integration with web frameworks
You can easily integrate the job queue pattern with web frameworks like FastAPI.
Here’s an example, assuming that you have already deployed process_job on
Modal with modal deploy as above. This example won’t work if you haven’t
deployed your app yet.
In this example:
- The
/submitendpoint accepts job data, submits a new job usingawait process_job.spawn.aio(), and returns the job’s ID to the client. - The
/result/{call_id}endpoint allows the client to poll for the job’s result using the job ID. If the job hasn’t completed yet, it returns a 202 status code to indicate that the job is still being processed. If the job has expired, it returns a 404 status code to indicate that the job is not found.
You can try this app by serving it with modal serve:
Then interact with its endpoints with curl:
Scaling and reliability
Modal automatically scales the job queue based on the workload, spinning up new instances as needed to process jobs concurrently. It also provides built-in reliability features like automatic retries and timeout handling.
You can customize the behavior of the job queue by configuring the @app.function() decorator with options like retries, timeout, and max_containers.