Early Return
Why & when to early return
Sometimes you need to respond quickly to an incoming HTTP request, and then do other work after sending the response. Some webhooks, like from Slack, require responses within a couple seconds, but you may need more time than that, say, if you're building an AI Slack bot/agent. We recommend accomplishing this today by sending an unawaited HTTP request to a val which does the longer processing.
How to return early, and process after
async function handle(req: Request) {
const new = new URL(req.url)
if (url.path === '/') {
// Send off the relevant data to /process below.
// This `fetch` is not awaited.
fetch(`${req.origin}/process`, {
method: "POST",
body: req.body,
});
// Respond immediately, before the processing is done
return Response.json("ok");
} else if (url.path === '/process) {
// Do the long processing here.
// await it to catch any errors and ensure it completes.
// Nobody is waiting on this request, so we can take as long as we need to.
await doSomeWork(request.body);
return Response.json("done");
}
return new Response("not found", { status: 404 })
}Other serverless platforms support
waitUntil
to handle this case more explicitly. While we don't have a waitUntil function
in our standard library, you can always create one.
Promises should otherwise be awaited
While this is a useful technique, it's important to emphasize that, in general,
you should otherwise await every Promise. If you don't remember to use await
with Promises, errors that occur in promises won't be properly handled and
functions may run out-of-order.
For example, if you use fetch to request some resource, but forget to await
it, then it won't throw errors when it fails, and you won't have the values you
expect to have:
export async function handle() {
try {
// Result will be an opaque Promise, not a useful value.
const result = fetch("https://google.com/");
} catch (e) {
// Errors will never be caught here because
// fetch is not awaited.
handleError(e);
}
}HTTP Lifecycle
When your HTTP file receives a request, we spin up a process to serve it. We
keep that process alive for some time after the response is sent to be ready for
quick follow on requests. After some inactivity with no new requests, your HTTP
process is terminated. This means that if you fire off Promises without awaiting
them, they may or may not finish before the process is killed, depending on how
long they take and whether the process serving the HTTP endpoint is being kept
alive to serve other traffic. The safest path is to await all Promises, or
handle long-running tasks in a new request, as explained above, which keeps the
HTTP process alive until it returns.
Last updated