Action X-Ray

把调试器级别的可见性直接嵌入架构之中:一次操作的进展及其每一步的中间状态都可在线查看——即便在生产环境中,也无需停止进程。

复杂的业务操作通常是一连串方法调用。在开发过程中,你可以在调试器里运行它,逐步走完整个执行路径,看到中间状态。这有助于发现复杂而不明显的缺陷。但有些问题只在真实数据、真实负载下才会出现。这时你需要一个在线调试器——它能透视操作的真实执行,在不停止进程的情况下找到原因。Action X-Ray 给你的正是这种能力。

文档 ↗

在生产环境中无法挂接调试器

调试器从内部展示一次操作——但在生产环境中你无法挂接它,而一次实时运行又没有可以抓住的着力点。

在开发过程中,调试器可以在任意步骤冻结执行:你能看到参数、中间值,以及将要传递下去的东西。在生产环境中这做不到——你无法为了单个请求而暂停进程,罕见的输入也难以复现。你也无法即时观察一次运行:调用链存在于调用栈中,它的中间值存在于局部变量里,而一旦某个调用返回,这一切就都消失了。日志只保留预先选定的值;技术性的追踪能看到调用及其耗时,却不知道其中哪些是业务步骤,也不知道它们之间哪些中间值重要。原因只能从间接线索去猜测。

数据在运行时是存在的——调试器已经证明了这一点。缺的是另一样东西:一个预先已知的边界,围绕整个运行、也围绕它的每一步,让你可以在其上挂接在线观察——而无需停止进程。

开发环境
validate
reserve断点{ validated_items: 3 } · 所有值都可见
charge

可在任意步骤暂停——整个 state 都可见

生产环境
请求响应 / 异常

无法停下——中间过程不可见

完整文档 ↗

运行的边界已经由架构设定

要把一次运行作为整体来观察,它就需要一个精确的边界——它的每一步也同样需要。

在 AOA 中,一次操作就是一个带有外部边界 Params → Result 的 Action。它由机器运行——机器就是执行 Action、并预先知道运行在哪里开始、又在哪里结束的 AOA 引擎。在内部,路径被拆分为一个个 Aspect,每个 Aspect 都有自己的中间状态,即 state。一个 Aspect 接收上一个 state 的 snapshot,并返回它自己新的 state——这个新 state 会完全替换掉上一个 state,而不是在其之上追加。因此,后续步骤需要的一切,都由该 Aspect 显式地向前携带,步骤之间不会有任何东西自行泄漏;@result_* 就在边界处立即检查输出。这些边界并不是一种观察工具,而是操作本身的构造;但正是它们提供了那些预先已知的点,在这些点上,每一步的输入、输出和 state 都清晰可见。

机器在任何时刻都知道运行的边框及其完整的契约路径:什么进入了每个 Aspect,又输出了什么样的 state。可观察的“单次运行”产物已经由架构本身组装完成——剩下的只是把它释放出来。

Action 的外部边界
Params
之前的 state{ }
01 · 观察点validate@result_* ✓
之后的 state{ validated_items: 3 }
之前的 state{ validated_items: 3 }
02 · 观察点reserve@result_* ✓
之后的 state{ …, reservation_id: 'res_42' }
之前的 state{ …, reservation_id: 'res_42' }
03 · 观察点charge@result_* ✓
之后的 state{ …, payment_id: 'pay_91' }
Result
完整文档 ↗

在线调试:从外部看到的一次实时运行

既然边界都是已知的,机器就在每一个边界上发出一个事件——而外部观察者把这些事件组装成运行的实时画面。

在外部边界上,你能看到实际的 ParamsResult;在每一个内部边界上,则能看到进入和离开的 state、耗时以及任何错误。机器知道所有这些点,并自动发出 lifecycle events;plugin 从外部接收它们,为某一次具体运行构建一个在线投影——一棵由各个步骤组成的树,带有真实的输入、输出、错误和耗时。在开发、测试和生产环境中都一样——无需在业务方法内部放置任何日志调用、手动计时器或追踪代码。

这不是一个挂接的调试器,也不是被停止的进程,而是它的一份安全的在线投影。观察者只能看到契约所允许的内容:敏感字段保持不透明,而 plugin 自身的失败会被隔离,不会改变操作的结果。这正是 Action X-Ray。

实时运行CreateOrderAction
start · Paramsvalidate · state → state′ · 0.4 msreserve · state′ → state″ · 12 mscharge · error · 3 msfinish · Result · 15 ms
lifecycle events
plugin · 在操作之外运行的在线投影
  • start · Params
  • validate · state → state′ · 0.4 ms
  • reserve · state′ → state″ · 12 ms不透明
  • charge · error · 3 ms
  • finish · Result · 15 ms

进程从不停止 · 在开发、测试和生产环境中都一样

plugin 在创建时被交给机器——业务方法保持不变:

service/machine.py
plugin = OpenTelemetryPlugin(    tracer_provider=tracer_provider,    logger_provider=logger_provider,    service_name="checkout-service",)# The plugin lives outside the Action; business methods stay untouched.machine = ActionProductMachine(plugins=[plugin])result = await machine.run(Context(), CreateOrderAction(), params)
完整文档 ↗

在测试中——同一张 X 光片

同样的在线 snapshot 在测试中也能获得:TestBench 通过同一个机器运行同一个操作。

TestBench 并不创建一种仅用于测试的特殊可见性——它通过同一个机器和同一组边界运行同一个 Action。改变的只有外部世界:不再使用生产环境的 Context、Resources 和 gateway,而是使用它们的测试实现,而角色、流水线、checkers 以及 Result 的组装都保持真实。操作可以完整运行,也可以停在单个边界——某个 Aspect、summary 或 compensator——而无需在业务代码中埋设特殊钩子。

测试验证的正是生产环境中可用的那同一个投影:不仅是最终的 Result,还有任何中间状态。改变的是操作周围的现实,而不是操作本身,也不是观察它的方式。

生产环境真实的 Context · Resources · Gateways
同一个 Action · 同一个机器角色 · 流水线 · checkers · Result 组装同一个在线投影
测试环境测试用 Context · fixtures · mocks
整个 Action——系统行为单个边界——精确定位

同一个 Action 通过 TestBench——完整运行或停在单个边界:

tests/test_create_order.py
inventory = AsyncMock(spec=InventoryGateway)inventory.reserve.return_value = "res_42"bench = TestBench().with_user(    user_id="customer", roles=(CustomerRole,)).with_mocks({InventoryGateway: inventory})# The whole operation — same machine, same boundariesresult = await bench.run(CreateOrderAction(), params, rollup=False)# Or stop at a single boundary and inspect its statestate_after = await bench.run_aspect(    CreateOrderAction(), "reserve_aspect",    params=params, state={"validated_items": 3},)assert state_after["reservation_id"] == "res_42"
完整文档 ↗

在线调试成为架构的一种属性

AOA 设定 Action 的外部边界、其 Aspects 的内部边界,并把中间状态变成一份契约。在一次运行期间,正是这些边界成为 lifecycle events 的坐标系——而过去只有在调试器下、或经过手动埋点之后才会出现的可见性,如今对每一次执行都可在线获得,包括生产环境,且操作内部没有任何基础设施代码。

调试针对某一次具体运行,每一步之前和之后的 state、错误及其确切边界都清晰可见——无需挂接调试器。
生产环境同一个投影可以在真实负载下、通过不改变 Action 的外部 plugins 在线获得。
测试验证的是同一个操作和同一组边界;只有它周围的外部现实被替换。
Action X-Ray · aoa.run