Edge Function takes too long or times out
Why a SupaHost Edge Function times out, what the 150-second response limit means, and patterns for long work: timeouts on calls, batching, queues and scheduled functions.
What you see
A function call hangs and then fails. Depending on where you look:
HTTP/2 504
sb-error-code: IDLE_TIMEOUT
or, in the dashboard's Test a function panel, the test gives up after about a minute with no response.
Why it happens
On SupaHost, each request must start responding within 150 seconds. If your handler hasn't returned a response by then, the runtime ends it with 504 IDLE_TIMEOUT. Separately, a worker has an overall lifetime cap, so a function is not a place for work that runs for many minutes.
The Test panel in the dashboard has its own, shorter 60-second timeout. A function that takes 90 seconds works when your app calls it, but the Test panel reports a timeout. That's the panel, not the function.
Slow functions are usually waiting, not computing: on an external API, a large database query, or a loop of sequential calls.
How to fix it
Find the slow step. Add timing logs and read them in Dashboard → your project → Functions tab → Logs card:
const t0 = performance.now() const rates = await fetch('https://api.example.com/rates', { signal: AbortSignal.timeout(15_000), // fail fast instead of hanging }) console.log('rates fetched in', Math.round(performance.now() - t0), 'ms')Each request also gets a log line with its total duration.
Run independent calls in parallel. Ten sequential 5-second calls take 50 seconds; in parallel they take about 5:
const results = await Promise.all( invoiceIds.map((id) => fetch(`https://api.example.com/invoices/${id}`)) )Keep the batch size reasonable so you don't hit the other API's rate limit.
Move the heavy query into the database. An index or an RPC that aggregates in SQL is usually far faster than pulling rows into the function. See Query performance and EXPLAIN.
Turn one long job into many short ones. Have the request enqueue work and return right away, then let a scheduled function process the queue in small batches:
-- every minute, ask the worker function to process the next batch select cron.schedule( 'process-report-queue', '* * * * *', $$ select net.http_post( url := 'https://app-one.acme.supahost.space/functions/v1/report-worker', headers := jsonb_build_object( 'Authorization', 'Bearer ' || (select decrypted_secret from vault.decrypted_secrets where name = 'service_role_key'), 'Content-Type', 'application/json'), body := '{}'::jsonb ) $$ );This assumes you saved the key in Vault as
service_role_key. See Queues with pgmq and Running functions on a schedule.Tell the user it's in progress. For a long report, return
202 Acceptedwith a job id, and let the client poll a table or listen on a Realtime channel for the result.
On SupaHost
The 150-second response limit and 150 MB memory per worker are fixed. SupaHost doesn't charge per invocation, so splitting one big job into many small calls doesn't cost more.