Opt/b gfilter worker #103
@@ -143,6 +143,19 @@ ALIYUN_OSS_POST_EXPIRE_SECONDS="600"
|
||||
ALIYUN_OSS_POST_MAX_SIZE_BYTES="20971520"
|
||||
ALIYUN_OSS_SUCCESS_ACTION_STATUS="200"
|
||||
|
||||
# BgFilter 受限资源 worker。父 api-server / external-generation-worker 与唯一的
|
||||
# `GENARRATIVE_PROCESS_ROLE=bgfilter-worker` 进程必须使用同一个内部 Token。
|
||||
# `npm run dev` 与 `npm run dev:api-server` 都会自动带起并验活唯一 worker,不要再开第二个终端重复启动。
|
||||
# 只有需要脱离父 API 单独验证 worker 时才运行 `npm run dev:bgfilter-worker`;不要让 `all` 角色兼任它。
|
||||
GENARRATIVE_BGFILTER_WORKER_HOST="127.0.0.1"
|
||||
GENARRATIVE_BGFILTER_WORKER_PORT="8083"
|
||||
GENARRATIVE_BGFILTER_WORKER_BASE_URL="http://127.0.0.1:8083"
|
||||
GENARRATIVE_BGFILTER_INTERNAL_TOKEN="CHANGE_ME_FOR_LOCAL"
|
||||
GENARRATIVE_BGFILTER_WORKER_CONCURRENCY="16"
|
||||
GENARRATIVE_EDITOR_BGFILTER_SINGLE_IMAGE_ESTIMATE_MS="5000"
|
||||
GENARRATIVE_BGFILTER_WORKER_MAX_REQUESTS="2048"
|
||||
GENARRATIVE_BGFILTER_WORKER_CONNECT_TIMEOUT_MS="2000"
|
||||
|
||||
# SpacetimeDB 数据目录备份到 OSS。备份 bucket 可与资源 bucket 分离;未设置时脚本回退使用 ALIYUN_OSS_BUCKET。
|
||||
GENARRATIVE_DATABASE_BACKUP_DATA_DIR=""
|
||||
GENARRATIVE_DATABASE_BACKUP_WORK_DIR=""
|
||||
|
||||
@@ -106,6 +106,18 @@ jobs:
|
||||
- name: Run frontend and script tests
|
||||
run: npm run test
|
||||
|
||||
- name: Run BgFilter worker smoke harness tests
|
||||
run: npm run bgfilter-worker:smoke-test
|
||||
|
||||
- name: Validate production health patrol behavior
|
||||
run: npm run check:production-health-patrol
|
||||
|
||||
- name: Validate production API release behavior
|
||||
run: npm run check:production-api-release
|
||||
|
||||
- name: Validate production API deploy behavior
|
||||
run: npm run check:production-api-deploy
|
||||
|
||||
backend-tests:
|
||||
name: Backend tests
|
||||
runs-on: genarrative-ci
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
name: genarrative-dev-stack-port-routing
|
||||
short_description: 修改 Genarrative 本地 dev 启动端口、代理目标、端口冲突处理时使用。
|
||||
description: 在 Genarrative 中修改 npm run dev / dev:spacetime / dev:api-server / dev:web / dev:admin-web 的本地启动端口、端口可用性探测、端口漂移、SpacetimeDB publish server、api-server 环境变量、Vite 代理目标和后台 admin-web 启动串联时使用。
|
||||
version: 1.0.0
|
||||
description: 在 Genarrative 中修改 npm run dev / dev:spacetime / dev:api-server / dev:bgfilter-worker / dev:web / dev:admin-web 的本地启动端口、端口可用性探测、端口漂移、SpacetimeDB publish server、Rust 进程环境变量、Vite 代理目标和后台 admin-web 启动串联时使用。
|
||||
version: 1.1.0
|
||||
author: Hermes Agent
|
||||
license: MIT
|
||||
metadata:
|
||||
@@ -13,7 +13,7 @@ metadata:
|
||||
|
||||
# Genarrative 本地 dev 启动端口与代理目标串联流程
|
||||
|
||||
用于维护 Genarrative 本地开发栈启动脚本,重点覆盖 `npm run dev` 与四个 `dev:*` 单模块命令的端口检查、端口漂移和后续流程目标传递。
|
||||
用于维护 Genarrative 本地开发栈启动脚本,重点覆盖 `npm run dev` 与五个 `dev:*` 单模块命令的端口检查、端口漂移和后续流程目标传递。
|
||||
|
||||
## 适用场景
|
||||
|
||||
@@ -31,40 +31,44 @@ metadata:
|
||||
2. Rust `api-server`:`8082`,健康检查为 `http://127.0.0.1:<api-port>/healthz`。
|
||||
3. SpacetimeDB standalone:`3101`,健康检查为 `http://127.0.0.1:<spacetime-port>/v1/ping`。
|
||||
4. 后台 Vite:`3102`,后台地址为 `http://127.0.0.1:<admin-web-port>/admin/`。
|
||||
5. 独立 BgFilter worker:`8083`,就绪检查为 `http://127.0.0.1:<bgfilter-worker-port>/readyz`。
|
||||
|
||||
端口不可用时,脚本会从优先端口开始向后寻找可用端口。后续流程必须以解析后的实际端口为准,不能继续使用默认端口。
|
||||
|
||||
Linux 多用户并发开发时,`GENARRATIVE_DEV_PORT_RANGE` 或 `--port-range` 会先向系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json` 申请一个端口段,再把该段映射为 `web = start`、`api = start + 1`、`spacetime = start + 2`、`adminWeb = start + 3`。注册表锁文件是 `/var/tmp/genarrative-dev-port-ranges/registry.lock`,可通过 `GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR` 覆盖目录。自动分配从 `10000-10099` 起,每次占用 100 个端口块,后续块按 `10100-10199`、`10200-10299` 递增;当前口径是“一个用户固定占用一个段,后续启动继续复用这段并在段内漂移”;该注册表只在 Linux 上生效;Windows 继续沿用原有端口探测、漂移和复用逻辑,不读系统级注册表。
|
||||
Linux 多用户并发开发时,`GENARRATIVE_DEV_PORT_RANGE` 或 `--port-range` 会先向系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json` 申请一个端口段,再把该段映射为 `web = start`、`api = start + 1`、`spacetime = start + 2`、`adminWeb = start + 3`、`bgfilterWorker = start + 4`。注册表锁文件是 `/var/tmp/genarrative-dev-port-ranges/registry.lock`,可通过 `GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR` 覆盖目录。自动分配从 `10000-10099` 起,每次占用 100 个端口块,后续块按 `10100-10199`、`10200-10299` 递增;当前口径是“一个用户固定占用一个段,后续启动继续复用这段并在段内漂移”;该注册表只在 Linux 上生效;Windows 继续沿用原有统一端口探测和漂移逻辑,不读系统级注册表。
|
||||
|
||||
## 实现入口
|
||||
|
||||
- `package.json`
|
||||
- `dev`:执行 `node scripts/dev.mjs`,启动完整四模块。
|
||||
- `dev:spacetime` / `dev:api-server` / `dev:web` / `dev:admin-web`:执行 `node scripts/dev.mjs <module>`。
|
||||
- `dev`:执行 `node scripts/dev.mjs`,启动完整五服务。
|
||||
- `dev:spacetime` / `dev:api-server` / `dev:bgfilter-worker` / `dev:web` / `dev:admin-web`:执行 `node scripts/dev.mjs <module>`;`dev:api-server` 会安全带起其依赖的 BgFilter worker。
|
||||
- `scripts/dev-stack-port-utils.mjs`
|
||||
- `isPortAvailable(...)`:探测端口是否可监听。
|
||||
- `findAvailablePort(...)`:从优先端口向后寻找可用端口,`0` 表示申请临时端口。
|
||||
- `resolveDevStackPorts(...)`:一次性解析 SpacetimeDB、api-server、主站 Vite、后台 Vite 端口,并避免本次解析结果互相冲突。
|
||||
- `resolveDevStackPorts(...)`:一次性解析 SpacetimeDB、api-server、主站 Vite、后台 Vite、BgFilter worker 端口,并避免本次解析结果互相冲突。
|
||||
- Linux 注册表分配:`reserveLinuxDevPortRange(...)` / `releaseLinuxDevPortRange(...)`,仅在 Linux 上启用系统级端口段登记与用户段复用,自动分配从 `10000-10099` 起。
|
||||
- CLI 模式:`node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:3101 api:127.0.0.1:8082 web:0.0.0.0:3000 adminWeb:127.0.0.1:3102`。
|
||||
- CLI 模式:`node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:3101 api:127.0.0.1:8082 web:0.0.0.0:3000 adminWeb:127.0.0.1:3102 bgfilterWorker:127.0.0.1:8083`。
|
||||
- `scripts/dev.mjs`
|
||||
- 解析 CLI 参数后统一计算 client host、端口、`SPACETIME_SERVER`、`RUST_SERVER_TARGET`。
|
||||
- 完整栈按 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite 顺序启动。
|
||||
- Linux 下会先申请系统级端口段并把它映射成四个 dev 端口;自动分配从 `10000-10099` 起,Windows 则直接沿用原有参数解析与端口漂移逻辑。
|
||||
- 完整栈按 SpacetimeDB、publish、BgFilter worker readiness、api-server readiness、主站 Vite、后台 Vite 顺序启动。
|
||||
- Linux 下会先申请系统级端口段并把它映射成五个 dev 端口;自动分配从 `10000-10099` 起,Windows 则把第五个服务纳入原有统一参数解析与端口漂移逻辑。
|
||||
- 完整栈和 `dev:api-server` 把两个 Rust 进程作为同一重启单元,先全部停止,再先启动 BgFilter worker、后启动 api-server;不要为同一份 Rust 源码创建两个并发 `cargo` watcher。
|
||||
- 单模块命令复用同一套参数和 env 解析。
|
||||
|
||||
## 必须保持的传递链路
|
||||
|
||||
`npm run dev` 和四个 `dev:*` 单模块命令中端口解析后,必须同步到以下位置:
|
||||
`npm run dev` 和五个 `dev:*` 单模块命令中端口解析后,必须同步到以下位置:
|
||||
|
||||
1. SpacetimeDB 启动:`spacetime start --listen-addr "${SPACETIME_HOST}:${SPACETIME_PORT}"`。
|
||||
2. SpacetimeDB 发布:`spacetime publish ... --server "${SPACETIME_SERVER}"`。
|
||||
3. Rust api-server:`GENARRATIVE_API_HOST`、`GENARRATIVE_API_PORT`、`GENARRATIVE_SPACETIME_SERVER_URL`、`GENARRATIVE_SPACETIME_DATABASE`。
|
||||
4. api-server 健康检查:`wait_for_api_server "${RUST_SERVER_TARGET}/healthz" ...`。
|
||||
5. 主站 Vite:`RUST_SERVER_TARGET`、`GENARRATIVE_RUNTIME_SERVER_TARGET`、`ADMIN_WEB_TARGET`、`ADMIN_WEB_PORT`、`--port=${WEB_PORT}`、`--host=${WEB_HOST}`。
|
||||
6. 后台 Vite:`ADMIN_API_TARGET`、`GENARRATIVE_API_TARGET`、`GENARRATIVE_API_PORT`、`--port=${ADMIN_WEB_PORT}`。
|
||||
7. 控制台日志:`[dev:ports]` 和 `[dev] web/admin web/api-server/spacetime` 必须显示最终实际地址。
|
||||
8. Linux 端口段注册:`[dev] port-range:` 与 `[dev] port-range-registry:` 只在 Linux 输出,Windows 不应依赖系统级注册表。
|
||||
5. BgFilter worker:`GENARRATIVE_PROCESS_ROLE=bgfilter-worker`、解析后的 `HOST / PORT`、与父 API 相同的 `GENARRATIVE_BGFILTER_WORKER_BASE_URL` / `GENARRATIVE_BGFILTER_INTERNAL_TOKEN`,以及显式有效的 `N / Q`。
|
||||
6. BgFilter worker readiness:父 API 启动前检查解析后地址的 `/readyz`。
|
||||
7. 主站 Vite:`RUST_SERVER_TARGET`、`GENARRATIVE_RUNTIME_SERVER_TARGET`、`ADMIN_WEB_TARGET`、`ADMIN_WEB_PORT`、`--port=${WEB_PORT}`、`--host=${WEB_HOST}`。
|
||||
8. 后台 Vite:`ADMIN_API_TARGET`、`GENARRATIVE_API_TARGET`、`GENARRATIVE_API_PORT`、`--port=${ADMIN_WEB_PORT}`。
|
||||
9. 控制台日志:`[dev:ports]` 和 `[dev] web/admin web/api-server/bgfilter-worker/spacetime` 必须显示最终实际地址。
|
||||
10. Linux 端口段注册:`[dev] port-range:` 与 `[dev] port-range-registry:` 只在 Linux 输出,Windows 不应依赖系统级注册表。
|
||||
|
||||
如果只改了其中一段,通常会出现:浏览器打开的前端可用,但 `/api/*` 代理到旧端口;后台页面可用但后台 API 失败;SpacetimeDB 启动在新端口但 publish 仍发往旧端口。
|
||||
|
||||
@@ -74,7 +78,7 @@ Linux 多用户并发开发时,`GENARRATIVE_DEV_PORT_RANGE` 或 `--port-range`
|
||||
- `scripts/dev-stack-port-utils.mjs`
|
||||
- `scripts/dev.mjs`
|
||||
- `scripts/dev-utils.mjs`
|
||||
- `docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md`
|
||||
- `docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
|
||||
- `docs/project-memory/shared-memory/pitfalls.md`
|
||||
2. 优先改公共端口工具,不要把端口探测逻辑复制到多个脚本。
|
||||
3. 修改 `scripts/dev.mjs` 时确认变量顺序:先解析参数和端口,再构造 `SPACETIME_SERVER` / `RUST_SERVER_TARGET`,最后启动对应 service。
|
||||
@@ -91,21 +95,21 @@ Linux 多用户并发开发时,`GENARRATIVE_DEV_PORT_RANGE` 或 `--port-range`
|
||||
node --check scripts/dev.mjs
|
||||
npm run test -- scripts/dev-stack-port-utils.test.ts
|
||||
npm run check:encoding
|
||||
node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:0 api:127.0.0.1:0 web:0.0.0.0:0 adminWeb:127.0.0.1:0
|
||||
node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:0 api:127.0.0.1:0 web:0.0.0.0:0 adminWeb:127.0.0.1:0 bgfilterWorker:127.0.0.1:0
|
||||
```
|
||||
|
||||
端口冲突回归测试建议:
|
||||
|
||||
1. 用测试或临时 Node server 占用某个优先端口。
|
||||
2. 调用 `findAvailablePort`,断言结果大于被占用端口。
|
||||
3. 调用 `resolveDevStackPorts`,断言四个结果互不相同。
|
||||
3. 调用 `resolveDevStackPorts`,断言五个结果互不相同。
|
||||
4. 如果实际启动完整栈,观察控制台:
|
||||
- `[dev:ports] ... 不可用,改用 ...`
|
||||
- `[dev] api-server: http://...:<actual-api-port>`
|
||||
- `[dev] spacetime: http://...:<actual-spacetime-port>`
|
||||
- 主站和后台 Vite 启动端口与日志一致。
|
||||
|
||||
完整启动属于长驻进程。需要 smoke 时用 background 方式启动,并另开命令检查 `/healthz`、`/v1/ping` 和页面端口;不要等待 `npm run dev` 自然退出。
|
||||
完整启动属于长驻进程。需要 smoke 时用 background 方式启动,并另开命令检查 api-server `/healthz`、BgFilter worker `/readyz`、SpacetimeDB `/v1/ping` 和两个页面端口;不要等待 `npm run dev` 自然退出。检查地址必须取 `.app/dev-stack.json` 或启动日志中的实际端口,不能假定 worker 一定停在 `8083`。
|
||||
|
||||
## 常见坑
|
||||
|
||||
@@ -122,7 +126,8 @@ node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:0 ap
|
||||
- [ ] Linux 注册表分配、同用户复用固定段并继续漂移、自动分配从 `10000-10099` 起、Windows bypass 都有测试覆盖。
|
||||
- [ ] `scripts/dev.mjs` 通过 `node --check`。
|
||||
- [ ] `npm run dev` 的 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite 都使用实际端口。
|
||||
- [ ] BgFilter worker 在 api-server 前 ready,父子共享实际 base URL / Token,Rust watch 只触发一次组合重启。
|
||||
- [ ] `npm run dev:web` 在主站端口不可用时能切换到可用端口。
|
||||
- [ ] 文档同步更新 `docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md`。
|
||||
- [ ] 文档同步更新 `docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
- [ ] 长期踩坑同步更新 `docs/project-memory/shared-memory/pitfalls.md`。
|
||||
- [ ] 修改中文文件后运行 `npm run check:encoding`。
|
||||
|
||||
@@ -44,10 +44,10 @@ npm run dev
|
||||
|
||||
补充说明:
|
||||
|
||||
- `npm run dev` 会启动 SpacetimeDB standalone、Rust `api-server`、主站 Vite 与后台 Vite,适合完整联调。
|
||||
- `npm run dev` 会启动 SpacetimeDB standalone、独立 `bgfilter-worker`、Rust `api-server`、主站 Vite 与后台 Vite,适合完整联调;内部 worker ready 后才启动 API。
|
||||
- 主站默认地址是 `http://127.0.0.1:3000`,后台可从 `http://127.0.0.1:3000/admin/` 进入,也可直连 `http://127.0.0.1:3102`。
|
||||
- 四个模块可独立启动:`npm run dev:spacetime`、`npm run dev:api-server`、`npm run dev:web`、`npm run dev:admin-web`。
|
||||
- 如需自动刷新后端模块,使用 `npm run dev -- --watch`;其中 `spacetime-module` 改动后只会重新发布模块,不会重启 standalone,`api-server` 改动后会重启 Rust 进程。主站和后台前端源码变化交给 Vite 自身 HMR,不由外层 watcher 重启。非 watch 模式下可在 `npm run dev` 终端输入 `rs api-server`、`rs web`、`rs admin-web`、`rs spacetime` 或 `rs all`,其中 `rs spacetime` 也是只重新发布模块。
|
||||
- 五个模块可独立启动:`npm run dev:spacetime`、`npm run dev:api-server`、`npm run dev:bgfilter-worker`、`npm run dev:web`、`npm run dev:admin-web`;其中 `dev:api-server` 会安全带起同 runner 的 BgFilter worker 依赖。
|
||||
- 如需自动刷新后端模块,使用 `npm run dev -- --watch`;其中 `spacetime-module` 改动后只会重新发布模块,不会重启 standalone,Rust 源码改动会把 `api-server` 与 `bgfilter-worker` 作为一个组合单元重启。主站和后台前端源码变化交给 Vite 自身 HMR,不由外层 watcher 重启。非 watch 模式下可在 `npm run dev` 终端输入 `rs api-server`、`rs bgfilter-worker`、`rs web`、`rs admin-web`、`rs spacetime` 或 `rs all`,其中 `rs spacetime` 也是只重新发布模块。
|
||||
|
||||
构建生产包:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Genarrative 容器化压测、隔离部署与 CI Job 镜像
|
||||
|
||||
本目录同时保存两类互不替代的容器资产:本机或预发的容器化模拟压测,以及 Gitea Actions 使用的预构建 CI job 镜像。它们都不替换当前生产 `systemd + Nginx + Jenkins` 发布路径;生产服务器仍以 `deploy/systemd/`、`deploy/nginx/`、`scripts/jenkins-*.sh` 和 `scripts/deploy/production-api-deploy.sh` 为准。
|
||||
本目录同时保存两类互不替代的容器资产:本机或预发的容器化模拟压测,以及 Gitea Actions 使用的预构建 CI job 镜像。它们都不替换当前生产 `systemd + Nginx + Jenkins` 发布路径;生产服务器仍以 `deploy/systemd/`、`deploy/nginx/`、`scripts/jenkins-*.sh` 和 `scripts/deploy/production-api-deploy.sh` 为准。当前 compose 不包含独立 `bgfilter-worker`,因此不是完整 BgFilter 预发拓扑,也不覆盖会触发 BgFilter 的现役任务;这里只验证非 BgFilter 路径,或使用 unsupported job 检查队列 claim / fail 回写和 API / worker 进程隔离。
|
||||
|
||||
## 拓扑
|
||||
|
||||
@@ -15,7 +15,7 @@ Docker Compose
|
||||
|
||||
当前容器模拟参数按 `genarrative-release` 服务器采样值收口为 2 vCPU / 2 GiB RAM / 4096 soft nofile / 768 worker_connections,并已在 compose 里落实到 `spacetimedb cpus=1.0 mem_limit=896m`、`api-server cpus=2.0 mem_limit=1g`、`external-generation-worker cpus=2.0 mem_limit=1g`、`nginx cpus=0.5 mem_limit=128m`、`otelcol cpus=0.25 mem_limit=128m`。SpacetimeDB 同时设置 `--page_pool_max_size=402653184`,给 reducer、订阅与运行时保留更多非 page pool 内存。
|
||||
容器 `api-server` 默认 `GENARRATIVE_API_WORKER_THREADS=4`,用于让 Tokio 在 2 vCPU 配额内有更多 I/O 调度 worker;该值不会突破 compose 里的 `cpus=2.0` CPU 上限。
|
||||
容器默认 `GENARRATIVE_EXTERNAL_GENERATION_MODE=queue`,用于验证 `api-server -> external_generation_job -> external-generation-worker` 链路;如只想本地同步排查 provider/OSS/SpacetimeDB 写回,可在本机 env 临时改为 `inline`,但该模式不会覆盖 worker 动态扩缩容验证。
|
||||
容器默认 `GENARRATIVE_EXTERNAL_GENERATION_MODE=queue`,用于验证不经过 BgFilter 的 `api-server -> external_generation_job -> external-generation-worker` 链路;会触发 BgFilter 的任务不属于当前 compose 验收范围。如只想本地同步排查非 BgFilter provider / OSS / SpacetimeDB 写回,可在本机 env 临时改为 `inline`,但该模式不会覆盖 worker 动态扩缩容验证。
|
||||
Collector 镜像使用 `otel/opentelemetry-collector-contrib:0.151.0`。
|
||||
生产服务器若启用 Collector,则由 `deploy/systemd/otelcol-contrib.service` 和 `deploy/otelcol/genarrative-debug.yaml` 托管,不走容器镜像。
|
||||
|
||||
|
||||
@@ -30,9 +30,10 @@ GENARRATIVE_WALLET_REFUND_OUTBOX_DIR=/var/lib/genarrative/wallet-refund-outbox
|
||||
GENARRATIVE_WALLET_REFUND_OUTBOX_BATCH_SIZE=100
|
||||
GENARRATIVE_WALLET_REFUND_OUTBOX_FLUSH_INTERVAL_MS=1000
|
||||
GENARRATIVE_WALLET_REFUND_OUTBOX_MAX_BYTES=67108864
|
||||
GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS=180000
|
||||
GENARRATIVE_BGFILTER_WORKER_CONCURRENCY=16
|
||||
GENARRATIVE_EDITOR_BGFILTER_SINGLE_IMAGE_ESTIMATE_MS=5000
|
||||
GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD=3
|
||||
GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS=300
|
||||
GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS=120
|
||||
# BgFilter 失败后的中间兜底:阿里云通用抠图(SegmentCommonImage)。AccessKey 留空则跳过该层,
|
||||
# BgFilter 失败直接本地 editor_green_screen 去背;填入后恢复 BgFilter→阿里云→本地三级兜底。
|
||||
# AccessKey 也可复用标准 SDK 命名 ALIBABA_CLOUD_ACCESS_KEY_ID / ALIBABA_CLOUD_ACCESS_KEY_SECRET。
|
||||
|
||||
Vendored
+10
-3
@@ -17,6 +17,10 @@ GENARRATIVE_EXTERNAL_GENERATION_WORKER_POLL_INTERVAL_MS=2000
|
||||
GENARRATIVE_EXTERNAL_GENERATION_WORKER_LEASE_SECONDS=600
|
||||
GENARRATIVE_EXTERNAL_GENERATION_WORKER_JOB_TIMEOUT_SECONDS=900
|
||||
GENARRATIVE_EXTERNAL_GENERATION_WORKER_LONG_JOB_TIMEOUT_SECONDS=1800
|
||||
# 父流程只访问同机 BgFilter worker;内部 Token 只通过受保护文件共享,不写明文 env。
|
||||
GENARRATIVE_BGFILTER_WORKER_BASE_URL=http://127.0.0.1:8083
|
||||
GENARRATIVE_BGFILTER_INTERNAL_TOKEN_FILE=/etc/genarrative/secrets/bgfilter-worker.token
|
||||
GENARRATIVE_BGFILTER_WORKER_CONNECT_TIMEOUT_MS=2000
|
||||
GENARRATIVE_API_MAX_CONCURRENT_REQUESTS=512
|
||||
GENARRATIVE_API_ADMIN_MAX_CONCURRENT_REQUESTS=16
|
||||
GENARRATIVE_API_SHUTDOWN_OUTBOX_FLUSH_TIMEOUT_MS=5000
|
||||
@@ -30,9 +34,12 @@ GENARRATIVE_WALLET_REFUND_OUTBOX_DIR=/var/lib/genarrative/wallet-refund-outbox
|
||||
GENARRATIVE_WALLET_REFUND_OUTBOX_BATCH_SIZE=100
|
||||
GENARRATIVE_WALLET_REFUND_OUTBOX_FLUSH_INTERVAL_MS=1000
|
||||
GENARRATIVE_WALLET_REFUND_OUTBOX_MAX_BYTES=67108864
|
||||
GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS=180000
|
||||
GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD=3
|
||||
GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS=300
|
||||
# N 与单图估时:父子共同派生 attempt = N×est×2、callBudget = 2×attempt+1s 的公式输入;
|
||||
# 单一来源放共享 env,专属 worker env 不重复定义。旧固定 REQUEST_TIMEOUT_MS 已删除。
|
||||
GENARRATIVE_BGFILTER_WORKER_CONCURRENCY=16
|
||||
GENARRATIVE_EDITOR_BGFILTER_SINGLE_IMAGE_ESTIMATE_MS=5000
|
||||
GENARRATIVE_EDITOR_BGFILTER_BASE_URL=http://58.87.105.82/bgfilter
|
||||
GENARRATIVE_EDITOR_BGFILTER_TOKEN=
|
||||
# BgFilter 失败后的中间兜底:阿里云通用抠图(SegmentCommonImage)。AccessKey 留空则跳过该层,
|
||||
# BgFilter 失败直接本地 editor_green_screen 去背;填入后恢复 BgFilter→阿里云→本地三级兜底。
|
||||
# AccessKey 也可复用标准 SDK 命名 ALIBABA_CLOUD_ACCESS_KEY_ID / ALIBABA_CLOUD_ACCESS_KEY_SECRET。
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
# 复制到 /etc/genarrative/bgfilter-worker.env;只放专用进程独占参数和可选日志覆盖。
|
||||
# provider、OSS、内部 Token 文件、N(CONCURRENCY)与单图估时统一来自先加载的 api-server.env,禁止在此重复定义。
|
||||
# systemd unit 会强制设置 GENARRATIVE_PROCESS_ROLE=bgfilter-worker。
|
||||
|
||||
GENARRATIVE_ENV=production
|
||||
GENARRATIVE_BGFILTER_WORKER_HOST=127.0.0.1
|
||||
GENARRATIVE_BGFILTER_WORKER_PORT=8083
|
||||
# Q:admission 保险丝,只防连接风暴;正常业务不应触达,显式配置时必须 >= N。
|
||||
GENARRATIVE_BGFILTER_WORKER_MAX_REQUESTS=2048
|
||||
# flat / complex 熔断只由本进程维护;两种模式共享参数,但状态互相独立。
|
||||
GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD=3
|
||||
GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS=120
|
||||
|
||||
GENARRATIVE_API_LOG=info,tower_http=info
|
||||
GENARRATIVE_OTEL_ENABLED=true
|
||||
OTEL_SERVICE_NAME=genarrative-bgfilter-worker
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318
|
||||
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,service.namespace=genarrative
|
||||
Vendored
+3
@@ -2,6 +2,9 @@
|
||||
# 默认不启用 Pingora shadow 巡检;只有同时配置 base URL 与 probe token 才会检查。
|
||||
|
||||
GENARRATIVE_HEALTH_PATROL_API_BASE_URL=http://127.0.0.1:8082
|
||||
# 巡检是独立进程,不读取 bgfilter-worker.env;若自定义了 GENARRATIVE_BGFILTER_WORKER_PORT,
|
||||
# 必须在此同步改为相同端口,否则巡检会持续误报 worker 不健康。
|
||||
GENARRATIVE_HEALTH_PATROL_BGFILTER_BASE_URL=http://127.0.0.1:8083
|
||||
GENARRATIVE_HEALTH_PATROL_SPACETIME_BASE_URL=http://127.0.0.1:3101
|
||||
GENARRATIVE_HEALTH_PATROL_PUBLIC_BASE_URL=http://127.0.0.1
|
||||
# 默认公网入口仍按 Nginx 巡检;Pingora 直连切换后改为 pingora-direct。
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
[Unit]
|
||||
Description=Genarrative BgFilter Worker
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=genarrative
|
||||
Group=genarrative
|
||||
WorkingDirectory=/opt/genarrative/current
|
||||
EnvironmentFile=/etc/genarrative/api-server.env
|
||||
EnvironmentFile=/etc/genarrative/bgfilter-worker.env
|
||||
Environment="LD_LIBRARY_PATH=/opt/genarrative/openssl-3.2.0/lib64:/opt/genarrative/openssl-3.2.0/lib"
|
||||
ExecStart=/usr/bin/env GENARRATIVE_PROCESS_ROLE=bgfilter-worker OTEL_SERVICE_NAME=genarrative-bgfilter-worker /opt/genarrative/current/api-server
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
KillSignal=SIGINT
|
||||
# shutdown 会立即拒绝仍在排队的请求,只排空已取得 provider permit 的调用;默认 N=16、est=5000ms 时 callBudgetMs=321s,额外窗口用于响应发送和进程收口。
|
||||
TimeoutStopSec=900
|
||||
LimitNOFILE=65535
|
||||
TasksMax=2048
|
||||
|
||||
# 固定 loopback 地址与非模板 unit 共同保证首版同机只运行一个 BgFilter worker。
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=full
|
||||
ReadWritePaths=/opt/genarrative /var/lib/genarrative
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -27,6 +27,7 @@
|
||||
### 后端与公开数据
|
||||
|
||||
- [外部生成 Worker 化方案](./technical/【后端架构】外部生成Worker化方案-2026-06-03.md)
|
||||
- [BgFilter 受限资源调度方案(同步内部 HTTP 原地等待版)](./technical/【后端架构】BgFilter受限资源调度方案-2026-07-21.md)
|
||||
- [统一公开作品 Read Model 设计](./technical/【后端架构】统一公开作品ReadModel设计-2026-05-26.md)
|
||||
- [外部 OpenAPI 与 API Key 接入方案](./【后端架构】外部OpenAPI与APIKey接入方案-2026-06-19.md)
|
||||
- [SpacetimeDB 连接池取消安全](./【后端架构】SpacetimeDB连接池租约Drop兜底与取消安全-2026-06-11.md)
|
||||
|
||||
@@ -16,6 +16,38 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-23 BgFilter 失败审计使用硬上限与独立 tracking outbox
|
||||
|
||||
- 背景:BgFilter worker 每个已发出的失败 provider attempt 都会启动 detached 审计任务;专用 worker 又关闭了 tracking outbox,使任务逐条等待 SpacetimeDB。`Q` 只约束内部 HTTP 请求生命周期,响应结束后无法限制仍在等待数据库的审计任务,部分失败、预算截短 timeout、重试恢复和熔断重置场景下可能持续堆积。
|
||||
- 决策:BgFilter worker 的失败审计在 `tokio::spawn` 前统一获取进程级 `1024` 个硬上限 permit,满载时直接丢弃并记录低基数指标,不创建等待任务。获准任务优先写入 worker 独立 tracking outbox,目录固定派生为共享 `GENARRATIVE_TRACKING_OUTBOX_DIR` 下的 `bgfilter-worker/` 子目录;worker 启动 outbox flush worker,退出时先排空已获准审计 enqueue,再封存并尽力 flush。BgFilter 专用策略在 outbox 缺失、容量拒绝或写盘失败时丢弃并观测,不回退同步直写 SpacetimeDB;其它外部 API 审计保持原有 fallback 语义。
|
||||
- 影响范围:`api-server` BgFilter worker、外部 API 失败审计策略、tracking outbox 进程接线、指标与测试、BgFilter 架构和开发运维文档;不修改 SpacetimeDB schema、procedure、bindings、前端或公开 DTO。
|
||||
- 验证方式:覆盖 spawn 前容量拒绝、flat / complex 共享总上限、permit 生命周期、独立 outbox 目录、outbox 满载 / 写盘失败不直写、SpacetimeDB 不可用时任务与磁盘保持有界,以及退出时 tracker drain 后再 flush;运行 api-server 定向测试、BgFilter fault smoke、Rust check、编码和 diff 检查。
|
||||
- 关联文档:`docs/technical/【后端架构】BgFilter受限资源调度方案-2026-07-21.md`、`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-22 BgFilter flat 与 complex 使用独立熔断状态
|
||||
|
||||
- 背景:complex 请求在 provider 持续快速失败时仍会不断发起真实 provider attempt,并为每次已发出的失败生成异步审计;现有 flat 熔断不能约束 complex,且五分钟冷却会让短暂故障恢复后的等待过长。
|
||||
- 决策:把现有 flat 熔断行为按原语义复用到 complex。flat / complex 共享 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD=3` 与 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS=120`,但在唯一 `bgfilter-worker` 内分别维护独立的连续失败数和打开截止时间;真实 provider attempt 的失败或成功只更新当前模式。两种模式都在排队前及取得 provider permit 后、第一次真实 HTTP 前检查自身熔断;已经通过第二次检查的逻辑调用仍可完成自己的第二次顺序 attempt。complex 熔断仍直接使父流程失败,不获得 flat 的阿里云 / 本地 fallback;本次不修改失败审计的异步处理流程。
|
||||
- 部署边界:deploy / Provision 将 worker env 中历史模板默认 cooldown `300` 定向迁移到 `120`,其它显式自定义值保持不变;`bgfilter_circuit_state` 分别上报 `mode=flat` 与 `mode=complex`。
|
||||
- 影响范围:`api-server` BgFilter worker、熔断指标与测试、worker 环境模板、生产部署迁移门禁、BgFilter 架构和运维文档;不修改 SpacetimeDB schema、父业务 fallback、计费或失败审计流程。
|
||||
- 验证方式:覆盖两种模式状态隔离、阈值、成功重置、cooldown 到期、permit 前二次检查和部署默认值迁移;运行 api-server BgFilter 定向测试、生产部署脚本门禁、编码检查与 diff 检查。
|
||||
- 关联文档:`docs/technical/【后端架构】BgFilter受限资源调度方案-2026-07-21.md`、`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
|
||||
## 2026-07-21 BgFilter 首版采用单实例同步内部 HTTP 与父流程原地等待
|
||||
|
||||
- 背景:角色动画在单个 `external_generation_job` 内通过 `buffer_unordered(frame_count)` 可并发发射最多 `48` 次 BgFilter 请求;限制父 worker 并发不能限制单个父 job 内的实际 BgFilter 并发。父 job checkpoint / continuation 和 SpacetimeDB 持久子任务都会扩大父状态机、attempt、计费、恢复和清理改动,而当前 BgFilter 成功结果本来就是 HTTP 图片二进制。
|
||||
- 决策:父 future 保持原调用栈、lease 和 attempt,等待期间继续占用通用 worker 槽并由现有 heartbeat 续租;所有调用统一同步请求唯一 `bgfilter-worker` 的内部 loopback HTTP。输入只传 OSS object key、参数、`maxQueueWaitMs / callBudgetMs` 和有界审计关联,成功直接返回经过校验的图片二进制。子 worker 使用有界 admission `Q` 和进程内 `Semaphore(N)`,负责最多两次顺序 provider attempt、flat 进程级熔断和失败审计;父流程继续负责 flat 降级、complex 失败、Alpha / 尺寸恢复、动画 finalizer、最终 OSS、业务写回、计费和父终态。
|
||||
- 超时边界:父 job 总预算仍为普通 `900s` / 长任务 `1800s`,并保留现有 `60s` 终态写回窗口。内部协议拆成互不挪用的 `maxQueueWaitMs` 与 `callBudgetMs`:前者由父剩余绝对预算扣除调用预算和父侧预留后派生,只限制等待 provider permit;flat 的 `39s` 父侧预留由 `37s` fallback(阿里云 `30s` + 本地 `7s`)与 `2s` 传输窗组成,complex 只留 `2s` 传输窗。后者从取得 permit 后起算,覆盖签名、最多两次 attempt、结果校验和响应构造。provider attempt 上限按 `N × est × 2` 派生,调用预算按 `2 × attempt + 1s` 派生;额外 `1s` 吸收 attempt 间开销,只要剩余时间仍能容纳完整 attempt 就不得先扣响应预留。父内部 client timeout 精确取 `maxQueueWaitMs + callBudgetMs + 2s`,不在发送阶段重新裁剪两笔相对预算。冻结 `N=16`、`est=5000ms` 时 attempt / callBudget 分别为 `160s / 321s`。动画删除旧的按帧数 timeout 增量,父侧不得在内部 timeout / 断连后重试整次 RPC。
|
||||
- 故障边界:首版不新增 `bgfilter_task_group`、`bgfilter_request_task`、raw OSS、checkpoint、continuation、数据库 capacity slot、共享熔断或 QPS token bucket。父或子进程崩溃、RPC 丢失时不查询、不恢复结果;父 job 沿用现有 lease / `max_attempts=1` 失败退款语义。动画首版保持所有已提交帧 collect / drain,不增加跨帧取消组。
|
||||
- 部署边界:专用进程首版仍复用完整 `AppState`,因此 systemd unit 先加载共享 `/etc/genarrative/api-server.env`,再加载 `/etc/genarrative/bgfilter-worker.env` 覆盖 worker 独占参数;父子共同依赖的 `N=16` 与 `est=5000ms` 必须来自共享基础环境,worker 专属环境只管理 flat 熔断参数和默认 `Q=2048` 保险丝。发布切换前校验父子使用同一个非空、非符号链接、`root:genarrative 0440` 的内部 Token 文件,并拒绝父子内部 URL、Token、连接参数、`N / est`、OSS bucket 或 endpoint 漂移(同 bucket 的独立 AK 允许)。worker 停机时立即拒绝仍在排队的请求,只排空已取得 provider permit 的调用;unit 使用 `TimeoutStopSec=900` 覆盖默认 `321s` 调用预算及响应收口。运行期巡检同时检查唯一 worker unit active 与 loopback readiness;本地 `npm run dev` 同样启动独立子进程并解析第五个 dev 端口,`ProcessRole::All` 不内嵌 listener。
|
||||
- 影响范围:已实施范围包括 `api-server` 内部 HTTP client、专用 `bgfilter-worker` listener / process role、并发与超时配置、部署和运维观测;未修改 SpacetimeDB schema、父 job schema、用户任务 DTO、任务列表或收费归属,当前待生产压测后启用。
|
||||
- 验证方式:`48` 帧并发进入父 future 时,健康唯一子 worker 进程持有的 BgFilter HTTP future 峰值不得超过生产显式配置的 `N`,且 `queued + running + egress` 不超过 `Q`(admission permit 持有到 response body 发送完成或 drop);覆盖 flat / complex 降级矩阵、内部 deadline、断连后已启动请求排空、动画全帧 drain、External v1 / inline 旁路扫描、二进制大小 / MIME / 尺寸门禁、单实例部署、DDD、编码和 diff 门禁。
|
||||
- 关联文档:`docs/technical/【后端架构】BgFilter受限资源调度方案-2026-07-21.md`、`docs/technical/【后端架构】外部生成Worker化方案-2026-06-03.md`、`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`。
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-20 角色动作抠图前禁止透明 padding
|
||||
|
||||
- 背景:图片画布角色动作此前在 BgFilter 前复用最终帧 finalizer,把 FFmpeg 抽帧先转成目标尺寸 RGBA 画布并用透明黑像素补边;透明区域进入 BgFilter、阿里云和本地键色共同读取的 OSS 源帧后,会干扰主体边缘判断并降低抠图质量。
|
||||
@@ -112,6 +144,8 @@
|
||||
|
||||
## 2026-07-15 BgFilter 输入改用私有 OSS 短期签名 URL
|
||||
|
||||
> 后续更正(2026-07-21):复用 object key、通过 `image_url` 提交且不传 `file` 的协议语义保留,但 600 秒 OSS GET URL 的签发和 BgFilter provider multipart 调用已迁入唯一 `bgfilter-worker`。父流程只向内部 worker 发送一次 object key、参数和剩余预算,不签发 BgFilter URL,也不重试已被 worker 接收的内部 RPC(2026-07-23 起:连接从未建立的失败按调度方案 §5.1 有界重连,见当日决策条目)。下文保留作历史记录。
|
||||
|
||||
- 背景:角色形象、图标图集、UI 素材图集、角色动作抽取帧和手动去背景在调用 BgFilter 前都已有私有 OSS object key;继续由 api-server 下载或保留图片并作为 multipart `file` 再上传,会重复传输图片字节并占用 API 进程网络与内存。
|
||||
- 决策:上述抠图链路统一复用 object key,签发 600 秒 OSS GET URL,并通过 BgFilter multipart 的 `image_url` 字段提交;请求中不再携带 `file`。签名 URL 只交给 BgFilter,不写日志或持久化。2026-07-17 起,生成原图和动作帧上传后不再保留图片字节;进入“阿里云通用抠图 → 本地键色”兜底链时按阶段从私有 OSS 重新下载。
|
||||
- 影响范围:`server-rs/crates/api-server/src/editor_project.rs`、`server-rs/crates/api-server/src/character_animation_assets.rs`、相关测试与文档;不改变 BgFilter endpoint、鉴权、`screen_color`、`seg_model`、输出校验、熔断规则、阿里云上传协议或降级顺序。
|
||||
@@ -127,6 +161,8 @@
|
||||
|
||||
## 2026-07-15 角色动作 BgFilter 请求超时按帧数扩展
|
||||
|
||||
> 后续更正(2026-07-21):本条按帧数增加 timeout 的决策已被 2026-07-21「BgFilter 首版采用单实例同步内部 HTTP 与父流程原地等待」的公式化双预算取代。当前每帧分别携带 `maxQueueWaitMs` 与 `callBudgetMs`:排队预算只约束等待 provider permit,取得 permit 后才启动调用预算;provider attempt 按 `N × est × 2`、调用预算按 `2 × attempt + 1s` 运行时派生,冻结 `N=16`、`est=5000ms` 时为 `160s / 321s`,不再按 `32 / 40 / 48` 帧扩展。下文保留作历史记录。
|
||||
|
||||
- 背景:角色动作全部序列帧会并发进入 BgFilter,而服务端可能在自身进程内排队;固定 `180000ms` 会把排队时间和单帧推理共用同一预算,靠后的请求可能在服务仍正常处理时被 api-server 提前取消。
|
||||
- 决策:保留 `GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS` 作为统一基准值。只有角色动作逐帧 BgFilter 在共享 Client 的 RequestBuilder 上把每一次 HTTP attempt 覆盖为“基准值 + `2000ms × 本次实际帧数`”,默认 `32 / 40 / 48` 帧为 `244000 / 260000 / 276000ms`;角色形象单图、图标、UI 和手动去背景不增加帧预算。该 timeout 覆盖请求发起到响应体读取完成;首次失败后的重试重新获得同样的 request deadline,整批并发策略、失败排空语义和 worker long-job 总预算不变。
|
||||
- 影响范围:`server-rs/crates/api-server/src/editor_project.rs`、`server-rs/crates/api-server/src/character_animation_assets.rs`、后端架构、开发运维和图片画布专题文档。
|
||||
@@ -135,6 +171,8 @@
|
||||
|
||||
## 2026-07-15 手动复杂去背景复用 BgFilter 单次重试
|
||||
|
||||
> 后续更正(2026-07-21):首次失败后再尝试一次、即同一次 complex 逻辑调用最多两次顺序 provider attempt 的语义保留,但重试所有权已迁入唯一 `bgfilter-worker`。父 `external-generation-worker` 至多让 worker 接收一次内部 HTTP RPC,不重试已被接收的 RPC(2026-07-23 起:连接从未建立的失败按调度方案 §5.1 有界重连,见当日决策条目);两次 provider attempt 都失败时,子 worker 把最终类型化错误返回父流程,complex 仍不接入 flat 的阿里云 / 本地 fallback。下文所称“worker 重试”按此边界理解。
|
||||
|
||||
- 背景:图片画布手动去背景已经改用 BgFilter `background_mode=complex`,但 worker 仍只发送一次上游请求,短暂网络抖动会直接让任务失败。
|
||||
- 决策:手动去背景的 complex 请求复用现有 `EDITOR_BGFILTER_RETRY_COUNT=1`,首次请求失败后立即重试一次,两次都失败仍返回最终错误;本次不把手动 complex 接入标准纯色背景链路的阿里云 / 本地兜底,也不改变 flat 路径的熔断状态。
|
||||
- 影响范围:图片画布手动去背景 worker、BgFilter complex 请求日志和 api-server 定向测试。
|
||||
@@ -169,6 +207,8 @@
|
||||
|
||||
## 2026-07-13 角色动作 BgFilter 全帧流水线与单次重试
|
||||
|
||||
> 后续更正(2026-07-23):本条「每次 BgFilter 调用失败后立即重试 1 次」与「不新增供应商进程锁或全局 Semaphore」已被 2026-07-21 起的唯一 `bgfilter-worker` 架构取代。重试所有权迁入子 worker:对一次逻辑调用最多两次顺序 provider attempt,provider 并发由 worker 进程内 `Semaphore(N)`(生产 `N=16`)约束;父侧不重试已被 worker 接收的内部 RPC,仅 TCP 连接从未建立的失败按调度方案 §5.1 有界重连(见 2026-07-23「BgFilter 父侧连接失败有界重连与冷启动宽限」条目)。全帧独立流水化、失败排空与整任务失败退款的语义保留。下文保留作历史记录。
|
||||
|
||||
- 背景:角色动作抽帧后原先固定 `buffered(3)`,并在整批绿幕源帧串行落 OSS 后才开始抠图;每帧还单独创建 HTTP Client。公网 BgFilter 的网络等待会让服务端推理队列出现空档,且首个最终错误会通过 `try_collect` 提前取消 api-server 中其余已发 Future。
|
||||
- 决策:BgFilter HTTP Client 在 `AppState` 中统一创建并复用 keep-alive 连接池;每次 BgFilter 调用失败后立即重试 `1` 次,两次都失败才进入既有“阿里云通用抠图 → 本地键色”降级链,每次已发失败调用都保留审计。角色动作全部 `32 / 40 / 48` 帧按“单帧绿幕源图落 OSS → BgFilter/降级 → 透明帧落 OSS”独立流水化,使用覆盖本次全部帧的 `buffer_unordered` 连续发射并携带原始帧序,完成后排序;不在 api-server 新增供应商进程锁或全局 Semaphore。任一帧最终失败时先排空全部已启动 Future,再让整个动作任务失败退款,不发布缺帧动画。
|
||||
- 影响范围:`server-rs/crates/api-server/src/state.rs`、`server-rs/crates/api-server/src/editor_project.rs`、`server-rs/crates/api-server/src/character_animation_assets.rs`、后端架构文档和图片画布技术文档。
|
||||
@@ -355,7 +395,7 @@
|
||||
|
||||
## 2026-07-03 图片画布生成纯色背景资产接入 BgFilter
|
||||
|
||||
> 后续更正:本条关于 multipart `file`、手动去背景独立 BiRefNet 配置以及 BgFilter 失败后直接本地兜底的描述,已分别由 2026-07-14、2026-07-15 OSS 签名 URL 决策和 2026-07-17 内存生命周期决策取代。下文保留作历史记录。
|
||||
> 后续更正:本条关于 multipart `file`、手动去背景独立 BiRefNet 配置以及 BgFilter 失败后直接本地兜底的描述,已分别由 2026-07-14、2026-07-15 OSS 签名 URL 决策和 2026-07-17 内存生命周期决策取代;其中固定 provider timeout 配置也已被 2026-07-21 的公式化双预算取代,当前请求分别携带 `maxQueueWaitMs / callBudgetMs`,attempt 按 `N × est × 2` 派生,冻结 `N=16 / est=5000ms` 时为 `160s`,调用预算为 `321s`。下文保留作历史记录。
|
||||
|
||||
- 背景:独立 BgFilter 服务已部署在 image host,并提供 `POST /bgfilter/remove-background`,支持显式 `screen_color` 和 `seg_model`。手动去背景已有独立 BiRefNet BFF,不能把两个服务的配置或语义混在一起。
|
||||
- 决策:角色形象生成、图标 spritesheet 生成和 UI 设计图素材提取在保存带纯色背景源图后,统一调用 BgFilter 生成透明 PNG;请求 multipart 字段为 `file`、`screen_color=<screenColor>` 和内部固定的 `seg_model=birefnet`。`segModel` 虽是后端可识别的内部兼容字段(另保留 `anime-seg`),但不向用户或外部 OpenAPI 暴露:当前 BgFilter 的内存与并发容量不适合由调用方自由切换模型。BgFilter 使用独立配置 `GENARRATIVE_EDITOR_BGFILTER_BASE_URL`、`GENARRATIVE_EDITOR_BGFILTER_TOKEN`、`GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS`,默认 base URL 为 `http://58.87.105.82/bgfilter`,默认请求超时 `180000ms`,token 未配置时复用 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN`。手动 `POST /api/editor/images/background-removals` 继续使用独立 BiRefNet 配置 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL`,不受 BgFilter 影响。BgFilter 参数里的 `seg_model=birefnet` 只表示 BgFilter 内部分割后端,不等于手动去背景的独立 BiRefNet 服务。若 BgFilter 失败,api-server 对这些标准纯色背景生成图使用本地 `editor_green_screen` 兜底;连续失败达到 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD`(默认 `3`)后,`GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS`(默认 `300`)内直接本地兜底。角色动作背景色和抠帧口径已由 2026-07-09 决策取代:角色动作同样使用多色自动决策,抽帧后优先阿里云通用抠图,失败再按选定背景色本地兜底。更正(截至 2026-07-10 实现):BgFilter 失败与熔断期本条描述的「直接本地兜底」已过时——角色形象/图标/UI 三条静态生图链路同样先走阿里云通用抠图,仅阿里云也失败才本地 `editor_green_screen` 兜底。
|
||||
@@ -1726,7 +1766,7 @@
|
||||
## 2026-05-30 Linux 本地 dev 端口段按系统级注册表分配
|
||||
|
||||
- 背景:同一台 Linux 开发机上有多个用户同时跑 `npm run dev` 时,单纯靠各自 `GENARRATIVE_DEV_PORT_RANGE` 容易撞段,且同一用户并发起两个 dev 会话时也会把相同端口段重复拿走。
|
||||
- 决策:Linux 上的本地 dev 端口段分配统一收口到系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json`,锁文件为 `/var/tmp/genarrative-dev-port-ranges/registry.lock`,可通过 `GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR` 覆盖目录。未手动指定时自动从 `10000-10099` 开始按 100 端口块分配,后续块按 `10100-10199`、`10200-10299` 递增;端口段映射固定为 `web = start`、`api = start + 1`、`spacetime = start + 2`、`admin-web = start + 3`;注册表会拒绝不同用户的相同或重叠段,并让同一用户后续启动继续复用自己已占用的固定段。`GENARRATIVE_DEV_PORT_RANGE` 与 `--port-range` 仍可手动指定端口段,但只在 Linux 生效,Windows 继续沿用原有端口探测与漂移逻辑,不读注册表。
|
||||
- 决策:Linux 上的本地 dev 端口段分配统一收口到系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json`,锁文件为 `/var/tmp/genarrative-dev-port-ranges/registry.lock`,可通过 `GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR` 覆盖目录。未手动指定时自动从 `10000-10099` 开始按 100 端口块分配,后续块按 `10100-10199`、`10200-10299` 递增;端口段最初映射为 `web = start`、`api = start + 1`、`spacetime = start + 2`、`admin-web = start + 3`,2026-07-21 按顶部 BgFilter 决策扩展 `bgfilter-worker = start + 4`;注册表会拒绝不同用户的相同或重叠段,并让同一用户后续启动继续复用自己已占用的固定段。`GENARRATIVE_DEV_PORT_RANGE` 与 `--port-range` 仍可手动指定端口段,但只在 Linux 生效,Windows 继续沿用统一端口探测与漂移逻辑,不读注册表。
|
||||
- 影响范围:`scripts/dev-stack-port-utils.mjs`、`scripts/dev.mjs`、`scripts/dev-stack-port-utils.test.ts`、`scripts/dev.test.ts`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`、本条决策记录、`development-workflow.md`。
|
||||
- 验证方式:`node --check scripts/dev-stack-port-utils.mjs`、`node --check scripts/dev.mjs`、`node node_modules/vitest/vitest.mjs run scripts/dev-stack-port-utils.test.ts scripts/dev.test.ts` 通过;Linux 下能看到 `[dev] port-range:` 与 `registry.json` 路径日志,自动分配从 `10000-10099` 起步,Windows 不出现注册表分配日志。
|
||||
- 关联文档:`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
@@ -4398,6 +4438,22 @@
|
||||
- 影响范围:`.gitea/workflows/project-ci.yml`、`deploy/container/gitea-ci-job.Dockerfile`、`scripts/gitea-ci-job-image.sh`、`scripts/check-gitea-ci-job-image.sh`、`scripts/check-gitea-ci-job-runtime.sh`、runner label/config 和 Gitea CI 运维文档。
|
||||
- 验证方式:构建脚本校验宿主与 runner 内层 Image ID 一致;环境脚本校验 Node、Rust、`rustfmt`、Chrome、bwrap、原生命令与 pkg-config 依赖;runtime 脚本执行完整 bwrap 和 Chrome headless canary;真实 PR 的四个 job 全部通过,同时复核 `Privileged=false`、`Binds=[]`、`MaskedPaths=[]`、`ReadonlyPaths=[]` 和独立网络。
|
||||
|
||||
## 2026-07-23 BgFilter 父侧连接失败有界重连与冷启动宽限
|
||||
|
||||
- 背景:主机重启或 worker 崩溃拉起期间,父侧对 loopback BgFilter worker 的 TCP 连接失败此前直接映射 `internal_error`:complex(队列 `max_attempts=1`)终态失败不可自愈,flat 被迫降级。systemd 层修复被否决——`After=` 在 `Type=simple` 下只提供进程启动排序,不构成「已监听」的 readiness 保证;而任何显式 readiness 交接(`Type=notify`、阻塞式 `ExecStartPost` 探活、socket activation 等)一旦成为 API / external worker 的启动硬依赖,都会把 BgFilter 故障扩大为整套服务不可启动。
|
||||
- 决策:仅对「TCP 连接从未建立」的失败(连接拒绝 / 不可达 / connect 阶段超时)做有界退避重连——这类请求从未进入 worker admission,无副作用、天然幂等;连接已建立后的任何失败(结果未知)与收到任何 HTTP 响应(含 5xx)维持原「不重试」禁令。每轮重连前按现有公式重算 `maxQueueWaitMs`,不突破「预算不足不发送」不变量。计量单位澄清:一次逻辑调用至多被 worker 接收一次 RPC,重连增加的只是连接尝试次数。
|
||||
- 冷启动宽限:重连配额按「本进程是否已连通过 worker」(收到任意 HTTP 响应即算,`AppState` 级标记)分档——冷启动档 flat 22.5s / complex 约 62.5s(覆盖开机竞态与慢开机),常规档 flat ≤1.5s(不侵蚀 39s fallback 预留)/ complex 22.5s(覆盖 `RestartSec=5s`+ 启动窗);档位单次调用内锁定。新增 `bgfilter_internal_connect_retry_total{mode}` 指标。
|
||||
- 平台差异(Windows 开发环境):连接已关闭的 loopback 端口不回 RST 而是挂到 connect timeout,错误呈现为 `deadline_exceeded` 且 `is_connect` 为真;重连判定只看 connect 分类,不看错误码。生产 Linux 即时拒绝,呈现 `internal_error`。
|
||||
- 安全不变量测试:除配额 / 跨窗 / deadline 地板路径外,专项覆盖「TCP 已 accept、未回任何 HTTP 字节即断开 → 不得发起第二次连接」,以 mock listener 的 accept 计数证明父侧未重连。
|
||||
- 影响范围:`server-rs/crates/api-server/src/bgfilter_worker.rs`、`state.rs`、`editor_project.rs`、调度方案 §5.1/§7/§9.3/§11、数据契约「BgFilter 连接复用、超时与动作帧流水线」条目、运维文档及各编辑器专题文档的旧禁令措辞统一改为「不重试已被 worker 接收的内部 RPC」。
|
||||
|
||||
## 2026-07-23 生产 API 发布按实际路径渲染 worker systemd unit
|
||||
|
||||
- 背景:Server-Provision 支持自定义 current link、API env 和角色 env,并在首次安装时渲染三个 worker unit;API deploy 为下发随 release 更新的 unit 又原样覆盖目标机配置,导致自定义路径在下一次发布时退回模板默认值。
|
||||
- 决策:`production-api-deploy.sh` 继续随 release 安装默认命名的 BgFilter、external-generation worker 和 controller unit,但安装前必须用本次部署参数渲染临时文件;新增 `--controller-env-file` 补齐 controller 专属 env 输入。release 内模板保持默认路径,供 provision 和 deploy 共同作为单一模板来源;自定义服务名仍由目标机自行管理,不强制覆盖。
|
||||
- 影响范围:`scripts/deploy/production-api-deploy.sh`、`scripts/check-production-api-deploy.mjs`、`jenkins/Jenkinsfile.production-api-deploy`、`jenkins/Jenkinsfile.production-full-build-and-deploy`、`scripts/check-production-ops-guardrails.mjs`、生产运维文档和 worker systemd 发布契约。
|
||||
- 验证方式:`bash -n scripts/deploy/production-api-deploy.sh`、`node --check scripts/check-production-api-deploy.mjs`、`npm run check:production-api-deploy`、`npm run check:production-ops`、`npm run check:encoding`、`git diff --check`。
|
||||
|
||||
## 2026-07-23 Gitea CI 镜像刷新到 SpacetimeDB 2.7.0 锁
|
||||
|
||||
- 背景:`server-rs/Cargo.lock` 已从镜像预热时的 SpacetimeDB 2.6.1 前移到 2.7.0,runtime 校验因此报告 `server_rust_cache_lock=partial`。受控 Cargo egress proxy 连续返回 CONNECT tunnel 502 时,Backend job 在 `check:module-runtime-artifact` 依赖解析阶段失败,尚未进入 workspace tests。
|
||||
|
||||
@@ -51,18 +51,19 @@ npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Linux 多用户共享同一台机器开发时,本地 dev 脚本会为当前 Linux 用户分配一个固定端口段并写入系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json`,自动分配从 `10000-10099` 开始,每段 100 个端口,四个 dev 服务依次使用 `start` 到 `start + 3`。可用 `GENARRATIVE_DEV_PORT_RANGE` 或 `npm run dev -- --port-range` 手动指定端口段用于特殊场景;注册表会阻止不同用户使用相同或重叠段,并让同一用户后续启动继续复用自己已占用的固定段。该机制只在 Linux 生效,Windows 仍沿用原有端口探测与漂移逻辑。
|
||||
Linux 多用户共享同一台机器开发时,本地 dev 脚本会为当前 Linux 用户分配一个固定端口段并写入系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json`,自动分配从 `10000-10099` 开始,每段 100 个端口,五个 dev 服务依次使用 `start` 到 `start + 4`,其中 BgFilter worker 固定为 `start + 4`。可用 `GENARRATIVE_DEV_PORT_RANGE` 或 `npm run dev -- --port-range` 手动指定端口段用于特殊场景;注册表会阻止不同用户使用相同或重叠段,并让同一用户后续启动继续复用自己已占用的固定段。该机制只在 Linux 生效,Windows 把第五个服务纳入原有统一端口探测与漂移逻辑。
|
||||
|
||||
本地 `npm run dev`、`npm run dev:spacetime` 和 `npm run dev:api-server` 会在 Rust 子进程环境中绕过项目默认 `sccache` wrapper,避免损坏的本机 cache daemon 阻断 `spacetime publish` 或 `api-server` 启动;显式设置的非 sccache 自定义 wrapper 会被保留。生产 / Jenkins 构建仍按流水线自身的 sccache 策略执行。
|
||||
本地 `npm run dev`、`npm run dev:spacetime`、`npm run dev:api-server` 和 `npm run dev:bgfilter-worker` 会在 Rust 子进程环境中绕过项目默认 `sccache` wrapper,避免损坏的本机 cache daemon 阻断 `spacetime publish` 或 Rust 服务启动;显式设置的非 sccache 自定义 wrapper 会被保留。生产 / Jenkins 构建仍按流水线自身的 sccache 策略执行。
|
||||
|
||||
该命令会启动:
|
||||
|
||||
- SpacetimeDB standalone
|
||||
- 独立 `bgfilter-worker`
|
||||
- Rust `api-server`
|
||||
- 主站 Vite
|
||||
- 后台 Vite
|
||||
|
||||
`npm run dev` 和单模块 `dev:*` 命令会更新根目录 `.app/dev-stack.json`,记录四个本地服务的 pid、端口、URL、启动状态和当前命令。该目录只作本机运行态观测,不提交 Git。
|
||||
`npm run dev` 和单模块 `dev:*` 命令会更新根目录 `.app/dev-stack.json`,记录五个本地服务的 pid、端口、URL、启动状态和当前命令。该目录只作本机运行态观测,不提交 Git。
|
||||
|
||||
开启自动刷新:
|
||||
|
||||
@@ -70,9 +71,9 @@ Linux 多用户共享同一台机器开发时,本地 dev 脚本会为当前 Li
|
||||
npm run dev -- --watch
|
||||
```
|
||||
|
||||
watch 模式只由外层调度器自动处理后端侧刷新:`spacetime-module` 改动后重新发布模块但不重启 standalone 宿主,`api-server` 改动后重启 Rust 进程。主站 Vite 与后台 Vite 的源码变化交给 Vite 自身 HMR,避免外层 watcher 监听到依赖缓存或临时文件后循环重启。
|
||||
watch 模式只由外层调度器自动处理后端侧刷新:`spacetime-module` 改动后重新发布模块但不重启 standalone 宿主;完整栈和 `dev:api-server` 只创建一套 Rust watcher,改动后先停止 API 与 BgFilter worker,再先启动并验活 worker、最后启动并验活 API。主站 Vite 与后台 Vite 的源码变化交给 Vite 自身 HMR,避免外层 watcher 监听到依赖缓存或临时文件后循环重启。
|
||||
|
||||
非 watch 模式下,`npm run dev` 终端支持输入 `rs spacetime`、`rs api-server`、`rs web`、`rs admin-web` 或 `rs all`。其中 `rs spacetime` 只会重新发布 `spacetime-module`,不会重启 standalone 宿主;其他模块仍按进程重启。
|
||||
非 watch 模式下,`npm run dev` 终端支持输入 `rs spacetime`、`rs api-server`、`rs bgfilter-worker`、`rs web`、`rs admin-web` 或 `rs all`。其中 `rs spacetime` 只会重新发布 `spacetime-module`,不会重启 standalone 宿主;重启任一 Rust 角色都会走 API / BgFilter worker 组合重启。
|
||||
|
||||
单独启动 SpacetimeDB:
|
||||
|
||||
@@ -86,6 +87,12 @@ npm run dev:spacetime
|
||||
npm run dev:api-server
|
||||
```
|
||||
|
||||
该命令会由同一 runner 自动带起独立 BgFilter worker,确保共享实际内部 base URL 和 Token。只单独启动内部 worker 时使用:
|
||||
|
||||
```bash
|
||||
npm run dev:bgfilter-worker
|
||||
```
|
||||
|
||||
单独启动前端:
|
||||
|
||||
```bash
|
||||
@@ -107,7 +114,7 @@ npm run server-manager:panel
|
||||
该命令启动 `server-rs/crates/server-manager-panel` 的 egui 桌面工具,从本机 `~/.ssh/config` 读取可用 `Host` alias,支持多服务器健康巡检、可折叠侧边栏和受控 systemd 服务启停。服务操作通过远端 `sudo -n systemctl start|stop|restart <unit>` 执行,目标服务器需要提前配置对应 unit 的免交互 sudo 权限。
|
||||
面板启动时会自动注入本机中文字体;如开发机中文仍显示为方块,可设置 `GENARRATIVE_SERVER_PANEL_CJK_FONT=/path/to/font.ttc|index` 指向本机 CJK 字体。
|
||||
|
||||
`npm run dev:api-server` 会保留终端实时输出,并把同一份输出持久化到 `logs/api-server/api-server-<timestamp>.log`。完整联调入口 `npm run dev` 启动的 Rust `api-server` 使用同一套日志规则。如需改写路径,可设置 `GENARRATIVE_API_SERVER_LOG_FILE`;如只改目录,可设置 `GENARRATIVE_API_SERVER_LOG_DIR`。
|
||||
`npm run dev:api-server` 会保留终端实时输出,并把 API 输出持久化到 `logs/api-server/api-server-<timestamp>.log`、BgFilter worker 输出持久化到 `logs/bgfilter-worker/bgfilter-worker-<timestamp>.log`。完整联调入口 `npm run dev` 使用同一套日志规则。API 日志可通过 `GENARRATIVE_API_SERVER_LOG_FILE` / `GENARRATIVE_API_SERVER_LOG_DIR` 改写,worker 日志可通过 `GENARRATIVE_BGFILTER_WORKER_LOG_FILE` / `GENARRATIVE_BGFILTER_WORKER_LOG_DIR` 改写。
|
||||
|
||||
开发态 `npm run dev` / `npm run dev:api-server` 默认打开 `GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED=true`,密码入口可以直接注册未知手机号账号;生产默认仍关闭该开关。
|
||||
|
||||
@@ -266,7 +273,7 @@ npm run check:server-rs-ddd
|
||||
|
||||
- 仓库 CI 入口是 `.gitea/workflows/project-ci.yml`,向 `master`、`codex/ai-game-creator-app` 推送和所有 PR 创建、更新时必须运行,也允许手工触发。
|
||||
- CI 固定拆分为 `Repository checks`、`Frontend tests`、`Backend tests`、`Native shell tests` 四个 required job;对应 PR context 完整名称是 `Project CI / Repository checks (pull_request)`、`Project CI / Frontend tests (pull_request)`、`Project CI / Backend tests (pull_request)`、`Project CI / Native shell tests (pull_request)`,首次运行后仍须从 Gitea 最近一周 context 表复核。测试使用独立 job,不能只藏在综合检查 step 中;原生壳验收单独运行以便定位重型构建失败。
|
||||
- 四个 job 共同覆盖 `npm run check`,并追加 `npm run check:server-rs-ddd`、`cargo test --locked --workspace --no-fail-fast --manifest-path server-rs/Cargo.toml`、`cargo check -p api-server --all-targets --manifest-path server-rs/Cargo.toml` 和 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`。`ffmpeg` 由预构建 job 镜像提供,避免视频抽帧测试因工具缺失提前返回。`codex/ai-game-creator-app` 分支的原生壳入口还必须覆盖 `npm run ai-game-creator-shell:check` 和 release build smoke。
|
||||
- 四个 job 共同覆盖 `npm run check`,并追加 `npm run bgfilter-worker:smoke-test`、`npm run check:production-health-patrol`、`npm run check:production-api-release`、`npm run check:production-api-deploy`、`npm run check:server-rs-ddd`、`cargo test --locked --workspace --no-fail-fast --manifest-path server-rs/Cargo.toml`、`cargo check -p api-server --all-targets --manifest-path server-rs/Cargo.toml` 和 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`。BgFilter 的 `.test.mjs` 使用 Node test runner,必须由 workflow 显式调用;生产巡检 / 发布 / 部署行为检查只运行无密钥临时 fixture,不连接现场环境。`ffmpeg` 由预构建 job 镜像提供,避免视频抽帧测试因工具缺失提前返回。`codex/ai-game-creator-app` 分支的原生壳入口还必须覆盖 `npm run ai-game-creator-shell:check` 和 release build smoke。
|
||||
- checkout 必须使用完整历史。PR 将 base SHA 写入 `SPACETIME_SCHEMA_BASE_REF`,直接推送 `master` 使用 before SHA;事件基线不可解析时直接失败。Gitea 检查的是 PR head 而非预合并 commit,workflow 必须拒绝不包含最新 base commit 的过期 PR,分支保护同时保持“PR 过期禁止合并”。
|
||||
- 普通 PR job 不读取业务 secret,不运行真实 API/SpacetimeDB/OSS/支付/生成/live smoke,也不执行会修改外部状态的维护、迁移、发布或备份命令。
|
||||
- Gitea 至少升级到 `1.26.4` 后才能注册执行 PR job 的 runner。runner 保留 `ubuntu-latest` 固定 digest 映射,并把 workflow 使用的 `genarrative-ci` 映射到 runner 内层 Docker 已装入的完整 Image ID;不映射 host,不向 job 暴露 Docker socket、业务 secret 或不必要内网。当前 CI 镜像约 `1.788 GB`,Image ID 为 `sha256:c04b114b1f145072c9df7842c4c974e1bb2eaaf391d95d84c9212a460546b7d5`,标签映射为 `genarrative-ci:docker://sha256:c04b114b1f145072c9df7842c4c974e1bb2eaaf391d95d84c9212a460546b7d5`。内层 Docker 数据持久化且 `force_pull: false`,该 ID 缺失时失败关闭,不现场拉取或回退浮动 tag。Runner 2.0.0 支持 job 级 `timeout-minutes`,但 runner 全局 `3h` 仍是硬上限;首次运行成功后,`master` 分支保护必须要求上述四个 job 全部成功。
|
||||
|
||||
@@ -3296,6 +3296,14 @@
|
||||
- 原因:单 attempt timeout、重试退避、图片下载与 worker / lease 分别使用独立的相对计时,没有共享同一绝对 deadline;只抬高 worker timeout 或单独压低 provider timeout 都无法保证留出终态写回窗口。
|
||||
- 处理:实际调用 VectorEngine 的四类图片 job 使用 `1800s` long 预算;从 job 开始的同一起点派生 provider deadline,常规提前 `60s`、短预算提前一半。每次 attempt、退避、下一次 attempt 和图片下载都必须在该 deadline 内;普通 HTTP / `inline` 不伪造 worker deadline。修复时不改动 lease fencing、迟到写回仲裁和原子退款语义。
|
||||
|
||||
## 同一 Rust 二进制的本地双进程不能各自并发 watch 重启(2026-07-21)
|
||||
|
||||
- 现象:本地把 `api-server` 与独立 `bgfilter-worker` 都用 `cargo run -p api-server` 启动后,一次 Rust 源码变更触发两套 watcher 并发停止、编译和链接;Windows 常因另一个实例仍占用 `api-server.exe` 而链接失败,或出现 API 已恢复但内部 worker 尚未 ready 的半更新状态。
|
||||
- 原因:两个进程角色共享同一 crate、target 和可执行文件,却被错误地当成两个互不相关的 dev service。更危险的是先启动 `GENARRATIVE_PROCESS_ROLE=all` 的 API:它会立即消费外部生成队列,可能在内部 BgFilter worker 尚未 ready 时领取任务。
|
||||
- 处理:`npm run dev` 与 `npm run dev:api-server` 只创建一套 Rust watcher,并把两个进程作为组合重启单元:先停止 API 与 BgFilter worker,再只让 worker 的 `cargo run` 完成必要构建,等待 worker `/readyz`,最后启动并验活 API。交互 `rs api-server`、`rs bgfilter-worker` 在完整栈内也必须走同一组合重启。`ProcessRole::All` 永远不内嵌 BgFilter listener;父子进程共享解析后的内部 base URL / Token,Linux 第五端口固定为端口段 `start + 4`,Windows 把第五端口纳入统一探测和漂移。
|
||||
- 验证:定向测试断言组合重启顺序为“stop API → stop worker → start/ready worker → start/ready API”,`dev:api-server` 自动带起同 runner worker,端口解析得到五个互不冲突的端口;再运行 `node --check scripts/dev.mjs`、dev-stack 定向测试和编码检查。
|
||||
- 关联:`scripts/dev.mjs`、`scripts/dev-stack-port-utils.mjs`、`.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
|
||||
## Gitea PR runner 不能把宿主 Docker socket 当普通 volume
|
||||
|
||||
- 现象:`act_runner` 的 `container.docker_host` 留空时,job inspect 会出现 `/var/run/docker.sock:/var/run/docker.sock`;PR 脚本即使 `valid_volumes: []`,仍可直接调用 Docker API 读取其它容器、挂宿主目录或取得 runner 配置。另一类迁移故障是 rootless daemon 可以启动,但 bwrap 在 job 内报 `No permissions to create new namespace`、`Failed to make / slave` 或 `Mount too revealing`。
|
||||
@@ -3332,6 +3340,14 @@
|
||||
- 重启边界:`docker restart --timeout 660` 只设置容器停止宽限,不能替代 Runner drain。rootless DinD supervisor 可能与 runner 同时停止内层 dockerd,使仍在收尾的 job 因连接关闭被标记失败;切换前必须同时确认 Gitea 没有 `in_progress` run 且内层 `docker ps` 为空。误触发时只重跑受影响的失败 job,不重跑已成功项。
|
||||
- 关联:`deploy/container/README.md`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`、`docs/project-memory/shared-memory/development-workflow.md`。
|
||||
|
||||
## 生产 API 发布重装 worker unit 不能丢失自定义路径(2026-07-23)
|
||||
|
||||
- 现象:Server-Provision 已按自定义 current link 和 env 路径安装 worker systemd unit,但下一次 API 发布后,worker 可能重新读取 `/opt/genarrative/current` 与 `/etc/genarrative/*.env`;默认路径仍有旧 release 时,服务 active 和部署成功都不能证明新二进制已运行。
|
||||
- 原因:发布包中的 BgFilter、external-generation worker 和 controller unit 是带默认路径的模板;deploy 若直接 `install` 原文件,会覆盖 provision 已渲染的目标机 unit。external-generation 专属 env 还是可选加载,错误路径可能不会阻止服务进入 active。
|
||||
- 处理:API deploy 安装三个 unit 前必须按本次 current、API env 和各角色 env 参数渲染临时文件,安装后保留 release 内原始模板不变;controller 自定义 env 由 `--controller-env-file` 显式传入。API Deploy 与 Full Job 必须同步暴露并透传 controller/BgFilter env,不能让流水线回退默认路径。自定义服务名表示沿用目标机自管 unit,不进入默认 unit 安装分支。
|
||||
- 验证:部署 guard 使用临时自定义绝对路径,直接读取实际安装目录中的三个 unit,核对 `WorkingDirectory`、`ExecStart`、共享 API env 与角色 env,不能只用 fake `systemctl is-active` 判绿。
|
||||
- 关联:`scripts/deploy/production-api-deploy.sh`、`scripts/check-production-api-deploy.mjs`、`scripts/jenkins-server-provision.sh`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
|
||||
## 通用灰度后台页不能依赖已退役业务配置
|
||||
|
||||
- 现象:通用 `feature_gate_config`、`/admin/api/feature-gates` 和现役功能 gate 仍在,但后台“灰度发布”Tab 随旧创作模板入口一起消失;Rust 权限仍可授予 `gray-release`,前端却没有对应路由。
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,9 @@
|
||||
|
||||
> 2026-07-18 退役覆盖:旧创作模板 job 类型、玩法写回和玩法恢复链路均已退出现役 worker。当前 worker 只领取 `source_module = editor-canvas` 的任务;本文涉及拼图、跳一跳、拼消消、敲木鱼等玩法的内容仅作为历史设计记录,历史队列行不得被领取或改写。
|
||||
|
||||
更新时间:`2026-07-15`
|
||||
> 2026-07-21 已实施、待生产压测专题:BgFilter 作为受限内部资源,仍遵守“单用户动作一个外部生成 job”;用户可见层与调度层都只有父 `external_generation_job`。父 future 保持原 lease 和 attempt,在当前调用栈内同步请求唯一 `bgfilter-worker` 的内部 HTTP,成功图片字节直接返回父流程。首版不新增 SpacetimeDB 子任务表、父 checkpoint / continuation 或 raw 中间结果 OSS。完整边界见 [`BgFilter 受限资源调度方案(同步内部 HTTP 原地等待版)`](./【后端架构】BgFilter受限资源调度方案-2026-07-21.md)。
|
||||
|
||||
更新时间:`2026-07-21`
|
||||
|
||||
## 背景
|
||||
|
||||
@@ -192,7 +194,7 @@ controller 配置:
|
||||
|
||||
- `editor_image_generation`:普通图片、生成规范、角色形象、UI 设计图、宣发素材和图片快速编辑。
|
||||
- `editor_image_edit`:图片编辑 / 修改结果。
|
||||
- `editor_background_removal`:手动去除任意图片背景,worker 使用 BgFilter complex 模式、首次失败后重试 `1` 次,并把执行阶段标记为 `processing`。
|
||||
- `editor_background_removal`:手动去除任意图片背景,父 `external-generation-worker` 至多让 worker 接收一次内部 HTTP RPC(连接从未建立时按调度方案 §5.1 有界重连)并把执行阶段标记为 `processing`;唯一 `bgfilter-worker` 使用 BgFilter complex 模式,对同一次逻辑调用最多执行两次顺序 provider attempt,两次都失败时把类型化错误返回父流程。
|
||||
- `editor_icon_spritesheet_generation`:图标素材 spritesheet 生成和拆分。
|
||||
- `editor_ui_design_asset_extraction`:UI 设计图红框素材提取。
|
||||
- `editor_character_animation_generation`:角色动作视频和帧素材生成。
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -28,7 +28,7 @@
|
||||
- 支持自定义画面比例和大小尺寸。
|
||||
- 模型固定为 `gpt-image-2`,模型展示对齐角色规范面板底部固定模型样式,不响应点击、不弹出模型切换菜单;历史草稿如果残留其他模型,提交时也必须强制改为 `gpt-image-2`。
|
||||
- 默认画面比例为 `16:9`,默认大小为 `1K`。
|
||||
- UI 素材提取面板不展示抠图背景色或抠图模型选择;前端用户路径固定提交 `screenColor=auto` 和 `segModel=birefnet`。后端先在 12 个候选色中自动决策具体 hex,最多重试 3 次,失败兜底 `#CFEFFF`;后端调用 BgFilter 时只把解析后的具体 hex 作为 `screen_color` 传入。后端仍识别内部保留的 `anime-seg`,但该选项不对用户可见。
|
||||
- UI 素材提取面板不展示抠图背景色或抠图模型选择;前端用户路径固定提交 `screenColor=auto` 和 `segModel=birefnet`。后端先在 12 个候选色中自动决策具体 hex,最多重试 3 次,失败兜底 `#CFEFFF`;父流程请求唯一 loopback `bgfilter-worker` 时只把解析后的具体 hex 作为 `screenColor` 参数传入。后端仍识别内部保留的 `anime-seg`,但该选项不对用户可见。
|
||||
|
||||
## 提示词契约
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用后端自动决策出的抠图背景色。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。
|
||||
```
|
||||
|
||||
- 后端收到 spritesheet 后先把带解析后纯色背景的源图 owned 上传私有 OSS(消费图片字节所有权,上传完成后释放原图缓冲,不克隆保留),写入项目资源和账号素材库;随后只持 object key。每次 BgFilter attempt 重新签发 600 秒 GET URL,multipart 固定传 `image_url`、`screen_color=<screenColor>`、`seg_model=<segModel>`、`background_mode=flat` 和 `cross_check=off`,不包含 `file`,默认 `segModel=birefnet`。BgFilter 主路径不重新下载原图;首次失败后立即重试 `1` 次(重试同样重新换签),第二次仍失败进入“阿里云通用抠图(按签名 URL 单独下载)→ 本地键色(再按 object key 独立下载一次原图并在产出后释放)”降级链。透明背景处理正常成功时,透明 spritesheet 同样先进入 OSS、项目资源和账号素材库,再复用图标素材的连通域拆分能力;调用方未指定素材文件夹时落默认“项目”文件夹。透明背景处理最终失败、但 provider 原图已经持久化时,任务以 `completed + warning` 收口,只把 provider 原图作为唯一主图放入画布,`generatedLayerId` 指向原图,不创建透明图集,也不继续拆分。该收口只捕获透明背景处理本身的最终失败;phase 上报、provider 原图持久化、透明处理图持久化和 `canvasCompletion` 写回错误仍正常传播,不能被原图降级吞掉。
|
||||
- 父流程收到 spritesheet 后先把带解析后纯色背景的源图 owned 上传私有 OSS(消费图片字节所有权,上传完成后释放原图缓冲,不克隆保留),写入项目资源和账号素材库;随后只持 object key,并仅向同机唯一 loopback `bgfilter-worker` 发起一次内部 HTTP RPC,请求中的源图只以 object key 传递,并附带 BgFilter 参数、排队预算 `maxQueueWaitMs`、调用预算 `callBudgetMs` 和有界审计关联,父流程不签发 BgFilter URL、不直连 provider,也不重试已被 worker 接收的内部 RPC(连接从未建立时按调度方案 §5.1 有界重连)。子 worker 在 `Q` admission 和 `Semaphore(N)` 约束下执行这次逻辑调用;排队只消耗 `maxQueueWaitMs`,取得 provider permit 后才启动 `callBudgetMs`。每次 provider attempt 前重新签发 600 秒 GET URL,multipart 固定传 `image_url`、`screen_color=<screenColor>`、`seg_model=<segModel>`、`background_mode=flat` 和 `cross_check=off`,不包含 `file`,并在调用预算内最多执行两次顺序 attempt,默认 `segModel=birefnet`。成功时,子 worker 通过内部 HTTP 二进制 body 把经过校验的图片字节直接返回父流程,不持久化中间结果;BgFilter 最终失败且父业务预算仍有效时,由父流程进入“阿里云通用抠图(按签名 URL 单独下载)→ 本地键色(再按 object key 独立下载一次原图并在产出后释放)”降级链。透明背景处理正常成功时,父流程把透明 spritesheet 写入 OSS、项目资源和账号素材库,再复用图标素材的连通域拆分能力;调用方未指定素材文件夹时落默认“项目”文件夹。BgFilter 与父侧 fallback 最终均失败、但 provider 原图已经持久化时,任务以 `completed + warning` 收口,只把 provider 原图作为唯一主图放入画布,`generatedLayerId` 指向原图,不创建透明图集,也不继续拆分。该收口只捕获透明背景处理本身的最终失败;phase 上报、provider 原图持久化、透明处理图持久化和 `canvasCompletion` 写回错误仍正常传播,不能被原图降级吞掉。最终透明结果及拆分切片的 OSS / 资源 / 画布持久化仍全部由父流程负责。
|
||||
- UI 素材自动拆分只在透明图集成功后执行,与图标图集一致,属于 best-effort 附加动作。未知素材数量时按从上到下、从左到右自动命名为 `素材 1`、`素材 2`;识别或切片持久化失败仍返回整张透明图集和 `sliceWarning`,前端显示非阻断 warning toast,用户可手动重试。`sliceWarning` 与透明背景最终失败使用的通用 `warning` 互斥,前者只表示透明图集成功但自动拆分失败,`sliceWarning.reason` 原始契约保持不变。
|
||||
- 正常透明化成功时,前端先把透明 spritesheet 作为 `assetKind: "icon-spritesheet"` 图集图层放在 UI 设计图右侧,再把拆分成功的独立素材作为 `assetKind: "icon"` 图标图层继续放到画布;透明背景处理最终失败时只消费后端快照中的 provider 原图。透明图集图层提供 `拆分图集` 工具栏按钮,可使用相同连通域规则重新拆分。
|
||||
|
||||
|
||||
@@ -59,8 +59,8 @@
|
||||
|
||||
## 去背与保存
|
||||
|
||||
- 后端收到 spritesheet 后先把带解析后纯色背景的源图写入私有 OSS,并在上传完成后释放原图缓冲,再签发 600 秒 GET URL 调用 BgFilter 透明化;BgFilter multipart 固定传 `image_url`、`screen_color=<screenColor>`、`seg_model=<segModel>`、`background_mode=flat` 和 `cross_check=off`,不包含 `file`。前端用户路径固定提交 `screenColor=auto` 与默认 `segModel=birefnet`,后端仍识别内部保留的 `anime-seg`,但这些内部参数不对用户可见。
|
||||
- 透明背景处理正常成功时,带背景原图和去背后的透明 spritesheet 都先写入 OSS、项目资源和账号素材库,再按 alpha 连通域和素材描述顺序执行附加拆分;若 BgFilter 返回较小图集,只把 alpha 蒙版重采样到 provider 原图尺寸并应用回原始高分辨率 RGB,不放大低分辨率后处理成品。画布完成快照同时写入透明主图与右侧 provider 原图(二者均已登记为 project resource / 账号素材),`generatedLayerId` 仍锚定透明主图;成功拆出的切片从 provider 原图右侧继续排列。调用方未指定素材文件夹时统一落默认“项目”文件夹。每个成功切片单独写入 OSS、项目资源和账号素材库,`sourceResourceId` 指向透明图集资源。透明背景处理最终失败、但 provider 原图已经持久化时,任务以 `completed + warning` 收口,只把 provider 原图作为唯一主图放入画布,`generatedLayerId` 指向原图,不创建透明图集,也不继续拆分,`iconImageSrcs=[]`。该收口只捕获透明背景处理本身的最终失败;phase 上报、provider 原图持久化、透明处理图持久化和 `canvasCompletion` 写回错误仍正常传播,不能被原图降级吞掉。
|
||||
- 父流程收到 spritesheet 后先把带解析后纯色背景的源图写入私有 OSS,并在上传完成后释放原图缓冲;随后只持 object key,并仅向同机唯一 loopback `bgfilter-worker` 发起一次内部 HTTP RPC,请求中的源图只以 object key 传递,并附带 BgFilter 参数、排队预算 `maxQueueWaitMs`、调用预算 `callBudgetMs` 和有界审计关联,父流程不签发 BgFilter URL、不直连 provider,也不重试已被 worker 接收的内部 RPC(连接从未建立时按调度方案 §5.1 有界重连)。子 worker 在 `Q` admission 和 `Semaphore(N)` 约束下执行这次逻辑调用;排队只消耗 `maxQueueWaitMs`,取得 provider permit 后才启动 `callBudgetMs`。每次 provider attempt 前重新签发 600 秒 GET URL,multipart 固定传 `image_url`、`screen_color=<screenColor>`、`seg_model=<segModel>`、`background_mode=flat` 和 `cross_check=off`,不包含 `file`,并在调用预算内最多执行两次顺序 attempt。前端用户路径固定提交 `screenColor=auto` 与默认 `segModel=birefnet`,后端仍识别内部保留的 `anime-seg`,但这些内部参数不对用户可见。成功时,子 worker 通过内部 HTTP 二进制 body 把经过校验的图片字节直接返回父流程,不持久化中间结果;BgFilter 最终失败且父业务预算仍有效时,由父流程进入“阿里云通用抠图(按签名 URL 单独下载)→ 本地键色(再按 object key 独立下载一次原图并在产出后释放)”降级链。
|
||||
- 透明背景处理正常成功时,父流程把带背景原图和去背后的透明 spritesheet 写入 OSS、项目资源和账号素材库,再按 alpha 连通域和素材描述顺序执行附加拆分;若 BgFilter 返回较小图集,只把 alpha 蒙版重采样到 provider 原图尺寸并应用回原始高分辨率 RGB,不放大低分辨率后处理成品。画布完成快照同时写入透明主图与右侧 provider 原图(二者均已登记为 project resource / 账号素材),`generatedLayerId` 仍锚定透明主图;成功拆出的切片从 provider 原图右侧继续排列。调用方未指定素材文件夹时统一落默认“项目”文件夹。每个成功切片单独写入 OSS、项目资源和账号素材库,`sourceResourceId` 指向透明图集资源。BgFilter 与父侧 fallback 最终均失败、但 provider 原图已经持久化时,任务以 `completed + warning` 收口,只把 provider 原图作为唯一主图放入画布,`generatedLayerId` 指向原图,不创建透明图集,也不继续拆分,`iconImageSrcs=[]`。该收口只捕获透明背景处理本身的最终失败;phase 上报、provider 原图持久化、透明处理图持久化和 `canvasCompletion` 写回错误仍正常传播,不能被原图降级吞掉。最终透明结果及切片的 OSS / 资源 / 画布持久化仍全部由父流程负责。
|
||||
- 自动拆分只在透明图集成功后执行,属于 best-effort 附加动作,不参与图集生成的成功判定。连通域识别或切片持久化失败时,接口仍返回并回填整张透明图集,`iconImageSrcs=[]`,并通过 `sliceWarning.code/reason` 暴露非阻断原因;`sliceWarning` 与透明背景最终失败使用的通用 `warning` 互斥,前者只表示透明图集成功但自动拆分失败,`sliceWarning.reason` 原始契约保持不变。前端在 inline、worker 队列完成和刷新恢复三条路径统一显示对应 warning toast,用户可在图集工具栏手动重试。
|
||||
- 响应通过 `iconImageSrcs` 返回成功切片素材;自动生成使用用户输入的素材描述命名,UI 设计提取和手动拆分按从上到下、从左到右自动命名为 `素材 N`。
|
||||
- 手动拆分调用 `POST /api/editor/icon-spritesheets/slices`,只允许读取当前用户项目中的 `icon-spritesheet` 资源,不调用图片生成 provider,不扣除泥点。输入限制为单边最多 `4096` 像素、总像素最多 `2048×2048`,单次最多持久化 `64` 个切片;超限在任何切片写入前拒绝。
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -24,6 +24,8 @@ pipeline {
|
||||
string(name: 'HEALTH_URL', defaultValue: 'http://127.0.0.1:8082/readyz', description: '本机 readiness 检查地址')
|
||||
string(name: 'API_ENV_FILE', defaultValue: '/etc/genarrative/api-server.env', description: 'api-server 环境文件')
|
||||
string(name: 'WORKER_ENV_FILE', defaultValue: '/etc/genarrative/external-generation-worker.env', description: '外部生成 worker 环境文件')
|
||||
string(name: 'CONTROLLER_ENV_FILE', defaultValue: '/etc/genarrative/external-generation-controller.env', description: '外部生成 controller 环境文件')
|
||||
string(name: 'BGFILTER_WORKER_ENV_FILE', defaultValue: '/etc/genarrative/bgfilter-worker.env', description: 'BgFilter worker 环境文件')
|
||||
string(name: 'DATABASE', defaultValue: 'genarrative-prod', description: 'api-server 连接的 SpacetimeDB database')
|
||||
string(name: 'SPACETIME_SERVER_URL', defaultValue: 'http://127.0.0.1:3101', description: 'api-server 连接的 SpacetimeDB server URL')
|
||||
}
|
||||
@@ -53,7 +55,7 @@ pipeline {
|
||||
if (!(params.DATABASE.trim() ==~ /^[a-z0-9]+(-[a-z0-9]+)*$/)) {
|
||||
error("DATABASE 必须匹配 ^[a-z0-9]+(-[a-z0-9]+)*\$: ${params.DATABASE}")
|
||||
}
|
||||
[API_ENV_FILE: params.API_ENV_FILE, WORKER_ENV_FILE: params.WORKER_ENV_FILE].each { name, value ->
|
||||
[API_ENV_FILE: params.API_ENV_FILE, WORKER_ENV_FILE: params.WORKER_ENV_FILE, CONTROLLER_ENV_FILE: params.CONTROLLER_ENV_FILE, BGFILTER_WORKER_ENV_FILE: params.BGFILTER_WORKER_ENV_FILE].each { name, value ->
|
||||
def envFile = value?.trim()
|
||||
if (!envFile || envFile == '/' || !(envFile ==~ /^\/(?!.*\.\.)[A-Za-z0-9._\/-]+$/)) {
|
||||
error("${name} 必须是 Linux 绝对路径且不能包含 ..: ${envFile}")
|
||||
@@ -117,6 +119,8 @@ pipeline {
|
||||
--health-url "${HEALTH_URL}" \
|
||||
--api-env-file "${API_ENV_FILE:-/etc/genarrative/api-server.env}" \
|
||||
--worker-env-file "${WORKER_ENV_FILE:-/etc/genarrative/external-generation-worker.env}" \
|
||||
--controller-env-file "${CONTROLLER_ENV_FILE:-/etc/genarrative/external-generation-controller.env}" \
|
||||
--bgfilter-worker-env-file "${BGFILTER_WORKER_ENV_FILE:-/etc/genarrative/bgfilter-worker.env}" \
|
||||
--database "${DATABASE}" \
|
||||
--spacetime-server-url "${SPACETIME_SERVER_URL:-http://127.0.0.1:3101}"
|
||||
'
|
||||
|
||||
@@ -41,6 +41,8 @@ pipeline {
|
||||
string(name: 'SPACETIME_RUN_AS_USER', defaultValue: 'spacetimedb', description: 'Stdb 发布使用的本机用户')
|
||||
string(name: 'API_ENV_FILE', defaultValue: '/etc/genarrative/api-server.env', description: 'API 与 Stdb publish 共用的 api-server 环境文件')
|
||||
string(name: 'WORKER_ENV_FILE', defaultValue: '/etc/genarrative/external-generation-worker.env', description: 'API 与 Stdb publish 共用的 worker 环境文件')
|
||||
string(name: 'CONTROLLER_ENV_FILE', defaultValue: '/etc/genarrative/external-generation-controller.env', description: 'API deploy 使用的外部生成 controller 环境文件')
|
||||
string(name: 'BGFILTER_WORKER_ENV_FILE', defaultValue: '/etc/genarrative/bgfilter-worker.env', description: 'API deploy 使用的 BgFilter worker 环境文件')
|
||||
choice(name: 'STDB_API_ROLLOUT_MODE', choices: ['normal', 'pause-after-stdb'], description: '定时任务默认 normal 完整发布 dev;人工维护窗口才选择 pause-after-stdb')
|
||||
string(name: 'STDB_API_ROLLOUT_APPROVERS', defaultValue: '', description: 'pause-after-stdb 必填:允许放行 API 的 Jenkins 用户/组,多个值用逗号分隔')
|
||||
booleanParam(name: 'EXIT_MAINTENANCE_MODE_AFTER_COMPLETION', defaultValue: true, description: '完整发布成功后是否退出维护模式;取消勾选会保留维护页,便于内网验收后人工恢复公网')
|
||||
@@ -233,6 +235,8 @@ pipeline {
|
||||
booleanParam(name: 'KEEP_MAINTENANCE_MODE', value: true),
|
||||
string(name: 'API_ENV_FILE', value: params.API_ENV_FILE ?: '/etc/genarrative/api-server.env'),
|
||||
string(name: 'WORKER_ENV_FILE', value: params.WORKER_ENV_FILE ?: '/etc/genarrative/external-generation-worker.env'),
|
||||
string(name: 'CONTROLLER_ENV_FILE', value: params.CONTROLLER_ENV_FILE ?: '/etc/genarrative/external-generation-controller.env'),
|
||||
string(name: 'BGFILTER_WORKER_ENV_FILE', value: params.BGFILTER_WORKER_ENV_FILE ?: '/etc/genarrative/bgfilter-worker.env'),
|
||||
string(name: 'DATABASE', value: params.DATABASE),
|
||||
string(name: 'SPACETIME_SERVER_URL', value: params.SPACETIME_SERVER_URL ?: ''),
|
||||
]
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
"dev": "node scripts/dev.mjs",
|
||||
"dev:spacetime": "node scripts/dev.mjs spacetime",
|
||||
"dev:api-server": "node scripts/dev.mjs api-server",
|
||||
"dev:bgfilter-worker": "node scripts/dev.mjs bgfilter-worker",
|
||||
"bgfilter-worker:load-smoke": "node scripts/bgfilter-worker-load-smoke.mjs",
|
||||
"bgfilter-worker:fault-smoke": "node scripts/bgfilter-worker-load-smoke.mjs fault",
|
||||
"bgfilter-worker:smoke-test": "node --test scripts/bgfilter-worker-load-smoke.test.mjs",
|
||||
"dev:web": "node scripts/dev.mjs web",
|
||||
"dev:admin-web": "node scripts/dev.mjs admin-web",
|
||||
"server-manager:panel": "cargo run -p server-manager-panel --manifest-path server-rs/Cargo.toml",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user