feat(routing): 引入多执行池智能调度
将 Worker 发现、路由画像、容量与执行传输抽象为平台无关接口,新增 Kubernetes 和静态容量适配器,并以 shadow 模式接入生产配置。 实现网络与容量评分、路由防抖、池队列、同步 Worker 租约、一次性执行令牌,以及提交状态不明时禁止重复分配的安全语义。 新增 0105 兼容迁移、管理接口、指标、OpenAPI 和回归测试。已执行全量 Go 测试、go vet、OpenAPI、迁移安全、Compose 与 Kustomize 验证。
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
CREATE TABLE IF NOT EXISTS gateway_execution_pools (
|
||||
pool_id text PRIMARY KEY,
|
||||
labels jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
capabilities jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
state text NOT NULL DEFAULT 'active',
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT gateway_execution_pools_id_check
|
||||
CHECK (pool_id ~ '^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$'),
|
||||
CONSTRAINT gateway_execution_pools_state_check
|
||||
CHECK (state IN ('active', 'draining', 'disabled')),
|
||||
CONSTRAINT gateway_execution_pools_labels_object_check
|
||||
CHECK (jsonb_typeof(labels) = 'object'),
|
||||
CONSTRAINT gateway_execution_pools_capabilities_object_check
|
||||
CHECK (jsonb_typeof(capabilities) = 'object')
|
||||
);
|
||||
|
||||
INSERT INTO gateway_execution_pools (pool_id, labels)
|
||||
VALUES ('legacy-default', '{"migration":"legacy"}'::jsonb)
|
||||
ON CONFLICT (pool_id) DO NOTHING;
|
||||
|
||||
INSERT INTO gateway_execution_pools (pool_id, labels)
|
||||
SELECT DISTINCT site, jsonb_build_object('legacy_site', site)
|
||||
FROM gateway_worker_instances
|
||||
WHERE NULLIF(site, '') IS NOT NULL
|
||||
ON CONFLICT (pool_id) DO NOTHING;
|
||||
|
||||
ALTER TABLE gateway_worker_instances
|
||||
ADD COLUMN pool_id text DEFAULT 'legacy-default',
|
||||
ADD COLUMN worker_id text DEFAULT '',
|
||||
ADD COLUMN endpoint text DEFAULT '',
|
||||
ADD COLUMN orchestrator_instance_ref text DEFAULT '',
|
||||
ADD COLUMN labels jsonb DEFAULT '{}'::jsonb,
|
||||
ADD COLUMN capabilities jsonb DEFAULT '{}'::jsonb,
|
||||
ADD COLUMN protocol_version text DEFAULT 'v1';
|
||||
|
||||
UPDATE gateway_worker_instances
|
||||
SET pool_id = site
|
||||
WHERE NULLIF(site, '') IS NOT NULL
|
||||
AND pool_id = 'legacy-default';
|
||||
|
||||
UPDATE gateway_worker_instances
|
||||
SET worker_id = instance_id
|
||||
WHERE worker_id = '';
|
||||
|
||||
UPDATE gateway_worker_instances
|
||||
SET orchestrator_instance_ref = pod_name
|
||||
WHERE orchestrator_instance_ref = ''
|
||||
AND NULLIF(pod_name, '') IS NOT NULL;
|
||||
|
||||
ALTER TABLE gateway_worker_instances
|
||||
ADD CONSTRAINT gateway_worker_instances_pool_fk
|
||||
FOREIGN KEY (pool_id) REFERENCES gateway_execution_pools(pool_id) ON DELETE RESTRICT,
|
||||
ADD CONSTRAINT gateway_worker_instances_routing_fields_not_null_check
|
||||
CHECK (num_nonnulls(pool_id, worker_id, endpoint, orchestrator_instance_ref, labels, capabilities, protocol_version) = 7) NOT VALID,
|
||||
ADD CONSTRAINT gateway_worker_instances_labels_object_check
|
||||
CHECK (jsonb_typeof(labels) = 'object') NOT VALID,
|
||||
ADD CONSTRAINT gateway_worker_instances_capabilities_object_check
|
||||
CHECK (jsonb_typeof(capabilities) = 'object') NOT VALID;
|
||||
|
||||
ALTER TABLE gateway_worker_instances
|
||||
VALIDATE CONSTRAINT gateway_worker_instances_routing_fields_not_null_check;
|
||||
|
||||
ALTER TABLE gateway_worker_instances
|
||||
VALIDATE CONSTRAINT gateway_worker_instances_labels_object_check;
|
||||
|
||||
ALTER TABLE gateway_worker_instances
|
||||
VALIDATE CONSTRAINT gateway_worker_instances_capabilities_object_check;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_worker_instances_pool_heartbeat
|
||||
ON gateway_worker_instances(pool_id, status, heartbeat_at, instance_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gateway_route_health (
|
||||
pool_id text NOT NULL REFERENCES gateway_execution_pools(pool_id) ON DELETE CASCADE,
|
||||
route_profile_key text NOT NULL,
|
||||
state text NOT NULL DEFAULT 'unknown',
|
||||
success_rate double precision NOT NULL DEFAULT 0,
|
||||
connect_tls_p95_ms bigint NOT NULL DEFAULT 0,
|
||||
first_byte_p95_ms bigint NOT NULL DEFAULT 0,
|
||||
upload_bytes_per_second double precision NOT NULL DEFAULT 0,
|
||||
jitter_p95_ms bigint NOT NULL DEFAULT 0,
|
||||
consecutive_failures integer NOT NULL DEFAULT 0,
|
||||
consecutive_successes integer NOT NULL DEFAULT 0,
|
||||
sample_count integer NOT NULL DEFAULT 0,
|
||||
sampled_at timestamptz NOT NULL,
|
||||
expires_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (pool_id, route_profile_key),
|
||||
CONSTRAINT gateway_route_health_state_check
|
||||
CHECK (state IN ('healthy', 'degraded', 'unreachable', 'unknown')),
|
||||
CONSTRAINT gateway_route_health_values_check
|
||||
CHECK (
|
||||
success_rate >= 0 AND success_rate <= 1
|
||||
AND connect_tls_p95_ms >= 0
|
||||
AND first_byte_p95_ms >= 0
|
||||
AND upload_bytes_per_second >= 0
|
||||
AND jitter_p95_ms >= 0
|
||||
AND consecutive_failures >= 0
|
||||
AND consecutive_successes >= 0
|
||||
AND sample_count >= 0
|
||||
AND expires_at >= sampled_at
|
||||
)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_route_health_fresh
|
||||
ON gateway_route_health(route_profile_key, expires_at, state, pool_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gateway_route_preferences (
|
||||
route_profile_key text PRIMARY KEY,
|
||||
current_pool_id text NOT NULL DEFAULT '',
|
||||
current_since timestamptz,
|
||||
challenger_pool_id text NOT NULL DEFAULT '',
|
||||
challenger_wins integer NOT NULL DEFAULT 0,
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT gateway_route_preferences_wins_check CHECK (challenger_wins >= 0)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gateway_route_probe_requests (
|
||||
route_profile_key text PRIMARY KEY,
|
||||
requested_at timestamptz NOT NULL DEFAULT now(),
|
||||
expires_at timestamptz NOT NULL DEFAULT now() + interval '30 seconds'
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_route_probe_requests_due
|
||||
ON gateway_route_probe_requests(expires_at, requested_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gateway_pool_capacity_desires (
|
||||
pool_id text PRIMARY KEY REFERENCES gateway_execution_pools(pool_id) ON DELETE CASCADE,
|
||||
desired integer NOT NULL,
|
||||
reason text NOT NULL DEFAULT '',
|
||||
valid_until timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT gateway_pool_capacity_desires_value_check CHECK (desired >= 0)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gateway_worker_execution_leases (
|
||||
lease_id uuid PRIMARY KEY,
|
||||
task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE,
|
||||
pool_id text NOT NULL REFERENCES gateway_execution_pools(pool_id) ON DELETE RESTRICT,
|
||||
worker_id text NOT NULL,
|
||||
instance_id text NOT NULL REFERENCES gateway_worker_instances(instance_id) ON DELETE CASCADE,
|
||||
nonce_hash text NOT NULL UNIQUE,
|
||||
state text NOT NULL DEFAULT 'reserved',
|
||||
expires_at timestamptz NOT NULL,
|
||||
released_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT gateway_worker_execution_leases_state_check
|
||||
CHECK (state IN ('reserved', 'running', 'released', 'expired'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_worker_execution_leases_active
|
||||
ON gateway_worker_execution_leases(pool_id, instance_id, expires_at)
|
||||
WHERE released_at IS NULL;
|
||||
|
||||
ALTER TABLE gateway_tasks
|
||||
ADD COLUMN assigned_pool_id text,
|
||||
ADD COLUMN assigned_worker_id text,
|
||||
ADD COLUMN route_profile_key text,
|
||||
ADD COLUMN routing_platform_id uuid,
|
||||
ADD COLUMN routing_platform_model_id uuid,
|
||||
ADD COLUMN routing_version text,
|
||||
ADD COLUMN routing_reason text,
|
||||
ADD COLUMN routing_snapshot jsonb,
|
||||
ADD COLUMN submission_state text DEFAULT 'not_started';
|
||||
|
||||
ALTER TABLE gateway_tasks
|
||||
ADD CONSTRAINT gateway_tasks_assigned_pool_fk
|
||||
FOREIGN KEY (assigned_pool_id) REFERENCES gateway_execution_pools(pool_id) ON DELETE SET NULL,
|
||||
ADD CONSTRAINT gateway_tasks_routing_platform_fk
|
||||
FOREIGN KEY (routing_platform_id) REFERENCES integration_platforms(id) ON DELETE SET NULL,
|
||||
ADD CONSTRAINT gateway_tasks_routing_platform_model_fk
|
||||
FOREIGN KEY (routing_platform_model_id) REFERENCES platform_models(id) ON DELETE SET NULL,
|
||||
ADD CONSTRAINT gateway_tasks_routing_snapshot_object_check
|
||||
CHECK (routing_snapshot IS NULL OR jsonb_typeof(routing_snapshot) = 'object') NOT VALID,
|
||||
ADD CONSTRAINT gateway_tasks_submission_state_not_null_check
|
||||
CHECK (num_nonnulls(submission_state) = 1) NOT VALID,
|
||||
ADD CONSTRAINT gateway_tasks_submission_state_check
|
||||
CHECK (submission_state IN ('not_started', 'submitting', 'submitted', 'submission_confirmation_pending', 'completed')) NOT VALID;
|
||||
|
||||
ALTER TABLE gateway_tasks
|
||||
VALIDATE CONSTRAINT gateway_tasks_submission_state_not_null_check;
|
||||
|
||||
ALTER TABLE gateway_tasks
|
||||
VALIDATE CONSTRAINT gateway_tasks_routing_snapshot_object_check;
|
||||
|
||||
ALTER TABLE gateway_tasks
|
||||
VALIDATE CONSTRAINT gateway_tasks_submission_state_check;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_tasks_assigned_pool_queue
|
||||
ON gateway_tasks(assigned_pool_id, status, next_run_at, priority, created_at)
|
||||
WHERE async_mode = true AND status = 'queued';
|
||||
Reference in New Issue
Block a user