基于 pg_cron 的轻量 HTTP 服务:将 PostgreSQL 内置定时任务封装为 REST API,并提供用于联调的静态页面。
- 列出
cron.job中的任务 - 列出最近
cron.job_run_details运行记录(与文档中 Monitoring jobs 一致) cron.schedule:两参数或三参数(命名任务),见POST /api/jobscron.schedule_in_database:在指定库中登记任务,见POST /api/jobs/in-databasecron.unschedule:按 job_id 或 job_name 删除,见DELETE /api/jobs/{id}与DELETE /api/jobs/by-name/{name}cron.alter_job:按需更新 schedule / command / database / username / active,见PATCH /api/jobs/{id}- 定时发起 HTTP 请求(与 Supabase pg_net 相同思路):
POST /api/jobs/http会登记一条 pg_cron 任务,命令为net.http_get/net.http_post GET /api/health用于探活(不访问数据库)
- Go 1.22 或更高版本(本地运行)
- 已启用 pg_cron 的 PostgreSQL(Docker Compose 会一并构建带扩展的数据库镜像)
数据库侧需允许加载 pg_cron(例如 shared_preload_libraries 包含 pg_cron,并设置 cron.database_name)。Compose 中的 db 服务已配置这些参数。
| 环境变量 | 说明 | 默认 |
|---|---|---|
DATABASE_URL |
PostgreSQL 连接串 | postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable |
HTTP_ADDR |
监听地址 | :8080 |
go run .浏览器访问:http://127.0.0.1:8080/index.html。
确保数据库已执行:
CREATE EXTENSION IF NOT EXISTS pg_cron;且实例配置与 pg_cron 文档 一致(shared_preload_libraries、cron.database_name 等)。
若使用 HTTP 定时请求(POST /api/jobs/http),还需安装并启用 pg_net,例如:
CREATE EXTENSION IF NOT EXISTS pg_net;(若不走本仓库的 Docker 示例,请以 pg_net 发行说明为准。本仓库自带的 docker/postgres 镜像已编译安装 pg_net。)
在项目根目录:
docker compose up --build默认构建使用 AWS Public ECR 上的 docker/library 同步镜像(postgres:16-bookworm、golang:1.22-bookworm),减轻从 docker.io 拉取时的超时问题。若能稳定访问 Docker Hub,可在项目根目录 .env 中设置:
POSTGRES_IMAGE=postgres:16-bookwormGOLANG_IMAGE=golang:1.22-bookworm
或使用国内/自建 registry 的完整镜像名后执行 docker compose up --build。
- 应用:http://127.0.0.1:8080/index.html
- PostgreSQL:
localhost:5432,用户postgres/ 密码postgres,数据库postgres
数据卷 pgdata 持久化数据库文件。首次初始化时:
docker/postgres/init-pgcron.sql:创建 pg_crondocker/postgres/init-pgnet.sql:创建 pg_net(镜像内已从 supabase/pg_net 源码编译安装)
db 服务的启动参数已设置 shared_preload_libraries=pg_cron,pg_net(pg_net 文档要求预加载)。若曾用旧 Compose 建过卷且未预加载 pg_net,请 docker compose down -v 后重建数据目录,或自行在 postgresql.conf 中调整并重启。
构建 db 镜像会从 Debian 与 GitHub 拉取大量包(含编译 pg_net 所需依赖)。若出现 502 Bad Gateway / Connection failed(多见于 deb.debian.org),可在项目根 .env 中设置 APT_DEBIAN_HOST(仅主机名),例如 mirrors.aliyun.com 或 mirrors.tuna.tsinghua.edu.cn,再执行 docker compose build --no-cache db。Dockerfile 内已对 apt/curl 做了多次重试与超时配置。
停止并删除容器(保留卷):
docker compose down同时删除数据卷:
docker compose down -v与 pg_cron README 中 cron.schedule / schedule_in_database / unschedule / alter_job 语义对齐。
| 方法 | 路径 | 对应扩展能力 |
|---|---|---|
GET |
/api/health |
存活检查 |
GET |
/api/jobs |
查询 cron.job |
GET |
/api/jobs/run-details?limit=50 |
查询 cron.job_run_details,limit 默认 50、最大 500 |
POST |
/api/jobs |
cron.schedule(schedule, command) 或 cron.schedule(job_name, schedule, command) |
POST |
/api/jobs/in-database |
cron.schedule_in_database(...) |
POST |
/api/jobs/http |
生成 net.http_get / net.http_post 作为 cron.schedule 的命令(需 pg_net);可选 database + job_name 走 schedule_in_database |
PATCH |
/api/jobs/{id} |
cron.alter_job(job_id, ...),Body 中字段均可选 |
DELETE |
/api/jobs/{id} |
cron.unschedule(job_id bigint) |
DELETE |
/api/jobs/by-name/{name} |
cron.unschedule(job_name text),name 需 URL 编码 |
POST /api/jobs 示例:
{
"job_name": "demo_every_minute",
"schedule": "* * * * *",
"command": "SELECT 1"
}POST /api/jobs/in-database 示例:
{
"job_name": "delete_old_data",
"schedule": "30 3 * * 6",
"command": "DELETE FROM events WHERE event_time < now() - interval '1 week'",
"database": "some_other_database",
"username": null,
"active": true
}PATCH /api/jobs/42 示例(仅改调度与命令,与文档 Altering a cron job 一致):
{
"schedule": "0 10 * * *",
"command": "VACUUM",
"active": false
}POST /api/jobs/http 示例(每分钟 GET 外部地址):
{
"job_name": "ping_httpbin",
"schedule": "* * * * *",
"method": "GET",
"url": "https://httpbin.org/get",
"headers": {},
"params": { "foo": "bar" },
"timeout_ms": 8000
}POST JSON 体调用 Webhook:
{
"schedule": "*/5 * * * *",
"method": "POST",
"url": "https://example.com/hook",
"headers": { "Content-Type": "application/json" },
"body": { "source": "pg_cron" }
}command 字段会直接作为 pg_cron 任务在数据库中执行 SQL。请勿将未鉴权的实例暴露到公网;生产环境应配合认证、网络隔离与最小权限数据库用户。
HTTP 任务由数据库内的 pg_net 发出出站请求,存在 SSRF 风险;应对 URL、网段与凭据做约束,勿让不可信用户任意指定内网地址。