Cloudflare Workers CPU time vs wall clock for a Sume webhook

A Sume webhook verifier on Workers spends CPU only on the HMAC and body read, not on waiting. See the limits and a WebCrypto verifier.

4 min readSume
All posts

A Cloudflare Worker that receives a Sume webhook is billed against CPU time, not against how long the video took to render, and verifying the signature is a small amount of CPU. The Workers limits page lists CPU time as 10 ms on the Free plan and 5 minutes by default on Paid, and says time spent waiting on fetch, KV or a database does not count as CPU time. So the receiver only needs to read the body, check an HMAC and answer; the slow work belongs elsewhere.

We did not measure the verifier on Workers, so treat the 10 ms figure as a limit to test against, not a promise. The same page says an HTTP request has no enforced wall-clock limit while the client stays connected. The receiving request should still be over in milliseconds. Run wrangler tail on a real delivery and read the CPU time it reports before you rely on the Free plan.

Limits that matter for a receiver

Sume job webhooks arrive as a POST with x-sume-webhook-timestamp and x-sume-webhook-signature: sume-v1=<hex>, signed with HMAC-SHA256 over <timestamp>.<raw_body>. Sume waits up to 10 seconds per attempt and tries up to 10 times, so answer quickly with a 2xx after storing the event. The table collects the Cloudflare numbers that bear on that design.

Workers limits relevant to a webhook receiver (read 2026-10-08)
LimitValueWhy it matters
CPU time, Free10 msKeep verification and storage minimal
CPU time, Paid5 min defaultNot a constraint for an HMAC
Waiting on fetch, KV, DBNot counted as CPUStoring the event is cheap in CPU terms
ctx.waitUntil after responseUp to 30 sShort follow-up work only; use a Queue for more
Subrequests, Free / Paid50 / 10,000One verified event needs few

Steps

  • Store the signing secret as a Worker secret named SUME_COM_WEBHOOK_SIGNING_SECRET; return an error and do nothing when it is missing.
  • Read the body once with request.text(), then verify with WebCrypto against the exact string. Do not parse and re-stringify.
  • Reject a timestamp more than 300 seconds from now, which is the replay tolerance the Sume docs use.
  • Write the event to a Queue or storage and return 204. Dedupe on job_id; a retry sends the same job.
  • Keep polling GET /v1/jobs/{id}/status as a backup for events you never received.

Verifier

crypto.subtle.verify compares in constant time, and the loop accepts either entry in a comma separated signature header, which covers the 24 hour dual-signing window after a secret rotation.

const hex = (s) => Uint8Array.from(s.match(/../g) ?? [], (b) => parseInt(b, 16));

export default {
  async fetch(request, env) {
    if (!env.SUME_COM_WEBHOOK_SIGNING_SECRET) return new Response("no secret", { status: 500 });
    const raw = await request.text();
    const ts = request.headers.get("x-sume-webhook-timestamp") ?? "";
    if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return new Response("stale", { status: 401 });
    const key = await crypto.subtle.importKey(
      "raw", new TextEncoder().encode(env.SUME_COM_WEBHOOK_SIGNING_SECRET),
      { name: "HMAC", hash: "SHA-256" }, false, ["verify"]);
    const sigs = (request.headers.get("x-sume-webhook-signature") ?? "").split(",");
    for (const part of sigs) {
      const sig = part.trim().replace(/^sume-v1=/, "");
      if (await crypto.subtle.verify("HMAC", key, hex(sig), new TextEncoder().encode(`${ts}.${raw}`))) {
        return new Response(null, { status: 204 });
      }
    }
    return new Response("bad signature", { status: 401 });
  },
};
// quick check in Node 18+: sign with the same secret, call worker.fetch(new Request(...), env)

What Sume does not do

Sume does not know which plan your Worker is on and does not adapt deliveries to it. If your handler runs over its CPU budget, the delivery fails and Sume retries on its fixed schedule. The SDK's `verifyWebhook` does the same work if you would rather import it than hand-roll the check.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume