feat(queue): 增加非文本模型分布式准入队列

使用 PostgreSQL 统一同步与异步非文本任务的并发准入、持久化等待和 Worker 容量分配,并将生产 API 与独立 Worker 角色拆分。

补充策略管理、共享契约、OpenAPI、Kubernetes 双节点 Worker 清单及跨节点验收脚本;未默认启用任何生产 queue_size 策略。

已在原基线完成 Go、前端、迁移、Shell、Kustomize 与长任务容量验收;合入最新主干后将重新执行发布门禁。
This commit is contained in:
2026-07-29 16:15:43 +08:00
parent 2e5a90731b
commit 9e4fc7362d
55 changed files with 4565 additions and 237 deletions
+27 -5
View File
@@ -76,7 +76,11 @@ var (
)
func Connect(ctx context.Context, databaseURL string) (*Store, error) {
config, err := postgresPoolConfig(databaseURL)
return ConnectWithMaxConns(ctx, databaseURL, 0)
}
func ConnectWithMaxConns(ctx context.Context, databaseURL string, maxConns int) (*Store, error) {
config, err := postgresPoolConfig(databaseURL, maxConns)
if err != nil {
return nil, err
}
@@ -91,13 +95,16 @@ func Connect(ctx context.Context, databaseURL string) (*Store, error) {
return &Store{pool: pool}, nil
}
func postgresPoolConfig(databaseURL string) (*pgxpool.Config, error) {
func postgresPoolConfig(databaseURL string, maxConns ...int) (*pgxpool.Config, error) {
config, err := pgxpool.ParseConfig(databaseURL)
if err != nil {
return nil, err
}
config.ConnConfig.ConnectTimeout = postgresConnectTimeout
config.ConnConfig.RuntimeParams["application_name"] = postgresApplicationName
if len(maxConns) > 0 && maxConns[0] > 0 {
config.MaxConns = int32(maxConns[0])
}
return config, nil
}
@@ -523,6 +530,8 @@ type GatewayTask struct {
AsyncMode bool `json:"asyncMode"`
RiverJobID int64 `json:"riverJobId,omitempty"`
Status string `json:"status"`
QueueKey string `json:"-"`
Priority int `json:"-"`
Cancellable *bool `json:"cancellable,omitempty"`
Submitted *bool `json:"submitted,omitempty"`
Message string `json:"message,omitempty"`
@@ -570,7 +579,8 @@ COALESCE(api_key_id, ''), COALESCE(api_key_name, ''), COALESCE(api_key_prefix, '
COALESCE(user_group_id::text, ''), COALESCE(user_group_key, ''), model,
COALESCE(model_type, ''), COALESCE(requested_model, ''), COALESCE(resolved_model, ''), COALESCE(request_id, ''),
COALESCE(conversation_id::text, ''), COALESCE(new_message_count, 0),
request, COALESCE(async_mode, false), COALESCE(river_job_id, 0), status, COALESCE(attempt_count, 0),
request, COALESCE(async_mode, false), COALESCE(river_job_id, 0), status,
COALESCE(queue_key, 'default'), COALESCE(priority, 100), COALESCE(attempt_count, 0),
COALESCE(remote_task_id, ''), COALESCE(remote_task_payload, '{}'::jsonb),
COALESCE(result, '{}'::jsonb), COALESCE(billings, '[]'::jsonb),
COALESCE(usage, '{}'::jsonb), COALESCE(metrics, '{}'::jsonb), COALESCE(billing_summary, '{}'::jsonb),
@@ -715,6 +725,11 @@ ORDER BY COALESCE(dynamic_priority, priority) ASC, priority ASC, created_at DESC
}
func (s *Store) CreatePlatform(ctx context.Context, input CreatePlatformInput) (Platform, error) {
normalizedPolicy, err := NormalizeAndValidateRateLimitPolicy(input.RateLimitPolicy)
if err != nil {
return Platform{}, err
}
input.RateLimitPolicy = normalizedPolicy
credentials, _ := json.Marshal(emptyObjectIfNil(input.Credentials))
config, _ := json.Marshal(emptyObjectIfNil(input.Config))
retryPolicy, _ := json.Marshal(emptyObjectIfNil(input.RetryPolicy))
@@ -734,7 +749,7 @@ func (s *Store) CreatePlatform(ctx context.Context, input CreatePlatformInput) (
var retryPolicyBytes []byte
var rateLimitPolicyBytes []byte
var dynamicPriority sql.NullInt64
err := s.pool.QueryRow(ctx, `
err = s.pool.QueryRow(ctx, `
INSERT INTO integration_platforms (
provider, platform_key, name, internal_name, base_url, auth_type, credentials, config,
default_pricing_mode, default_discount_factor, pricing_rule_set_id,
@@ -789,6 +804,11 @@ RETURNING id::text, provider, platform_key, name, COALESCE(internal_name, ''), C
}
func (s *Store) UpdatePlatform(ctx context.Context, id string, input CreatePlatformInput) (Platform, error) {
normalizedPolicy, err := NormalizeAndValidateRateLimitPolicy(input.RateLimitPolicy)
if err != nil {
return Platform{}, err
}
input.RateLimitPolicy = normalizedPolicy
var credentials any
if input.Credentials != nil {
credentialsBytes, _ := json.Marshal(emptyObjectIfNil(input.Credentials))
@@ -812,7 +832,7 @@ func (s *Store) UpdatePlatform(ctx context.Context, id string, input CreatePlatf
var retryPolicyBytes []byte
var rateLimitPolicyBytes []byte
var dynamicPriority sql.NullInt64
err := s.pool.QueryRow(ctx, `
err = s.pool.QueryRow(ctx, `
UPDATE integration_platforms
SET provider = $2,
platform_key = COALESCE(NULLIF($3, ''), platform_key),
@@ -2138,6 +2158,8 @@ func scanGatewayTask(scanner taskScanner) (GatewayTask, error) {
&task.AsyncMode,
&task.RiverJobID,
&task.Status,
&task.QueueKey,
&task.Priority,
&task.AttemptCount,
&task.RemoteTaskID,
&remoteTaskPayloadBytes,