Inquir Compute · platform limits

When serverless timeout limits block slow work

Every serverless platform caps how long a function can run. Those limits are sensible for HTTP handlers but painful for slow background work: large file processing, bulk API sync, multi-model inference pipelines. The escape hatch is not a longer timeout—it is separating HTTP acceptance from async execution, then chaining pipeline steps that each fit within a step's budget.

Last updated: 2026-06-28

Direct answer

When serverless timeout limits block slow work. Inquir separates HTTP acceptance from async execution. The HTTP handler validates input, enqueues a durable background job, and returns 202 immediately—it completes well within any platform timeout. The job then runs outside the HTTP window with its own timeout budget (5 s by default, configurable up to 24 hours per step), and the queue retries failed steps with backoff.

When it fits

  • Work that consistently takes longer than your HTTP platform timeout
  • You are hitting Vercel's 60s, Lambda's 900s, or Workers' 30s CPU limit on background jobs that snuck into HTTP handlers

Tradeoffs

  • Raising the timeout is a temporary fix, not an architectural one. The work still runs inside a single execution context with one failure domain—a crash at minute 14 of a 15-minute Lambda restarts the whole 15 minutes.
  • Recursive invocations (calling yourself to "continue" work) lose context across calls, risk double-writing on failure, and are invisible to any observability tool that expects a single execution trace per job.

Real timeout limits across common serverless platforms

  • Vercel Serverless Functions: 60s (Pro), 300s (Enterprise)
  • AWS Lambda: 900s (15 min) maximum
  • Cloudflare Workers: 30s CPU time (Bundled plan)
  • Supabase Edge Functions: 60s

These limits exist for good reasons—serverless functions are designed for fast, stateless HTTP handlers. The problem is when teams try to run background work through the same function execution path: CSV processing, bulk record sync, multi-step ML pipelines, or nightly data archival.

Why workarounds fall apart

Raising the timeout is a temporary fix, not an architectural one. The work still runs inside a single execution context with one failure domain—a crash at minute 14 of a 15-minute Lambda restarts the whole 15 minutes.

Recursive invocations (calling yourself to "continue" work) lose context across calls, risk double-writing on failure, and are invisible to any observability tool that expects a single execution trace per job.

Pipeline chaining as the escape hatch from platform timeout limits

Inquir separates HTTP acceptance from async execution. The HTTP handler validates input, enqueues a durable background job, and returns 202 immediately—it completes well within any platform timeout. The job then runs outside the HTTP window with its own timeout budget (5 s by default, configurable up to 24 hours per step), and the queue retries failed steps with backoff.

For work that runs for hours, decompose it into multiple steps—each step leaves a checkpoint, a failure re-runs one step, and the pipeline sequences them. See the multi-step pipeline architecture page for fan-out, merge, and per-step retry patterns.

Serverless platform timeout comparison

HTTP function limits for common platforms, and how Inquir pipeline steps compare.

Serverless platform timeout comparison
PlatformHTTP function limitBackground / async path
Vercel60s (Pro) / 300s (Enterprise)No built-in background execution
AWS Lambda900s (15 min) maxAsync invoke still caps at 900s
Cloudflare Workers30s CPU time (Bundled)60s with paid Unbound plan
Supabase Edge Functions60sNo built-in pipeline execution
Inquir (HTTP handler)5 s default / configurable up to 24 h
Inquir (pipeline step)Own timeout per step (5 s default, up to 24 h); chain steps for checkpoints

What pipeline-backed execution enables

Work that outlasts HTTP timeout limits

HTTP handler returns 202 in milliseconds. Pipeline step runs the slow work with its own timeout—no shared execution context with the HTTP path.

Per-step failure isolation

A failure in step 3 of 5 does not restart steps 1 and 2. Only the failed step retries, with its own retry count and backoff policy.

Status polling and callbacks

Return a jobId from the 202 response. Client polls a status endpoint or receives a webhook callback when the pipeline completes.

Multi-step composition for very long work

Chain steps for checkpoints, not because of a cap: each step has its own timeout (5 s default, up to 24 h), so a 4-step pipeline re-runs one step after a failure instead of the whole hour.

Pattern: HTTP accepts, pipeline runs

1

HTTP handler validates and triggers

Parse input, validate, enqueue a durable background job, return 202 with a jobId. This completes in well under any HTTP platform timeout.

2

Pipeline step does the slow work

The step runs outside the HTTP window with its own timeout budget (5 s default, up to 24 h). Chain steps for checkpoints when work spans hours, not because of a cap: work that exceeds a single step budget.

3

Client polls or receives callback

Use the jobId to poll a status endpoint, or have the final pipeline step POST a webhook to the client when complete.

HTTP → pipeline handoff: escape the timeout

The HTTP handler returns 202 immediately—it never approaches the platform timeout. The pipeline step runs the slow work outside the HTTP window.

api/start-csv-import.mjs (HTTP handler)
export async function handler(event) {
  const { fileUrl } = JSON.parse(event.body || '{}');
  if (!fileUrl) return { statusCode: 400, body: JSON.stringify({ error: 'fileUrl required' }) };
  // Returns in <100ms — well inside Vercel 60s, Lambda 900s, or any other platform limit
  const { jobId } = await global.jobs.enqueue('import-csv', { fileUrl });
  return { statusCode: 202, body: JSON.stringify({ jobId, status: 'started' }) };
}
jobs/import-csv.mjs (pipeline step — outside HTTP window)
export async function handler(event) {
  // Runs outside the HTTP window with its own timeout budget (up to 24 h)
  const { fileUrl } = event.payload ?? {};
  const rows = await downloadAndParseCSV(fileUrl);   // may take several minutes for large files
  for (const batch of chunk(rows, 500)) {
    await db.upsertBatch(batch);                      // idempotent by row ID
  }
  return { imported: rows.length, fileUrl };
}

When the HTTP→pipeline pattern applies

When this works

  • Work that consistently takes longer than your HTTP platform timeout
  • You are hitting Vercel's 60s, Lambda's 900s, or Workers' 30s CPU limit on background jobs that snuck into HTTP handlers

When to skip it

  • Work that completes in under 10 seconds—keep it synchronous in the HTTP handler for simpler debugging

FAQ

Is a pipeline step truly unlimited in time?

No. Each pipeline step has a configurable timeout: 5,000 ms by default, up to 24 hours (86,400,000 ms) on the platform default limits. That is far longer than any HTTP function timeout, but chain steps anyway when work spans hours: each step leaves a checkpoint and a failure re-runs one step. For work longer than a step budget, chain multiple steps—see the long-running serverless jobs page for multi-step decomposition.

How does this differ from raising the Lambda timeout to 900s?

Lambda caps the entire execution at 900s in one execution context. Inquir chains steps, each with its own timeout budget (up to 24 hours) and independent retry. A crash at minute 14 of one step does not restart a prior step that already completed.

What if the client needs a synchronous result?

For synchronous results, the client must poll a status endpoint using the jobId, or you configure the final pipeline step to POST a callback to the client. True synchronous long-running work is fundamentally incompatible with serverless HTTP timeouts on any platform.