← Back to Patterns

Cloud Run request timeouts don't kill your code (so your architecture has to)

A Cloud Run request timeout ends the request, not necessarily the work. If the operation can outlive its caller, the system needs explicit job semantics instead of hope.

By Ivan Richter LinkedIn

Last updated: Sep 1, 2026

4 min read

On this page

A Cloud Run request timeout closes the connection and returns a 504. It doesn’t terminate the container instance, and the code may continue processing after the caller has been told the request failed. The timeout is therefore a transport deadline, not an execution boundary.

If correctness depends on work stopping when the response window ends, the architecture is relying on a guarantee Cloud Run doesn’t provide.

The failure is ambiguous by default

Consider a handler that writes a record, calls an external API, and then updates status. The request times out after the external call but before the final update.

The caller sees failure and retries. The first invocation may still be running. The external system may have accepted the operation. The application now has two executions and no transport-level evidence that says which side effect happened.

A longer timeout reduces how often this exact sequence occurs. It doesn’t remove it. Clients disconnect, proxies have their own deadlines, networks fail, and long Cloud Run requests are more likely to need reconnection and retry handling.

A 504 must therefore mean only one thing: the caller didn’t receive a response in time. It says nothing reliable about domain completion.

Keep bounded request work inside the request

Synchronous execution is appropriate when the operation is short, its side effects can be committed atomically or idempotently, and the caller genuinely needs the result before proceeding.

Use an application deadline shorter than the Cloud Run deadline. Pass cancellation or remaining-time signals through database and HTTP clients. Stop starting new work when there isn’t enough time to finish it safely. Roll back transactions and return a classified error while the platform can still deliver it.

This doesn’t make cancellation perfect. It makes the handler cooperate with a known deadline instead of discovering it when the connection disappears.

The request path should have an explicit answer for:

  • the maximum expected execution time
  • which calls receive shorter child deadlines
  • what can be retried safely
  • which side effects use idempotency keys
  • what state remains when the caller disconnects

If those answers are vague, increasing timeoutSeconds only extends the period of ambiguity.

Move durable work behind acceptance

When work can outlive the caller, persist the intent and give execution another owner.

The request validates input, creates a job or command with a stable idempotency key, and returns an identifier. A queue, Cloud Tasks target, workflow, Cloud Run job, or another worker processes the operation. The client reads status or receives a callback later.

The durable record needs real states such as pending, running, succeeded, failed, cancelled, and retryable. Store the external operation identifiers needed to reconcile ambiguous responses. A worker retry should continue or deduplicate the same command, not create another interpretation of the user’s intent.

This split also makes timeouts easier to classify. The acceptance request either persisted the command or it didn’t. The worker has its own execution deadline and retry policy. Neither layer infers completion from whether an HTTP client remained connected.

Idempotency covers both client and platform retries

Generate the idempotency key at the boundary where business intent becomes durable. Reusing a request ID generated inside each attempt is useless. Every retry will look new.

Enforce uniqueness where the side effect begins. For a payment, message, export, or external write, store the key and result before returning success. When the downstream API supports idempotency, pass the same key through. When it doesn’t, use a local state machine and reconciliation rather than pretending exactly-once delivery appeared through optimism.

Timeouts are only one source of duplicate attempts. Deployments, worker crashes, task retries, and operators produce the same requirement.

Observe execution separately from response delivery

Log the request ID, command or job ID, idempotency key, deadline, side effects attempted, external identifiers, and terminal state. Metrics should distinguish:

  • requests that reached their deadline
  • commands accepted but still running
  • worker retries
  • ambiguous downstream outcomes
  • completed work whose original response was lost

Without that separation, a timeout graph becomes a poor proxy for business state.

Choose who owns the work

Keep work in a Cloud Run request when it is naturally request-shaped and can remain correct if the caller retries. Use a durable execution model when the operation needs to survive disconnection, run longer than the response contract, or coordinate side effects that require reconciliation.

Cloud Run defines what its request timeout means. The architecture has to be equally precise about who owns the work after the request ends.

More in this domain: Infrastructure

Browse all

Related patterns