Files
ai-gateway-go/migrations/000026_scheduled_tasks.sql
T
superidou 9501751792 0.10.1: 安全与业务逻辑加固、新品牌与部署加固
三轮审查修复(60+ 项),相对远端 main(b536672)的关键变更:
- 安全: 数据面 SSRF 拨号防护(防 DNS rebinding)/上游凭据剥离/登录防枚举
  与锁定态统一/可信代理(X-Forwarded-For)限流加固/会话版本失效机制/
  撤销即时传播/弱密钥拒绝启动/脱敏字节级重写(保签名契约)
- 业务逻辑: 裸 body 上传 panic/bootstrap 审计管线卡死/定价通配符优先级/
  全局工具可见性/调度器停机补跑/TOTP 挑战令牌消费顺序/熔断探针语义/
  >4MB 响应 token 计量/管理员重置密码作废会话 等
- 前端: 新 logo(语枢 AI 网关主题)/Provider 凭据异常警示/删除入口/
  后端错误消息透传/localStorage 敏感数据收敛
- 部署: CREDENTIAL_MASTER_KEY 持久化与弱值拒绝/Provider DELETE 接口/
  nginx 安全头/worker 内存限制
- 新增迁移 000029(key_hash 索引)/000030(usage_daily 币种维度)
2026-08-13 10:50:51 +08:00

57 lines
3.0 KiB
SQL

-- M8 P3: PostgreSQL-backed scheduled task definitions and durable execution queue.
CREATE TABLE IF NOT EXISTS gateway.scheduled_tasks (
id uuid PRIMARY KEY,
code text NOT NULL UNIQUE CHECK (code ~ '^[a-z][a-z0-9_-]{1,63}$'),
name text NOT NULL CHECK (length(name) BETWEEN 1 AND 128),
description text NOT NULL DEFAULT '' CHECK (length(description) <= 4000),
cron_expression text NOT NULL CHECK (length(cron_expression) <= 128),
timezone text NOT NULL DEFAULT 'UTC' CHECK (length(timezone) <= 128),
target_type text NOT NULL CHECK (target_type IN ('application', 'digital_employee')),
target_code text NOT NULL CHECK (length(target_code) BETWEEN 1 AND 64),
prompt text NOT NULL CHECK (length(prompt) BETWEEN 1 AND 100000),
variables jsonb NOT NULL DEFAULT '{}'::jsonb CHECK (jsonb_typeof(variables) = 'object'),
skill_ids uuid[] NOT NULL DEFAULT '{}',
mcp_server_ids uuid[] NOT NULL DEFAULT '{}',
conversation_id text NOT NULL DEFAULT '' CHECK (length(conversation_id) <= 128),
notification_channel_id uuid REFERENCES gateway.notification_channels(id) ON DELETE SET NULL,
encrypted_api_key bytea NOT NULL,
api_key_kek_version integer NOT NULL CHECK (api_key_kek_version > 0),
enabled boolean NOT NULL DEFAULT false,
next_run_at timestamptz,
last_run_at timestamptz,
last_status text NOT NULL DEFAULT '' CHECK (last_status IN ('', 'success', 'failed')),
last_error text NOT NULL DEFAULT '' CHECK (length(last_error) <= 4000),
created_by uuid NOT NULL REFERENCES gateway.admin_accounts(id),
revision bigint NOT NULL DEFAULT 1,
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
CHECK ((enabled AND next_run_at IS NOT NULL) OR (NOT enabled))
);
CREATE INDEX IF NOT EXISTS scheduled_tasks_due_idx
ON gateway.scheduled_tasks (next_run_at, id) WHERE enabled;
CREATE TABLE IF NOT EXISTS gateway.scheduled_task_runs (
id uuid PRIMARY KEY,
task_id uuid NOT NULL REFERENCES gateway.scheduled_tasks(id) ON DELETE CASCADE,
trigger_type text NOT NULL CHECK (trigger_type IN ('scheduled', 'manual')),
scheduled_for timestamptz NOT NULL,
status text NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'running', 'success', 'failed')),
attempts integer NOT NULL DEFAULT 0 CHECK (attempts >= 0),
worker_id text NOT NULL DEFAULT '' CHECK (length(worker_id) <= 128),
started_at timestamptz,
finished_at timestamptz,
response jsonb,
error text NOT NULL DEFAULT '' CHECK (length(error) <= 4000),
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
UNIQUE (task_id, trigger_type, scheduled_for)
);
CREATE INDEX IF NOT EXISTS scheduled_task_runs_pending_idx
ON gateway.scheduled_task_runs (created_at, id) WHERE status = 'pending';
CREATE INDEX IF NOT EXISTS scheduled_task_runs_history_idx
ON gateway.scheduled_task_runs (task_id, created_at DESC);
CREATE INDEX IF NOT EXISTS scheduled_task_runs_running_idx
ON gateway.scheduled_task_runs (started_at) WHERE status = 'running';