Skip to content

TRAE-011 — Production Architecture Closeout P0:Worker → Queue → Container → Neon 收口 #31

Closed

Description

@jhackuy

总控编号

PASAY-TASK-011

执行者

TRAE

Route

dev

优先级

P0

任务名称

Production Architecture Closeout P0:把现有 Telegram Webhook / Cloudflare / Neon 基础收敛成唯一生产主链

Authoritative Target Architecture

冻结目标:

Telegram → HTTPS Webhook → Cloudflare Worker(fetch) → Cloudflare Queue → Cloudflare Worker(queue consumer) → Cloudflare Container(FastAPI/Pasay runtime) → Neon PostgreSQL → Telegram Reply

定时任务统一:

Cloudflare Cron / scheduled() → 同一 Queue → 同一 queue consumer → 同一 Container → Neon

说明:Cloudflare Queues 的消费者本身由 Worker queue() handler 承接,再通过 Cloudflare Containers 原生 binding 调用 Container;因此逻辑简图可继续写成 Queue → Container,实现层不得错误假设 Queue 能绕过 consumer Worker 直接调用 Container。

本任务完成后,上述链路就是 Pasay 唯一目标生产 runtime。


已有事实 / 必须复用

  1. PASAY-WEBHOOK-ARCH-P0-001 / Issue #18 / PR #19 已 merge:

    • FastAPI POST /telegram/webhook
    • Telegram Update 持久化幂等
    • PTB Application.process_update(...)
    • bounded retry / stale claim recovery
    • health / logging
  2. 仓库已有 Cloudflare Worker + Neon/Postgres runtime boundary foundation。执行时必须读取当前 GitHub authority/base 的真实文件后复用;禁止重新造第二套 cloudflare-worker-v2、第二套 DB boundary、第二个 FastAPI app。

  3. 当前业务代码、Telegram UX、Membership / Property / Rent / Expense / Repair / Operation 都不是本任务重构对象。

  4. TRAE 只负责开发实现、测试、commit/push、PR;不负责生产部署、账号配置、值守或 Ops。


Goal

一次性完成架构代码收口,使仓库具备可部署的唯一生产路径:

  • 外部 Telegram 请求只进 Worker;
  • Worker 不执行业务,只做边界校验 + enqueue;
  • Queue 是异步缓冲与重试边界;
  • queue consumer 只负责把标准 envelope 可靠投递到同一 Container;
  • Container 内继续运行现有 FastAPI / Telegram handler / Pasay domain;
  • 所有持久业务状态继续进入 Neon;
  • Cron 与 Telegram 共用同一 queue/container/runtime,不再形成第二套执行栈。

禁止为了“架构漂亮”重写已经能工作的业务层。


Scope

A. Cloudflare Worker — Telegram ingress 只做最小入口

在现有 cloudflare-worker/ 原地增量:

  • 暴露生产 Telegram webhook route(具体 pathname 复用当前配置,禁止再增加重复公开入口)。
  • 校验 Telegram webhook secret / method / content type / payload 基础合法性。
  • 解析最小必要字段:update_id、可选 chat_id,但不得在 Worker 内解释业务 intent。
  • 将原始 Telegram Update 封装成 versioned queue envelope 后 env.<QUEUE>.send(...)。
  • enqueue 成功后快速返回 Telegram 可接受的 2xx。
  • enqueue 失败必须返回明确失败,不得伪造成功。

Worker fetch 层禁止:

  • 初始化 PTB
  • 调 FastAPI business service
  • 直接写 Neon
  • 调 LLM
  • 复制 Rent/Repair/Expense 等领域逻辑

B. Queue Envelope — 只定义一个统一消息合同

建立最小 versioned envelope,至少:

  • version
  • kind: telegram_update | scheduled_job
  • event_id
  • occurred_at
  • payload

Telegram:

  • event_id 必须稳定映射 update_id,保证重送可识别。

Scheduled:

  • event_id 必须可确定性/幂等生成,禁止每次 retry 生成全新业务事件身份。

不要引入 Avro/Protobuf/schema registry;TypeScript type + Python Pydantic/schema(确有需要)即可。

C. Queue Consumer → Cloudflare Container

在同一 Cloudflare Worker 项目实现 queue(batch, env, ctx) consumer:

  • 使用 Cloudflare Containers 当前官方原生 binding/API 调用 Pasay Container。
  • 禁止新建公网“内部 API”再从 Queue 经 Internet 绕一圈。
  • 每条消息投递到 Container 的单一内部 ingestion 边界。
  • Telegram envelope 最终进入已存在的 FastAPI Telegram webhook/update processing 能力;优先抽出/复用内部 service,不复制处理逻辑。
  • scheduled envelope 进入最小统一 job ingestion/dispatch 边界;若当前已有 scheduler/job service 必须复用。

Queue retry / ack 原则:

  • Container 2xx 且明确 accepted/idempotent duplicate → ack。
  • 临时失败 → retry。
  • 永久 malformed / unsupported → 明确终结,不无限 retry。
  • 使用 Cloudflare Queue 自带 retry/dead-letter 能力(如当前配置需要),禁止再造 Redis/Celery/RabbitMQ。

D. Container — 唯一 Python Runtime

现有 Dockerfile / FastAPI app 原地收敛,使同一 image 可作为 Cloudflare Container 运行:

  • 一个 FastAPI app;
  • 一个业务 domain;
  • 一个 DB boundary;
  • 一个 Telegram processing service;
  • 不在 Container 内启动 PTB long polling;
  • 不同时启动第二个 Telegram consumer;
  • 不依赖 Windows 本机常驻进程才能工作。

容器启动必须 fail-fast:

  • 必需 env 缺失 → 启动/health 明确 degraded/fail;
  • migrations 连接使用 direct/unpooled URL(按现有 DB boundary);
  • application runtime 使用现有 Neon 推荐连接方式;
  • secret 不写日志。

E. Neon / Database Boundary 收口

复用现有 app/infrastructure/postgres.py / DATABASE_URL / DATABASE_URL_UNPOOLED 体系(以执行时代码事实为准):

  • 不新增第二套 DB config。
  • 不新增 SQLite/Redis 作为业务事实。
  • webhook/update idempotency 与业务状态继续以 PostgreSQL/Neon 为事实源。
  • Alembic 必须继续 single-head。

本任务除非 queue/container ingress 确有必要,禁止新增业务 migration。

F. Cron 统一进入 Queue

建立最小 scheduled() handler:

  • 只负责生成合法 scheduled_job envelope 并 enqueue。
  • 禁止 Cron handler 直接执行业务 DB 写入。
  • 定时 reminder/digest/task wake-up 等后续业务都应可复用此入口,但本任务只建立基础通道,不新增运营功能。

G. Health / Architecture Truth

收口健康检查,至少能区分:

  • Worker ingress alive
  • queue binding configured
  • Container runtime alive
  • DB runtime boundary configured/connected(按现有 health 能力)

更新 CURRENT_ARCHITECTURE.md:

  • 删除/明确标记 2026-08-10 long-polling/Hermes 拓扑为 historical,不再写成 current production target。
  • 当前目标图只保留本 Issue 冻结的新架构。
  • 明确 Telegram 与 Cron 共用 Queue + Container。

不要写长篇平台文档;只更新事实。


Long Polling / Legacy Runtime Exit Gate

代码层必须证明:

  1. Cloudflare Container 启动路径不会调用 run_polling() / getUpdates。
  2. 生产配置不要求 Windows 本机 PTB polling gateway。
  3. 不保留“Webhook 与 polling 同时都可以作为生产入口”的双主架构。
  4. 若仓库必须保留本地 polling 脚本用于 dev/debug,必须明确 development-only,默认生产关闭,且不得被 Docker/Cloudflare startup 引用。
  5. Hermes/Lily 不作为 Telegram transport/runtime;如相关代码仍存在,只能是独立 supervisor/AI capability,不得消费同一 bot token 的 updates。

本任务只做仓库代码/配置层收口,不负责到 Windows 机器停止服务或到 Telegram API 实际执行 setWebhook/deleteWebhook。


Required End-to-End Validation

必须有 targeted integration tests / deterministic harness 证明:

T1 Telegram ingress

合法 Update #123
→ Worker fetch
→ exactly one queue envelope
→ envelope.kind=telegram_update
→ event_id 稳定映射 #123。

T2 Duplicate Telegram delivery

相同 update_id 再次进入
→ 即使 Queue at-least-once / Worker 重送
→ Container/Postgres idempotency 仍保证关键业务 process exactly-once effect。

T3 Queue → Container

queue consumer 收到合法 telegram envelope
→ 通过原生 Container binding 调唯一 Pasay runtime
→ 成功 2xx → ack。

T4 Temporary container failure

→ Queue retry
→ 不丢消息
→ 不在 Worker 内自己循环无限 retry。

T5 Permanent malformed envelope

→ fail closed / terminal handling
→ 不进入业务 service
→ 不无限 retry。

T6 Scheduled

scheduled()
→ scheduled_job envelope
→ Queue
→ 同一 Container ingestion
→ 不走第二业务 runtime。

T7 No polling in production startup

静态 + runtime test 证明 Cloudflare/Docker production startup 不调用 Telegram long polling/getUpdates。

T8 Neon boundary

Container 使用现有 DB boundary;direct migration/app runtime 配置不串线;Alembic single-head。

T9 Regression

Issue #18 webhook/update service 直接相关测试继续 PASS;Telegram 业务 handler 不因 transport 改造发生语义回退。


Strictly Forbidden

  • 不改 Telegram 3×2 一级菜单 / UX
  • 不改 Owner / Secretary 产品逻辑
  • 不做 Property / Rent / Expense / Repair / Operation 新功能
  • 不做 Mini App
  • 不改 OpenDesign
  • 不引入 Redis / Kafka / RabbitMQ / Celery / Temporal
  • 不建第二个 queue/orchestrator
  • 不把 Worker 变成业务后端
  • 不在 Worker 直接写 Neon
  • 不重写 FastAPI
  • 不新建第二个 Bot runtime
  • 不做 Kubernetes / VPS / 新服务器架构
  • 不 production deploy
  • 不修改 Cloudflare/GitHub/Telegram account secrets
  • 不处理 TRAE Auto Wake / ND 工作流

Stop Condition — ARCHITECTURE FROZEN

以下全部满足即立即 STOP:

  • Worker fetch → Queue 已实现
  • Queue consumer → Cloudflare Container 原生调用已实现
  • Container → 现有 FastAPI/Pasay domain → Neon 已收敛
  • Cron → 同一 Queue → 同一 Container 已建立
  • Webhook/update 幂等继续成立
  • production startup 无 long polling/getUpdates
  • 无第二套 DB / Bot / business runtime
  • health 可验证关键边界
  • CURRENT_ARCHITECTURE.md 与代码一致
  • targeted tests PASS
  • commit + push + PR

达到本 Stop Condition 后:

ARCHITECTURE_FROZEN = YES

后续除真实 blocker/production bug 外,禁止再开“继续优化架构”任务;主线转入功能修复与业务完善。

PR 创建后:

  • 不等待 CI
  • 不等待 CodeRabbit
  • 不 merge
  • 不设置 ready-for-owner
  • 输出 HANDOFF_COMPLETE

Final Report

中文精简报告必须包含:

  • PASAY-TASK-011
  • 执行者:TRAE
  • Issue / PR
  • branch / authority base SHA / head SHA
  • changed files
  • 最终实际 runtime diagram
  • Worker ingress
  • Queue envelope / retry / ack
  • Container binding / ingestion
  • Container startup 是否存在 polling(必须 NO)
  • Neon DB boundary
  • Cron 共用路径
  • health
  • targeted tests
  • legacy runtime 保留/删除边界
  • 明确未做事项
  • ARCHITECTURE_FROZEN = YES/NO
  • Final Status

最后一行:
HANDOFF_COMPLETE

Activity

  1. added
    route:devDirect TRAE implementation; no design change required
    ready-for-devTask is ready for TRAE implementation
    and removed
    ready-for-devTask is ready for TRAE implementation
    on Aug 20, 2026
  2. jhackuy commented on Aug 20, 2026

    @jhackuy
    OwnerAuthor

    PASAY-TASK-011-FIX2 已批准并进入返修。返修合同以 PR #32 最新 ND_RETURN — PASAY-TASK-011-FIX2 评论为唯一执行范围;继续现有 branch/PR,禁止新建 PR、禁止 merge、禁止扩大 Scope。

  3. added
    ready-for-devTask is ready for TRAE implementation
    and removed
    ready-for-devTask is ready for TRAE implementation
    on Aug 20, 2026
  4. jhackuy commented on Aug 20, 2026

    @jhackuy
    OwnerAuthor

    PASAY-TASK-011-FIX8 — CI PostgreSQL 16 Final Repair

    Executor: TRAE
    Issue: #31
    PR: #32
    Branch: issue/31-prod-arch-closeout-p0
    Task: 停止 SQLite 兼容路线,GitHub Actions targeted backend tests 改用 PostgreSQL 16。

    Root cause

    GitHub pasay-gate Run #37 已确认:CI 仍使用 DATABASE_URL=sqlite://,73 tests collected 后因 PostgreSQL-specific schema/constraints(当前首个明确错误为 btrim())产生 22 errors。继续给 tests/conftest.py 增加 SQLite 兼容只会继续暴露更多 PostgreSQL 方言差异,不是正确修复方向。

    Required changes

    1. 修改 .github/workflows/pr-ci.yml,为 pasay-gate job 增加 PostgreSQL 16 service:
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: postgres
        ports:
          - 5432:5432
        options: >-
          --health-cmd="pg_isready -U postgres"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=5
    1. targeted pytest 环境必须改为:
    DATABASE_URL: "postgresql+psycopg2://postgres:postgres@localhost:5432/postgres"
    DATABASE_URL_UNPOOLED: "postgresql+psycopg2://postgres:postgres@localhost:5432/postgres"
    PASAY_TEST_DB_NAME: "pasay_pm_test"
    1. 继续复用现有 tests/conftest.py 的 PostgreSQL test DB 隔离机制;不要再新增第二套 test DB 机制。
    2. 撤掉 FIX7 为 SQLite 新增的 tests/conftest.py 双方言兼容分支,恢复 PostgreSQL-only test harness。
    3. 如果 aiosqlite 只是 FIX5/FIX6 为错误 CI 路线新增,且生产/现有测试无真实依赖,则从 requirements.txt 删除。
    4. 检查 FIX5 为 SQLite 专门加入 internal_ingest.py 的 SQLite compatibility;如果仅为错误 CI 路线服务,则回退该 SQLite-only 分支。不要为了测试环境污染生产 PostgreSQL 路径。
    5. 不改业务功能、不改模型约束、不改 Worker 架构、不做无关重构、不新建 Issue/PR、不 merge。

    Required GitHub validation

    必须由 GitHub Actions 真实执行:

    • tests/test_prod_arch_closeout_p0_031.py
    • tests/test_telegram_webhook_p018.py

    硬验收:

    collected 73 items
    73 passed
    0 failed
    0 errors
    0 skipped
    pasay-gate = SUCCESS
    

    本机 PASS 不能替代 GitHub CI。

    Stop condition

    完成 push 后提交 HANDOFF_COMPLETE;TRAE 不 merge。

  5. added 3 commits that reference this issue on Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-devTask is ready for TRAE implementationroute:devDirect TRAE implementation; no design change required

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions