DEV Community

Cover image for Vercel's New waitUntil Utility πŸ•°οΈβœ¨
Matt Lewandowski
Matt Lewandowski

Posted on

Vercel's New waitUntil Utility πŸ•°οΈβœ¨

Vercel just launched their new waitUntil utility, and it has cut my response times in half. My requests have gone from ~90ms to now being ~42ms on average! The waitUntil method allows you to perform asynchronous tasks, after returning the response to the user in Vercels serverless functions.

This is useful for things like:

  1. Logs & Analytics: You can log important information about the request and send analytics data to your preferred tracking service without delaying the response to the user.
  2. Cache Control: If your application relies on caching mechanisms, you can update your cache asynchronously after returning the response. This ensures that the user receives the response quickly while the cache is updated in the background.
  3. Web Sockets: In real-time applications like Kollabe, you might need to publish WebSocket messages on the server. With waitUntil, you can send these messages asynchronously, allowing the user to receive the response immediately while the messages are published in the background.

What exactly does that mean? Let's take a look.

Gif of a user voting on Kollabe

This is code from my route handler for my website Kollabe.



import { waitUntil } from "@vercel/functions";
import { NextResponse } from "next/server";

const postHandler = async (request: Request, data: VoteRequest) => {
  try {
    const vote = await prisma.vote.upsert({
      where: {
        userId_roundId_version: {
          userId: request.session.user.id,
          roundId: data.roundId,
          version: data.version,
        },
      },
      create: {
        submission: data.answer,
        user: { connect: { id: request.session.user.id } },
      },
      include: fullVoteInclude,
    });

    waitUntil(
      pushVote(
        request.session.user.id,
        data.roomId,
        data.roundId,
        [vote]
      ),
    );

    return NextResponse.json({ vote });
  } catch (e) {
    return NextResponse.json({ Message: e.message, status: 500 });
  }
};

export const POST = appRouteAuthWrapper(
  appRoutePayloadWrapper<VoteRequest>(postHandler, voteRequest),
);


Enter fullscreen mode Exit fullscreen mode

This captures users voting on tickets. When a user votes, they call my route handler to create that vote. Kollabe is a real-time app, that utilizes web sockets. That means that after successfully saving the user's vote in my persistence layer, I need to publish that vote to the WebSocket.

My client does not care if this part of the request fails. Their data was saved successfully. Previously, you would have to wait for the Websocket call to finish before returning successfully to the user. If you did not wait, the lifecycle of the request would be complete and you would not push your changes to the WebSocket.



await pushVote(
  req.session.user.id,
  req.body.roomId,
  req.body.roundId,
  [vote],
);


Enter fullscreen mode Exit fullscreen mode

Not anymore! With Vercels waitUntil you can simply wrap the asynchronous function and Vercel will keep the function alive before shutting down.



waitUntil(
  pushVote(
    request.session.user.id,
    data.roomId,
    data.roundId,
    [vote]
  ),
);


Enter fullscreen mode Exit fullscreen mode

This means that the request does not wait for the WebSocket message to publish. It will return successful to the user, while the WebSocket message is published in the background.

A couple of things that are worth noting:

  1. This only works with the App router. Unfortunately, if you use the pages router ( like myself ), you would need to change your routes over to use this. I found it worth it in my situation.
  2. waitUntil will not wait forever. It will inherit the same timeout limits that your functions have.
  3. This is only if you are hosting on Vercel! This is not a NextJS feature, but a Vercel one. You might even need to install @vercel/functions if you aren't already using it.
  4. This is specific to serverless environments.

Top comments (1)

Collapse
 
empz profile image
Emiliano Parizzi

Wondering if this can be used in a Server Component. I'm using a logging library that requires a call to a flush() method (which needs to be awaited).