HTTP Endpoints with long running tasks

I’ve recently had to serve some data via an endpoint that relies on a background task because it takes a while to process. Here’s my solution.

It uses two endpoints - one to launch the task and then redirect to a second endpoint which will display the status of that task and the result once it completes.

@anvil.server.background_task
def long_running_task():
    sleep(30)
    anvil.server.task_state["result"] = "Hello World"


@anvil.server.http_endpoint("/task")
def launch_task():
    task = anvil.server.launch_background_task("long_running_task")
    response = anvil.server.HttpResponse(303)
    response.headers["location"] = f"{anvil.server.get_api_origin()}/results?task_id={task.get_id()}"
    return response
  
  
@anvil.server.http_endpoint("/results")
def results(task_id):
    task = anvil.server.get_background_task(task_id)
    status = task.get_termination_status()
    responses = {
        None: {"status": 202, "body": "Your dataset is being generated. Wait a few moments and then refresh this page."},
        "failed": {"status": 500, "body": "An error occurred whilst generating your dataset. Get Owen to have a look."},
        "killed": {"status": 500, "body": "The background task to generate your dataset has been killed. Get Owen to have a look."},
        "missing": {"status": 500,"body": "The background task to generate your dataset is AWOL. Get Owen to have a look"},
        "completed": {"status": 200, "body": task.get_state().get("result", None)}
    }
    return anvil.server.HttpResponse(**responses[status])
3 Likes

Update

I refactored the code for the results endpoint to use proper HTTP responses.

1 Like