使用 Aspire 实现 Runtime 和 Observability
Lino 生成服务、web apps 和基础设施资源之后,Aspire 可帮助以可见的方式在本地运行所有内容。Observability 不是锦上添花:它能显示 APIs、数据库、cache、messaging 和 workers 是否健康。
在包含 events、Outbox、workers、Redis、RabbitMQ 和多个模块的应用中,许多问题不会只出现在屏幕上。它们会出现在 logs、queues、jobs、migrations、参数和 runtime 资源中。本节说明如何把解决方案看作正在运行的系统,而不仅仅是生成出来的文件。
使用 Aspire 运行
AppHost 集中负责解决方案的本地运行。它会启动服务、web apps,以及 PostgreSQL、Redis、RabbitMQ、workers 等依赖项。
dotnet run --project src/Aspire/AppHost/<ProjectName>.AppHost.csproj
使用 dashboard 检查 logs、变量、endpoints 和资源状态。如果某个服务启动失败,请先从 AppHost 以及它注入的依赖项开始排查。
Aspire 会让本地拓扑变得可见:APIs、web apps、数据库、cache、message broker 和 workers 会作为相关资源显示出来。这个视图有助于发现手动运行时可能隐藏的配置问题,例如错误的 connection string、缺失的参数、没有 endpoint 的服务,或尚未启动的依赖项。
- Logs: 跟踪初始化错误、认证失败、migrations 问题和 worker 消息。
- Endpoints: 确认端口、URLs、health checks,以及指向 web apps 和 APIs 的链接。
- 参数: 验证传播到每个服务的 secrets 和变量。
- 依赖项: 在诊断应用之前,确认 Redis、RabbitMQ 和数据库已经 provision。
数据库资源
Lino 生成的服务通常有自己的 DbContexts、migrations 和 connection strings。在模块化系统中,请验证每个模块是否使用预期的数据库/schema,以及 migrations 是否应用在正确位置。
- 按环境确认 connection strings。
- 在测试依赖新 schema 的流程之前执行 migrations。
- 监控连接失败和 query 时间。
- 避免在本地运行时使用生产数据库。
在简单服务中,数据库跟随服务。在模块化服务中,数据库属于服务,但每个模块可以有自己的 schema、DbContext、migrations 和 scripts。这种分离也需要体现在运维中:应用 migrations 时,请在执行前确认服务、模块、provider 和环境。
数据库故障通常表现为 API 错误,但原因可能在 AppHost、connection string、待执行的 migration、不存在的 schema 或本地凭据中。因此,诊断应从完整链路开始:Aspire 中的参数、活动的数据库资源、已应用的 migration、正确的 DbContext,以及调用预期模块的 endpoint。
Redis 和 cache
Redis 可根据启用的 templates 用于 cache、临时状态、tokens、rate limiting 或其他资源。cache 能提升性能,但也会引入 invalidation 和 eventual consistency。
请记录 key、过期时间和数据来源。在不了解加密、过期和访问控制的情况下,不要把敏感 secrets 存入 cache。
当项目使用分布式 cache 时,多个实例可以共享值,这对水平扩展很有用。只使用本地内存 cache 时,每个进程都会保留自己的副本。这种差异会影响生产行为、负载测试和数据 invalidation。
| 问题 | 为什么重要 |
|---|---|
| cache 中数据的来源是什么? | 定义当值过期或被 invalidated 时如何重新计算。 |
| 可接受的 TTL 是多少? | 决定系统可以容忍潜在旧数据多长时间。 |
| cache 是按 tenant、用户还是全局划分? | 避免上下文之间的数据泄漏和建模不佳的 key。 |
RabbitMQ 和 messaging
messaging 支撑 integration events 和异步通信。使用 Outbox 时,应用不依赖于在事务同一时刻发布消息;worker 可以再次尝试。
- 检查生成的 exchanges、queues 和 bindings。
- 监控卡住的消息和不活跃的 consumers。
- 设计 idempotent handlers。
- 使用 correlation logs 跟踪消息路径。
integration events 有用,正是因为 producer 不需要等待所有 consumers。但这会把一部分复杂度转移到运维中:消息可能延迟,consumers 可能失败,payloads 可能变化,handlers 也可能执行多次。流程文档应明确发布哪个 event、谁消费它,以及更新哪个本地状态。
Shadow Entities 依赖这种 observability。如果 tenant 或用户 entity 通过 event 复制到其他模块,consumer 失败可能导致本地副本过期。系统需要能够诊断 event、消息、handler,以及 consumer 模块数据库中执行的更新。
Hangfire Dashboard
启用 background jobs 时,Hangfire Dashboard 可帮助检查 recurring jobs、失败、retries 和 Outbox 处理执行情况。
在共享环境中保护 dashboard。它会暴露相关运维信息,不应在没有认证和授权的情况下公开。
将 dashboard 用作诊断工具,而不是 logs 和 metrics 的替代品。它显示 queues、尝试次数和执行历史,但完整调查仍然需要 correlation id、结构化 logs 和业务上下文,才能理解 job 失败的原因。
- Retries: 检查失败是暂时性的,还是 job 会无限期继续失败。
- Recurring jobs: 确认间隔、批次和平均执行时长。
- Outbox: 观察卡住的消息、重新处理以及发生异常的 handlers。
- 安全: 限制访问,因为 payloads 和错误可能暴露敏感数据。
Workers 和后台处理
Workers 执行不应阻塞 HTTP 请求的任务:发送消息、Outbox 处理、清理、同步和外部集成。
- 使用适合数据量的批次。
- 定义 retries 和失败处理。
- 记录错误时包含足够上下文,以便重新处理。
- 不要把永久性失败隐藏在通用 logs 中。
添加 worker 时,也要定义频率、批次大小、失败行为和对领域的影响。每隔几秒读取 100 条记录的 worker,与每日 job 有不同的运维行为;两者都需要根据真实数据量进行观测和容量规划。
不要把需要立即响应用户的事情放到 background 中执行。将 worker 用于后续任务、集成、通知、重新处理和维护。如果用例依赖结果来完成事务,请将其作为同步流程处理,或建模一个用户可见的中间状态。
