#cloudflare-workers#serverless#one-off

“I need to run something later from a Cloudflare Worker but there's no setTimeout that survives”

Schedule a background job from a Cloudflare Worker

Workers can't keep a timer alive past the response. Make one fetch to Fliq with a future scheduled_at and Fliq calls your Worker back on time — no Durable Objects, no Queues.

A Cloudflare Worker’s execution context dies when the response is sent. You can’t hold a timer for 30 minutes, and reaching for Durable Objects just to “call this URL later” is a lot of machinery. Make one fetch to Fliq instead: it stores the fire time and POSTs back to your Worker on schedule.

The request

From inside the Worker, create a job whose url points at a route on the same Worker. Store your Fliq token as a Worker secret (wrangler secret put FLIQ_API_TOKEN).

curl -X POST https://api.fliq.sh/jobs \
  -H "Authorization: Bearer fliq_sk_your_token" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://my-worker.example.workers.dev/api/send-welcome",
    "http_method": "POST",
    "scheduled_at": "2026-06-12T10:30:00Z",
    "headers": { "Content-Type": "application/json" },
    "body": "{\"email\":\"user@example.com\"}",
    "max_retries": 3
  }'
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    if (url.pathname === "/api/signup") {
      // 30 minutes after signup, have Fliq call us back.
      await fetch("https://api.fliq.sh/jobs", {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${env.FLIQ_API_TOKEN}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          url: "https://my-worker.example.workers.dev/api/send-welcome",
          http_method: "POST",
          scheduled_at: new Date(Date.now() + 30 * 60_000).toISOString(),
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ email: "user@example.com" }),
          max_retries: 3,
        }),
      });
      return Response.json({ ok: true });
    }

    if (url.pathname === "/api/send-welcome") {
      const { email } = await request.json();
      // ... send the email ...
      return Response.json({ sent: true });
    }

    return new Response("Not found", { status: 404 });
  },
};

No Durable Objects, no Queues, no wrangler.toml cron triggers — just one outbound fetch.

What Fliq handles for you

  • The timer Workers don’t have. The fire time lives in Fliq’s Postgres, well outside the Worker’s request lifetime, so the callback survives the isolate being torn down.
  • Retries on the callback. If your Worker route is briefly erroring when Fliq calls back, max_retries with backoff covers it.
  • Dynamic schedules. Create, change, or cancel jobs by API at runtime — unlike wrangler.toml cron triggers, which are fixed at deploy and can’t carry a dynamic payload.
  • History. Every callback attempt is recorded, so a misbehaving handler is visible in the dashboard rather than lost in Worker logs.
Add durable timers to your Workers — free during beta