napp-macro
#[nasa::application(...)] 属性宏的实现 crate。业务项目不直接依赖它,经 nasa 门面的 application
feature 使用;运行时语义见 napp 与 运维指南。
宏把业务的异步 main 改写为统一进程入口:
- 生成静态
ApplicationSpec(组件声明顺序、编译期缺省应用名)并调用napp::run,真实main返回std::process::ExitCode。 - 声明
"web"时在 crate 根自动生成mvc_router!(nasa::Application)收集端,并把业务 crate 内 nominal 的路由项投影为运行时稳定的RouteMeta;业务不得再手写mvc_router!(会因crate::__mvc重复定义编译失败)。 - 业务
main变成启动 Hook:零参数或接收一个Application,返回anyhow::Result<()>;成功返回后资源封存,运行由 Runner 接管。
编译期校验(与运行期同口径,先在宏上失败):
- 组件白名单:
log、nacos-config、telemetry、db、redis、cache、saga、kafka、outbox、auth、web、ws、nacos-discovery、scheduling;未知或重复组件拒绝。 - 业务可按任意顺序书写;宏固定规范为
log -> nacos-config -> telemetry -> db -> redis -> cache -> saga -> kafka -> outbox -> auth -> web -> ws -> nacos-discovery -> scheduling。 saga隐式加入 DB 与 Outbox;独立outbox隐式加入 DB。Inbox 是事务内原语,没有组件字符串; Kafka 或其它 transport 不由 Saga 推断。- 隐式依赖只补齐缺项;显式同时声明
saga、db、outbox与只声明saga生成同一组件图。 - 组合约束:
auth必须和web同时声明;其余依赖关系由运行期根据最终配置继续校验。 - 每个声明组件都会生成 feature 探测常量引用,能力未启用时在业务 crate 编译阶段直接失败。
- 入口契约:必须是 crate 根的
async fn main,非泛型、至多一个Application参数、返回anyhow::Result<()>;生成的类型门禁同时要求 Hook future 为Send + 'static。入口不能再叠加#[tokio::main]或#[EnableScheduling]/#[EnableAsync],因为 Application 已拥有 runtime 与调度 生命周期。 - 生成 crate 根锚点模块:属性放错位置时错误直接指向宏调用处。
宏内路径解析复用 macro-support(直接依赖优先、门面回退、Cargo 重命名兼容)。
使用示例
[]
= { = "1", = ["application", "log", "redis", "cache", "web"] }
async
虽然源码按 web, cache, redis, log 书写,生成的规范启动顺序仍是 log -> redis -> cache -> web。
YML 配置与边界
本宏不读取 yml;它只生成 ApplicationSpec。zcf/application.yml 和各组件配置由 napp 运行时读取。
- 属性只能放在 crate 根异步
main上。 - 声明
"web"后宏会生成唯一的路由收集模块,业务不能再手工生成同名收集器。 - Hook 返回成功后资源登记入口封口,运行期不能继续修改组件图。
- feature 缺失、重复组件、未知组件和非法组合都在编译期拒绝。