fix(worker): delegate production ddl to cd
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 59s
CD Pipeline / build-and-deploy (push) Successful in 7m9s
CD Pipeline / post-deploy-checks (push) Successful in 1m53s
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 59s
CD Pipeline / build-and-deploy (push) Successful in 7m9s
CD Pipeline / post-deploy-checks (push) Successful in 1m53s
This commit is contained in:
@@ -298,6 +298,13 @@ class Settings(BaseSettings):
|
|||||||
"processes that share a constrained production role."
|
"processes that share a constrained production role."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
DATABASE_BOOTSTRAP_DDL_ENABLED: bool = Field(
|
||||||
|
default=True,
|
||||||
|
description=(
|
||||||
|
"Run idempotent schema bootstrap DDL during process startup. "
|
||||||
|
"Production workers disable this after CD migration preflight."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
# Redis (192.168.0.188:6380, DB 0 - 與 OpenClaw 共用)
|
# Redis (192.168.0.188:6380, DB 0 - 與 OpenClaw 共用)
|
||||||
|
|||||||
@@ -582,15 +582,26 @@ async def _main() -> None:
|
|||||||
await init_redis_pool()
|
await init_redis_pool()
|
||||||
await init_worker_redis_pool() # Worker 專屬,無超時限制
|
await init_worker_redis_pool() # Worker 專屬,無超時限制
|
||||||
|
|
||||||
# Initialize PostgreSQL (Episodic Memory) - 確保 incidents 表存在
|
# Production schema ownership belongs to CD migration/preflight. Local and
|
||||||
try:
|
# development workers retain the idempotent bootstrap fallback by default.
|
||||||
await init_db()
|
if settings.DATABASE_BOOTSTRAP_DDL_ENABLED:
|
||||||
logger.info("postgresql_initialized", status="ok")
|
try:
|
||||||
except Exception as e:
|
await init_db()
|
||||||
logger.error(
|
logger.info("postgresql_initialized", status="ok")
|
||||||
"postgresql_init_failed",
|
except Exception as e:
|
||||||
error=str(e),
|
logger.error(
|
||||||
message="Episodic Memory (DB) will be unavailable - incidents won't persist",
|
"postgresql_init_failed",
|
||||||
|
error=str(e),
|
||||||
|
message=(
|
||||||
|
"Episodic Memory (DB) will be unavailable - incidents "
|
||||||
|
"won't persist"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logger.info(
|
||||||
|
"database_bootstrap_ddl_skipped",
|
||||||
|
owner="cd_migration_preflight",
|
||||||
|
workload="signal_worker",
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ Runtime bootstrap guard tests.
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import inspect
|
||||||
from collections.abc import Awaitable
|
from collections.abc import Awaitable
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import yaml
|
||||||
from sqlalchemy.exc import DBAPIError
|
from sqlalchemy.exc import DBAPIError
|
||||||
|
|
||||||
|
|
||||||
@@ -63,6 +66,24 @@ class _ConnectionBudgetEngine:
|
|||||||
raise RuntimeError('too many connections for role "awoooi"')
|
raise RuntimeError('too many connections for role "awoooi"')
|
||||||
|
|
||||||
|
|
||||||
|
def test_production_worker_delegates_bootstrap_ddl_to_cd() -> None:
|
||||||
|
from src.workers import signal_worker
|
||||||
|
|
||||||
|
root = Path(__file__).resolve().parents[3]
|
||||||
|
manifest = yaml.safe_load(
|
||||||
|
(root / "k8s/awoooi-prod/08-deployment-worker.yaml").read_text(
|
||||||
|
encoding="utf-8"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
container = manifest["spec"]["template"]["spec"]["containers"][0]
|
||||||
|
env = {item["name"]: item.get("value") for item in container["env"]}
|
||||||
|
source = inspect.getsource(signal_worker._main)
|
||||||
|
|
||||||
|
assert env["DATABASE_BOOTSTRAP_DDL_ENABLED"] == "false"
|
||||||
|
assert "if settings.DATABASE_BOOTSTRAP_DDL_ENABLED" in source
|
||||||
|
assert 'owner="cd_migration_preflight"' in source
|
||||||
|
|
||||||
|
|
||||||
def test_get_engine_uses_database_pool_budget(monkeypatch):
|
def test_get_engine_uses_database_pool_budget(monkeypatch):
|
||||||
from src.db import base as db_base
|
from src.db import base as db_base
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,8 @@ spec:
|
|||||||
value: "0"
|
value: "0"
|
||||||
- name: DATABASE_NULL_POOL
|
- name: DATABASE_NULL_POOL
|
||||||
value: "true"
|
value: "true"
|
||||||
|
- name: DATABASE_BOOTSTRAP_DDL_ENABLED
|
||||||
|
value: "false"
|
||||||
- name: AWOOOI_BUILD_COMMIT_SHA
|
- name: AWOOOI_BUILD_COMMIT_SHA
|
||||||
value: "ea857399517abed2824e536a2dda7e77463512c3"
|
value: "ea857399517abed2824e536a2dda7e77463512c3"
|
||||||
- name: ENABLE_AWOOOP_ANSIBLE_CANDIDATE_BACKFILL_WORKER
|
- name: ENABLE_AWOOOP_ANSIBLE_CANDIDATE_BACKFILL_WORKER
|
||||||
|
|||||||
Reference in New Issue
Block a user