P5 Swift
已实现 PoC
部署运维与授权自检:关停也要优雅
Swift 是 P5 数据导入流水线(先仿真),端口 18084。本主题从部署工程师 / 运维工程师视角讲「上线与合规」:启动流程怎么走、授权到期怎么自动优雅关停本产品而不影响其它产品、AUTH_KEY 怎么配、运维子命令怎么用。用 3 个故事讲清「从拉起来到按规矩关掉」的全过程——每步都有真实端点与 JSON 返回,授权细节与代码一一对应。
运维工程师
部署工程师
系统管理员
授权自检
优雅退出
AUTH_KEY
共 3 个故事
能 / 不能速览
✅ 这个主题能做
- 启动流程全自动:LoadConfig(fallback 默认值 + env 兜底)→ Bootstrap(PG 优先,ping 失败自动降级 SQLite)→ NewServer → StartLicenseWatcher 授权自检
- 双路优雅退出:Ctrl+C / SIGTERM 系统信号,或 POST /api/v1/admin/shutdown → httpServer.Shutdown 5s 内完成,不丢账
- 授权周期自检:启动立即校验 + 每 30 分钟在线校验(LicenseCheckInterval=30min);ShutdownScheduler 幂等评估,授权不满足到点 handleLicenseShutdown 只优雅退出本产品、不影响其它产品
- AUTH_KEY 三级兜底:DB system_settings → 环境变量 → config.yaml;在线校验 nonce + crypt_data 防重放
- 运维端点:GET /license/info(force=1 强制重校验,否则 TTL 缓存)、PUT /license/auth-key(内联 admin JWT,成功清缓存)、POST /admin/shutdown
- 子命令四件套:run(启动)/ service(崩溃 2s 自动重启)/ backup(导出演示数据 JSON 到 stdout)/ health(健康检查,unhealthy 退出码 1)
⛔ 这个主题做不了
- 在线校验必须外网可达授权服务器(zyinfo.pro:19999),断网时只能给宽限档,无法确认授权(非离线授权)
- 授权保护的是「进程级」合规(不满足自动关停),不是业务功能级门禁
- GET /license/info 仅展示机器码与有效期,不做人工关停;关停动作由调度器自动触发
- service 是简化监管器(2s 重启),非 systemd / 进程守护全功能
- 无 config.yaml 时 SECRET_KEY 走演示默认值,只能用于演示环境
适用角色
本主题面向三类运维侧角色:
- 部署工程师:首次部署、启动流程、端口与数据库切换、退出演练(cmd/main.go 与 server/bootstrap.go)。
- 运维工程师:授权巡检与到期续费、关停调度观察、backup/health 例行作业(license_check.go 与 platform/license)。
- 系统管理员:授权密钥写入(PUT /license/auth-key)、登录验证、跨产品密钥互认。
能力速览(已实现 PoC)
启动引导 Bootstrap
PG(chatbi_action_dev)优先,ping 失败自动降级 SQLite(data/swift_platform.db);AutoMigrate 建全部表 + 默认管理员 admin/admin1 幂等创建。
授权周期自检 WatchPeriodic
启动立即校验 + 每 30 分钟在线校验(LicenseCheckInterval=30min);Manager TTL 缓存默认 10 分钟,force=1 绕过缓存强制重校验。
关停调度 ShutdownScheduler
幂等评估:未注册 → hard 档(20min+随机 0-10min);已过期不足 30 天 → grace 档(6h+随机 0-2h);过期超 30 天 → hard 档;到期回调 handleLicenseShutdown。
授权密钥 ResolveAuthKey
AUTH_KEY 三级兜底:DB system_settings → 环境变量 → config.yaml security.auth_key;在线校验 nonce+crypt_data(共享 AES 派生密钥解密比对,防重放)。
运维端点
GET /api/v1/license/info(force=1 强制重校验,返回授权与关停状态)、PUT /api/v1/license/auth-key(内联 admin JWT,成功清缓存)、POST /api/v1/admin/shutdown(触发优雅退出)。
运维子命令
run 启动 HTTP 服务 / service 监管模式(崩溃自动重启)/ backup 导出账户·结算·分录·支付 JSON / health 健康检查(unhealthy 退出码 1)。
调整指南(怎么调整)
- 调整端口:SWIFT_PORT 环境变量优先,其次 config 的 server.port,最后默认 18084。
- 调整数据库:有 PostgreSQL(DB_* 环境变量 / DATABASE_URL)自动用 PG,不可用自动降级 SQLite;生产建议接真 PG。
- 调整授权周期:LicenseCheckInterval 默认 30 分钟(watcher.go 常量),测试可传短间隔;TTL 缓存默认 10 分钟(NewManager 可调)。
- 调整关停档位:grace 宽限 6h + 随机 0-2h、hard 硬关 20min + 随机 0-10min、30 天过期阈值均为 NewShutdownScheduler 默认参数,可按部署策略覆盖。
- 调整密钥来源:优先写 DB(PUT /license/auth-key 持久化、重启不丢);容器 / 服务编排场景用环境变量 AUTH_KEY 注入。
- 调整退出方式:手工关停用 POST /api/v1/admin/shutdown(带共享 SECRET_KEY 签发的 admin JWT);脚本 / 任务计划关停发 SIGTERM。
做得好的场景(已实测)
这套部署设计最亮眼的是「无配置也能起、关停真优雅」:
- 裸机几分钟拉起:LoadConfig fallback + env 兜底,没有 config.yaml 也照常启动,日志明确提示。
- PG→SQLite 透明降级:Bootstrap 自动探测连接,失败自动切 SQLite 并打 Warn 日志,无需手工改配置。
- 关停真正优雅:退出双路(信号或 HTTP 指令)汇入 main select → httpServer.Shutdown 5s,数据早已落盘,不丢账。
- 授权合规自治:到期自动优雅关停本产品、AIP/Foundry/Apollo/Gotham 各产品独立授权互不影响;幂等评估不反复刷新倒计时。
- 密钥管理收敛:三级兜底一处生效,在线校验 nonce+crypt_data 防重放防伪造,换机器机器码即变。
- 工具链齐整:run/service/backup/health 四个子命令覆盖启动、自愈、备份、体检,脚本化友好。
限制与不足
以下是明确的边界,先知道再读故事:
- 在线校验依赖外网:授权服务器在 zyinfo.pro:19999,断网 / 域名不通时只能给宽限档,不能确认授权。
- 授权形态单一:为「机器码 + 有效期」在线校验(V5 下放能力),不是离线 License 文件 / 加密狗。
- service 是简化监管器:2s 自动重启,没有 systemd 的依赖管理、日志接管与开机自启。
- SQLite 是降级方案:Bootstrap 目标是 PostgreSQL,SQLite 只为单机 PoC 兜底。
- license/info 含演示信息:product_info 的公司 / 微信号为演示数据,不是正式授权公示。
场景故事
故事 1
首次部署:一台没有配置、没有 PostgreSQL 的新机器上把 Swift 拉起来——fallback、降级、双路退出
场景:部署上线
角色:部署工程师
代码:cmd/main.go · server/bootstrap.go
- 背景
- 孙工,部署工程师。客户现场一台新的 Windows 服务器,只有两个环境变量 DEEPSEEK_API_KEY 和 SECRET_KEY,没有 config.yaml、没有 PostgreSQL、连数据库目录都没有。他要在这台"裸机"上把 Swift 拉起并做一次退出演练——验证 LoadConfig fallback、Bootstrap 的 PG→SQLite 降级、双路优雅退出。
- 传统做法对比
- 以前部署金融系统要先手工装 PostgreSQL、配 JDBC、写建表脚本、再逐个初始化表,缺一个依赖整个启动就白屏,光排环境问题就大半天。Swift 的 Bootstrap 把建库、AutoMigrate、默认管理员一次做完:PG 连不上自动降级 SQLite(data/swift_platform.db),几分钟就能起来。
- 角色
- 部署工程师(首次部署与退出演练);运维工程师(后续巡检);系统管理员(登录验证)。
- 操作步骤
-
- 把 .env 放到运行目录(可选:DB_* / DEEPSEEK_API_KEY / SECRET_KEY,缺省用默认值兜底)
- 运行 ./swift run:LoadConfig 找不到 config.yaml 会打 Warn 并 fallback 默认值 + env 兜底
- 观察日志:PG 不可达 → "PostgreSQL unavailable, falling back to SQLite",随后自动建 data/swift_platform.db
- 浏览器访问 http://127.0.0.1:18084,GET /health 确认 {"status":"ok","service":"zy-action-swift"}
- 用 admin/admin1 登录,确认默认管理员与 admin 角色已幂等就绪
- 演练退出:先 Ctrl+C 看信号退出,再重启后调 POST /api/v1/admin/shutdown 看 HTTP 指令退出
- 系统响应
- 健康检查真实返回:
GET /health
{"status":"ok","service":"zy-action-swift"}
HTTP 退出指令返回 {"code":0,"message":"shutdown accepted"},main select 双路感知后日志依次出现 "Shutting down Swift server..." 与 "Swift server exited",全程 5s 内完成。
- 结果洞察
- 无配置、无 PG 也能起:LoadConfig fallback + env 兜底把"环境缺失"从致命错误降为可选;Bootstrap 的 PG→SQLite 降级让单机 PoC 和联网生产共用同一套代码;双路退出汇入同一 select,SIGTERM 与 HTTP 指令行为一致,数据早已落盘不丢账。
- 调整建议
- 生产必须接真 PostgreSQL(配 DB_* 或 DATABASE_URL),别用 SQLite 兜底;端口冲突时用 SWIFT_PORT 换端口(默认 18084);退出演练放在发版窗口做,先 backup 再关停。
- 动手试一试
- 删掉 config.yaml 起一次,看 fallback 与降级日志;Ctrl+C 退出后再启动,用 admin JWT 调 POST /api/v1/admin/shutdown 看第二种退出路径;再把 SWIFT_PORT 设为 18085 起第二个实例验证端口优先级。
- 限制提示
- 无 config.yaml 时 SECRET_KEY 用演示默认值,只能用于演示环境;SQLite 是降级方案,不是生产目标库;退出演练需确保无在途交易。
故事 2
授权自检与自动关停:到期前 30 分钟自检告警、到期瞬间优雅关停本产品而不影响其它产品
场景:授权合规
角色:运维工程师
代码:platform/license · license_check.go
- 背景
- 周工,运维工程师。负责的 Swift 演示实例授权 2026-08-29 已过期 1 天。今天 08-30 16:05 的周期自检发现授权不满足,调度器自动安排了关停。他要在到期瞬间验证两件事:一、Swift 能否自己优雅关停;二、同机器上的 AIP / Foundry / Apollo / Gotham 是否毫发无损。
- 传统做法对比
- 以前商业软件的授权过期只有两种粗暴处理:要么硬卡死直接拒绝登录(业务全停、现场炸锅),要么过期了还在裸跑(合规风险黑洞)。Swift 的做法是三层合规:未注册直接 hard 档(20min+随机 0-10min);已过期不足 30 天给 grace 宽限档(6h+随机 0-2h),留出续费窗口;过期超过 30 天转 hard 档。到点 handleLicenseShutdown 只优雅退出本产品,各产品独立授权互不拖累。
- 角色
- 运维工程师(授权巡检与关停观察);系统管理员(到期续费);部署工程师(关停演练)。
- 操作步骤
-
- 登录后 GET /api/v1/license/info 查看 authorized / exp_date / hardware_id / auth_key_set
- 发现 shutdown_scheduled=true,看 shutdown_tier、shutdown_deadline、shutdown_reason 定位档位与原因
- 用 force=1 强制在线重校验一次,绕过 TTL 缓存确认最新授权状态
- 等待下一个 30 分钟自检:调度器幂等评估,同档位且 deadline 未到则保持原 deadline,不反复刷新倒计时
- 到点 handleLicenseShutdown → 本产品优雅退出;切到 AIP / Foundry / Apollo / Gotham 页面确认其它产品照常服务
- 续费后 PUT /api/v1/license/auth-key 写入新密钥 → 调度器取消关停(shutdown_scheduled=false)
- 系统响应
- 授权状态真实返回:
GET /api/v1/license/info
{"authorized":false,"exp_date":"2026-08-29","hardware_id":"aip-9f3b2c1d...",
"auth_key_set":true,"message":"-",
"product_info":{"name":"ZY Action Platform","company":"深圳展映科技有限公司",
"date":"2026.8.10","website":"zyinfo.pro","wechat":"youkpan"},
"shutdown_scheduled":true,"shutdown_deadline":1788134400,
"shutdown_tier":"grace","shutdown_reason":"授权已过期,请获取注册 KEY 完成续期"}
shutdown_deadline 为 Unix 秒;到期触发后日志打印 "license: 授权不满足,触发本产品优雅退出"。
- 结果洞察
- 到期瞬间优雅关停不丢账:httpServer.Shutdown 5s 内完成,账户 / 结算 / 分录早已落库;grace / hard 两档给了 6h 宽限续费窗口,网络校验失败也走宽限而不是直接拒死;幂等评估保证 30 分钟自检不会反复刷新倒计时;最关键的是各产品独立授权,Swift 关停 AIP 等其它产品毫无感知。
- 调整建议
- 到期前用监控对 license/info 的 shutdown_deadline 做日历告警,别等自动关停;生产环境 AUTH_KEY 写到 DB 或 env,避免文件丢失;网络不可达会进宽限档,运维要同时盯授权服务器连通性。
- 动手试一试
- 把 AUTH_KEY 环境变量临时置空,GET /license/info 看档位变 hard、deadline 约 20 分钟后;再 PUT 回正确密钥,看调度器取消关停(shutdown_scheduled=false);观察期间其它产品的 license/info 是否不受影响。
- 限制提示
- 在线校验打外网 zyinfo.pro:19999,断网只能宽限不能确认;TTL 缓存 10 分钟内结果可能滞后,需 force=1 强制重校验;授权保护的是进程级合规,不是业务功能级门禁。
故事 3
授权密钥三级兜底与运维工具链:AUTH_KEY 怎么配、backup / health / service 怎么用
场景:日常运维
角色:系统管理员
代码:platform/license · cmd/main.go
- 背景
- 韩总,系统管理员。要给新部署的 Swift 配授权并纳入例行运维。他关心三件事:授权密钥 AUTH_KEY 写在哪里最稳(ResolveAuthKey 三级兜底:DB → env → config.yaml)、数据怎么定时备份(backup 子命令)、进程挂了怎么自愈(service 子命令)+ 怎么体检(health 子命令)。
- 传统做法对比
- 以前 License 是放在安装目录的授权文件,容易丢、换机器就失效;授权校验要单独部署服务或写死脚本。Swift 把授权密钥收敛到统一三处:DB(系统设置页可直接写,重启不丢)、环境变量(容器 / 服务编排注入)、config.yaml(本地文件兜底);机器码 = MAC 前 14 字符 + 硬盘序列号 md5,换机器码即变,天然绑定机器。
- 角色
- 系统管理员(配置授权密钥与排障);运维工程师(备份 / 健康检查例行作业);部署工程师(service 监管模式)。
- 操作步骤
-
- 用共享 SECRET_KEY 签发的 admin JWT 调 PUT /api/v1/license/auth-key,body 传 {"auth_key":"..."} 写库
- 验证返回 {"code":0,"updated":true},且 system_settings 已落库 AUTH_KEY、授权缓存被清空
- 重启服务确认密钥仍在(DB 持久化),GET /license/info 看 auth_key_set=true
- ./swift backup 导出账户 / 结算 / 分录 / 支付 JSON 到 stdout,用于定时备份
- ./swift health 跑健康检查(config / database / port 三组件),unhealthy 时退出码 1 供监控脚本捕获
- ./swift service 启动监管模式:子进程崩溃 2 秒后自动拉起;在线校验用 nonce + crypt_data 防重放防伪造
- 系统响应
- 授权密钥写入真实返回:
PUT /api/v1/license/auth-key
{"code":0,"updated":true}
backup 输出 JSON 含 exported_at、product="zy-action-swift" 与 accounts / settlements / journal_entries / payments 四个数组;health 输出组件明细,任一 unhealthy 则进程以退出码 1 结束。
- 结果洞察
- 三级兜底让密钥"DB 最优先、容器注入次之、本地文件最后",写库即生效(清缓存强制下次重校验);backup 可进 crontab / 任务计划定时导出;health 是现成的监控探针(unhealthy 退出码 1);service 监管模式适合无人值守现场,崩溃 2 秒自愈。
- 调整建议
- 生产建议 AUTH_KEY 走环境变量注入(避免明文写文件);backup 加定时任务并异地保存;health 接监控告警;多实例 / 开机自启场景用 systemd / Windows 任务计划替代简化监管器。
- 动手试一试
- 登录后 PUT 一个密钥看 updated=true 与 system_settings 落库;再调 ./swift backup 看四张表 JSON;跑一次 ./swift health 看 config / database / port 三组件状态,再把数据库文件移走验证 unhealthy 退出码。
- 限制提示
- PUT 需内联 admin JWT(共享 SECRET_KEY 签发),非 admin 返回 403;service 是简化监管器,非 systemd 全功能;在线校验需外网可达授权服务器。
常见问题
Swift 多久做一次授权校验?
启动后立即校验一次,之后每 30 分钟周期校验(WatchPeriodic,LicenseCheckInterval=30min)。日常 GET /license/info 默认走 10 分钟 TTL 缓存,带 force=1 参数会强制在线重校验一次。
授权不满足会怎样?
ShutdownScheduler 幂等评估:未注册 → hard 档(20min+随机 0-10min);已过期不足 30 天 → grace 宽限档(6h+随机 0-2h);过期超 30 天 → hard 档;网络校验失败 → grace 档。到点 handleLicenseShutdown 优雅退出本产品,不影响 AIP / Foundry / Apollo / Gotham。
AUTH_KEY 从哪里读?
ResolveAuthKey 三级兜底:先读数据库 system_settings 的 AUTH_KEY,缺失回退环境变量 AUTH_KEY,再回退 config.yaml 的 security.auth_key。在线校验时请求带 hid(机器码前 16 位)+ auth_key + nonce,服务器返回 crypt_data 解密后须与 nonce 一致,防重放。
怎么优雅关停 Swift?
两条路:一、向进程发 SIGINT / SIGTERM(Ctrl+C);二、POST /api/v1/admin/shutdown(带共享 SECRET_KEY 签发的 admin JWT,非本产品 RBAC)。两条路汇入 main select → httpServer.Shutdown,5 秒内完成,数据不丢。
换机器部署会不会影响授权?
会。机器码 = zyaction|MAC 前 14 字符|硬盘序列号的 md5,换机器(网卡或硬盘变化)机器码就变,需要拿新机器码重新申请授权;各产品独立授权,互不影响。部署与组件分工的更多细节见《架构与组件》主题。
主题小结
一句话:Swift 部署 = 启动三连(LoadConfig → Bootstrap → NewServer)后授权自检常驻(启动 + 每 30 分钟在线校验),授权不满足到点优雅关停本产品、其它产品不受影响;运维靠 run / service / backup / health 四个子命令 + /license/info、/license/auth-key、/admin/shutdown 三个端点。记住边界:在线校验需外网,SQLite 是降级方案,service 是简化监管器。