Ruby on Rails 工程架构——Huginn 的 MVC 与 Concerns 拆分
Ruby on Rails 工程架构——Huginn 的 MVC 与 Concerns 拆分
学习目标
- 理解 Huginn 的 Rails 8.1 工程架构
- 掌握 Concerns 模块化拆分的 28 个横向关注点
- 了解 Controller 层的路由设计与多租户隔离
- 学会在大型 Rails 项目中实施关注点分离
项目实践
整体架构
Concerns 分类
Huginn 的 28 个 Concerns 可分为以下几类:
核心框架类
| Concern | 职责 | 被谁使用 |
|---|---|---|
AssignableTypes | 自动发现 Agent 子类 | Agent 基类 |
JsonSerializedField | JSON 列序列化与双模式兼容 | Agent, Event |
LiquidInterpolatable | Liquid 模板插值与自定义扩展 | Agent 基类 |
DryRunnable | Dry Run 沙箱执行 | 支持 Dry Run 的 Agent |
WorkingHelpers | working? / 错误日志检测 | Agent 基类 |
控制流与编排类
| Concern | 职责 | 被谁使用 |
|---|---|---|
AgentControllerConcern | 控制其他 Agent 的能力 | CommanderAgent, SchedulerAgent |
集成与协议类
| Concern | 职责 | 被谁使用 |
|---|---|---|
WebRequestConcern | HTTP 请求封装 | WebsiteAgent, PostAgent 等 |
TwitterConcern | Twitter API 封装 | Twitter 系列 Agent |
GoogleOAuth2Concern | Google OAuth2 流程 | GoogleCalendarAgent |
DropboxConcern | Dropbox API 封装 | Dropbox 系列 Agent |
OpenaiConcern | OpenAI API 封装 | OpenAI 系列 Agent |
SlackConcern | Slack API 封装 | SlackAgent |
UI 与工具类
| Concern | 职责 | 被谁使用 |
|---|---|---|
FormConfigurable | 表单可配置字段声明 | DeDuplicationAgent 等 |
HasGuid | 自动生成 GUID | Agent, Scenario |
SortableEvents | 事件排序能力 | 有事件排序需求的 Agent |
MarkdownClassAttributes | Markdown 渲染支持 | Agent 基类 |
长运行进程框架
LongRunnable 框架允许 Agent 作为持续运行的后台进程(而非定时任务):
TwitterStreamAgent:保持与 Twitter Streaming API 的长连接LocalFileAgent:使用listenGem 监控本地文件系统变化JabberAgent:保持 XMPP 长连接
注册机制:
# AgentRunner 启动时加载Agents::TwitterStreamAgent # 触发 require,注册到 LongRunnableAgents::JabberAgentAgents::LocalFileAgent
# 每个 Worker 类实现 setup_worker 返回实例列表def self.setup_worker [new(id: self.to_s)]end多租户隔离
隔离保证:
- 每个 Agent 绑定
user_id - Link 两端 Agent 必须属于同一用户(
validates :sources, owned_by: :user_id) - Webhook 路由通过
user_id+agent_id双重验证 - 凭据通过
user.user_credentials隔离
问题与规避
Agent 类型字符串化
Agent.type 字段存储完整的类名(如 Agents::WebsiteAgent),而非短名。
优势:STI(单表继承)自动处理;代价:类名重构需要同步更新数据库。
Concern 依赖顺序
某些 Concern 依赖其他 Concern 先加载(如 AgentControllerConcern 需要 can_control_other_agents! 方法已定义)。
规避方式:在 Agent 基类中按顺序 include,确保依赖链正确。
设计取舍
大单体 vs 微服务
Huginn 选择大单体 Rails 应用而非微服务:
| 维度 | 大单体(Huginn) | 微服务 |
|---|---|---|
| 部署 | 单一进程 | 多进程编排 |
| Agent 间通信 | 数据库事件 | 消息队列/HTTP |
| 开发效率 | 高(共享代码库) | 低(跨服务协调) |
| 扩展性 | 垂直扩展为主 | 水平扩展灵活 |
对于个人自动化场景,大单体的复杂度完全可控,且避免了分布式系统的各种陷阱。
参考来源
- Ruby on Rails Guides — Rails 官方文档
- Concerns in Rails — ActiveSupport::Concern 文档