Skip to content

Resumable functions

Any async function wrapped with a @dispatch.function decorator becomes a resumable function. This means that every await statement becomes a checkpoint in the execution of that function. When an exception is raised, Dispatch will retry execution of the entire function from the last successful checkpoint.

For example, if function has three await statements and the last one raised an exception, the next time that function is executed, it will restore the return values of the first two await statements and will only re-run the third.

Consider this example application that implements a checkout flow. When user purchases a product, application charges the credit card, marks the order as completed and sends an email confirmation.

from fastapi import FastAPI
from dispatch.fastapi import Dispatch
app = FastAPI()
dispatch = Dispatch(app)
@dispatch.function
async def charge_credit_card(user_id):
# Charge the credit card via Stripe, for example
# Return receipt ID afterwards
return "receipt_789"
@dispatch.function
async def send_email_confirmation(user_id, order_id, receipt_id):
# Send an email with order details
pass
@dispatch.function
async def mark_order_as_completed(order_id):
# Update order in the database
pass
@dispatch.function
async def checkout(user_id, order_id):
# Checkpoint 1
receipt_id = await charge_credit_card(user_id)
# Checkpoint 2
await send_email_confirmation(user_id, order_id, receipt_id)
# Checkpoint 3
await mark_order_as_completed(order_id)
@app.post("/buy")
async def buy():
user_id = "user_123"
order_id = "order_456"
await checkout.dispatch(user_id, order_id)

If send_email_confirmation raises an exception, checkout function will be executed again, but it won’t execute charge_credit_card again. Instead, Dispatch restores receipt_id from the previous execution and runs send_email_confirmation right away. No need to worry about charging user’s credit card twice.

Dispatch makes checkout function resumable, meaning that it picks up execution where it left off. This includes any other async functions that checkout calls, as long as they’re also wrapped with a @dispatch.function decorator.

This powerful mechanism is so simple to integrate and yet it offers incredible value — Dispatch ensures that resumable functions always run to completion, no matter what failures it encounters.