Supabase 自部署 Edge Functions 超时从 60s 延长到 360s 完整复盘

背景

在自部署 Supabase 环境中,Edge Functions 默认超时时间为 60 秒 。业务场景需要一个耗时较长的函数(约 350 秒),因此需要将超时延长至 360 秒。

自部署 Supabase 的 Edge Functions 超时涉及多个层级,任何一层配置不正确都会导致请求被提前切断。本文记录了完整的排查过程和最终解决方案。

一、问题现象

创建一个测试函数 slow-test,等待 90 秒后返回:

javascript 复制代码
Deno.serve(async (req: Request) => {
  const startTime = Date.now();
  console.log("[slow-test] 函数开始执行,时间戳: " + startTime);
  await new Promise((resolve) => setTimeout(resolve, 90000));
  const duration = (Date.now() - startTime) / 1000;
  console.log("[slow-test] 等待结束,实际耗时: " + duration + " 秒");
  return new Response(JSON.stringify({ message: "成功执行了 " + duration + " 秒" }), {
    headers: { "Content-Type": "application/json" },
  });
});

现象:函数在约 60 秒时被强制终止,日志显示:

vbscript 复制代码
wall clock duration warning: isolate: xxx
wall clock duration reached: isolate: xxx (in_flight_req_exists = true)
failed to send request to user worker: request has been cancelled by supervisor
user worker failed to respond: request has been cancelled by supervisor

二、超时链路分析

Supabase Edge Functions 的请求链路涉及三个独立层级,每个层级都有自己的超时限制:

java 复制代码
客户端 → Kong 网关 → Edge Runtime (Worker) → 用户函数
         ↓              ↓
    read_timeout    workerTimeoutMs
层级 配置位置 默认值 作用
Kong 网关 kong.yml 中 functions-v1.read_timeout 150000ms (150s) 网关等待上游响应的时长
Edge Runtime 参数 docker-compose.yml 命令行参数 60s Worker 空闲超时
Edge Runtime 硬编码 main/index.ts 中 workerTimeoutMs 60s 最终生效的硬上限
环境变量 docker-compose.yml 环境变量 --- 辅助配置,可能被覆盖

关键原则 :main/index.ts 中的 workerTimeoutMs 是最终生效的硬编码值,优先级高于环境变量和命令行参数。

三、完整解决方案

3.1 修改 main/index.ts(核心)

这是最关键的一步,Edge Runtime 内部的硬编码超时值优先于所有环境变量和命令行参数。

找到 volumes/functions/main/index.ts,修改 workerTimeoutMs:

arduino 复制代码
// 修改前
const workerTimeoutMs = 60 * 1000; // 60秒


// 修改后
const workerTimeoutMs = 360 * 1000; // 360秒

3.2 修改 kong.yml

找到 volumes/api/kong.yml 中的 functions-v1 服务,修改超时配置:

yaml 复制代码
- name: functions-v1
  _comment: 'Edge Functions: /functions/v1/* -> http://functions:9000/*'
  url: http://functions:9000/
  read_timeout: 370000      # 从 150000 改为 370000(370秒)
  write_timeout: 370000     # 新增
  connect_timeout: 30000    # 新增
  routes:
    - name: functions-v1-all
      strip_path: true
      paths:
        - /functions/v1/
  plugins:
    - name: cors

注意 :Kong 的超时单位是毫秒。370000 表示 370 秒,比 Edge Runtime 的 360 秒多 10 秒缓冲,避免边界问题。

3.3 修改 docker-compose.yml

kong 服务 --- 环境变量:

yaml 复制代码
kong:
  environment:
    # ... 已有配置 ...
    KONG_NGINX_PROXY_PROXY_READ_TIMEOUT: "370s"
    KONG_NGINX_PROXY_PROXY_SEND_TIMEOUT: "370s"
    KONG_NGINX_PROXY_PROXY_CONNECT_TIMEOUT: "30s"

functions 服务 --- 环境变量与启动命令:

bash 复制代码
functions:
  environment:
    # ... 已有配置 ...
    FUNCTIONS_WORKER_TIMEOUT_MS: "360000"
    EDGE_RUNTIME_WORKER_TIMEOUT_MS: "360000"
  command:
    [
      "start",
      "--main-service",
      "/home/deno/functions/main",
      "--user-worker-request-idle-timeout",
      "360000",
      "--request-read-timeout",
      "360000",
      "--request-wait-timeout",
      "360000"
    ]

顶层 volumes --- 补充 deno-cache :

yaml 复制代码
volumes:
  db-config:
  deno-cache:          # 确保这一行存在
  supabase_db_data:

四、配置层级总结

层级 配置文件 配置项 值
Kong 网关 kong.yml functions-v1.read_timeout 370000ms
Kong 网关(兜底) docker-compose.yml (kong) KONG_NGINX_PROXY_PROXY_READ_TIMEOUT 370s
Edge Runtime 参数 docker-compose.yml (functions) --user-worker-request-idle-timeout 360000ms
Edge Runtime 环境变量 docker-compose.yml (functions) FUNCTIONS_WORKER_TIMEOUT_MS 360000
Edge Runtime 硬编码 main/index.ts workerTimeoutMs 360 * 1000

必须形成的关系:Kong(370s) > Edge Runtime(360s) > 实际需求

五、验证测试

5.1 测试函数

javascript 复制代码
// volumes/functions/slow-test/index.ts
Deno.serve(async (req: Request) => {
  const startTime = Date.now();
  console.log("[slow-test] 函数开始执行,时间戳: " + startTime);


  const waitSeconds = 350; // 测试值
  console.log("[slow-test] 开始等待 " + waitSeconds + " 秒...");


  await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));


  const duration = (Date.now() - startTime) / 1000;
  console.log("[slow-test] 等待结束,实际耗时: " + duration + " 秒");


  return new Response(
    JSON.stringify({
      message: "成功执行了 " + duration + " 秒的操作",
      durationSeconds: duration,
    }),
    { status: 200, headers: { "Content-Type": "application/json" } }
  );
});

5.2 触发测试

bash 复制代码
ANON_KEY=$(grep ANON_KEY .env | cut -d '=' -f2)


curl -X POST "http://127.0.0.1:8000/functions/v1/slow-test" \
  -H "Authorization: Bearer ${ANON_KEY}" \
  -H "Content-Type: application/json"

5.3 成功日志

css 复制代码
[Info] [slow-test] 开始等待 350 秒...
[Info] [slow-test] 等待结束,实际耗时: 349.986 秒

5.4 验证命令

perl 复制代码
# 确认 Kong 环境变量
docker exec -it supabase-kong env | grep -iE "PROXY_READ|PROXY_SEND|PROXY_CONNECT"


# 确认 Edge Runtime 启动参数
docker inspect supabase-edge-functions --format '{{.Config.Cmd}}'


# 确认 main/index.ts 中的超时值
grep -n "workerTimeoutMs" ./volumes/functions/main/index.ts


# 确认 kong.yml 中的超时值
grep -n "read_timeout" ./volumes/api/kong.yml

六、踩坑记录

坑 1:只改环境变量不生效

原因:main/index.ts 中的 workerTimeoutMs 是硬编码值,优先级高于环境变量。

解决:必须修改 main/index.ts 中的 workerTimeoutMs。

坑 2:Kong 返回 The upstream server is timing out

原因 :kong.yml 中 functions-v1 服务的 read_timeout 是 150000(150秒),服务级配置优先级高于环境变量。

解决:修改 kong.yml 中的 read_timeout 为 370000。

坑 3:开发环境配置不生效

原因 :开发环境使用了独立的 main/index.ts 文件,其 workerTimeoutMs 仍然是默认的 60 秒。

解决:每个环境都需要单独修改对应的 main/index.ts 文件。

坑 4:参数传递正确但仍不生效

原因:参数虽然被正确传递到容器(通过 docker inspect 确认),但 Edge Runtime 版本可能不识别这些参数。

解决:确认 Edge Runtime 版本兼容性,并确保 main/index.ts 中的硬编码值已修改。

七、注意事项

7.1 CPU 时间限制仍然存在

即使墙上时钟延长到 360 秒,CPU 执行时间限制仍然是 2 秒。纯 setTimeout 等待(I/O 密集型)不受影响,但计算密集型任务仍会在 2 秒左右被终止。

7.2 请求空闲超时

请求空闲超时(Request Idle Timeout)默认是 150 秒。如果函数在 150 秒内没有发出响应,平台仍会返回 504 错误。

7.3 最大支持 400 秒

自部署 Supabase 的 Edge Functions 墙上时钟上限最大可配置为 400 秒。如需延长到 400 秒,将所有相关值从 360000 改为 400000,Kong 的 read_timeout 改为 410000 即可。

7.4 重启方式

修改配置后必须完全停止并重建,不能用 restart:

bash 复制代码
docker compose down kong functions
docker compose up -d kong functions

八、总结

问题 解决方案
默认 60 秒超时 修改 main/index.ts 中的 workerTimeoutMs
Kong 150 秒切断 修改 kong.yml 中 functions-v1.read_timeout
环境变量不生效 硬编码值优先级最高,必须改代码
开发环境独立配置 每个环境单独修改 main/index.ts

核心结论 :Supabase Edge Functions 超时配置需要三层对齐,其中 main/index.ts 中的 workerTimeoutMs 是最终生效的硬编码值,是最关键的配置项。

相关推荐
程序员-Benothing11 分钟前
Vim编辑器从入门到精通:模式、快捷键、配置、插件
linux·运维·服务器
m0_6464299720 分钟前
Docker 完整核心知识点总结(超通俗易懂版)
运维·docker·容器
亚川楼宇自控系统数据中心厂家42 分钟前
IBMS 集成管理系统:如何打通楼宇自控实现建筑一体化管控
运维
迪康Defender1 小时前
终端安全审批体系设计:如何平衡安全管控与业务连续性
运维·服务器·安全·运维开发·学习方法·业界资讯·远程工作
luo_guibin2 小时前
Linux系统下OpenSSL升级全流程,新旧版本切换
linux·运维·服务器
7177772 小时前
支持混合云的 DevOps 平台有哪些:主流方案对比与选型指南
运维·devops
看着博客敲代码3 小时前
No space left on device:服务器被 SSH 爆破到日志写满的完整排查与止血
linux·运维·服务器·安全·ssh
编程序的员3 小时前
使用OpenTelemetry来监控Rust应用
运维·rust·monitoring·opentelemetry
实战派K8S&DB3 小时前
TDSQL 核心模块与进程体系
运维·数据库·分布式·sql·mysql
Rooting++3 小时前
用友打包的APP壳子怎么获取SHA1码?
运维·服务器