跳转到内容

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 基类
JsonSerializedFieldJSON 列序列化与双模式兼容Agent, Event
LiquidInterpolatableLiquid 模板插值与自定义扩展Agent 基类
DryRunnableDry Run 沙箱执行支持 Dry Run 的 Agent
WorkingHelpersworking? / 错误日志检测Agent 基类

控制流与编排类

Concern职责被谁使用
AgentControllerConcern控制其他 Agent 的能力CommanderAgent, SchedulerAgent

集成与协议类

Concern职责被谁使用
WebRequestConcernHTTP 请求封装WebsiteAgent, PostAgent 等
TwitterConcernTwitter API 封装Twitter 系列 Agent
GoogleOAuth2ConcernGoogle OAuth2 流程GoogleCalendarAgent
DropboxConcernDropbox API 封装Dropbox 系列 Agent
OpenaiConcernOpenAI API 封装OpenAI 系列 Agent
SlackConcernSlack API 封装SlackAgent

UI 与工具类

Concern职责被谁使用
FormConfigurable表单可配置字段声明DeDuplicationAgent 等
HasGuid自动生成 GUIDAgent, Scenario
SortableEvents事件排序能力有事件排序需求的 Agent
MarkdownClassAttributesMarkdown 渲染支持Agent 基类

长运行进程框架

LongRunnable 框架允许 Agent 作为持续运行的后台进程(而非定时任务):

  • TwitterStreamAgent:保持与 Twitter Streaming API 的长连接
  • LocalFileAgent:使用 listen Gem 监控本地文件系统变化
  • JabberAgent:保持 XMPP 长连接

注册机制

# AgentRunner 启动时加载
Agents::TwitterStreamAgent # 触发 require,注册到 LongRunnable
Agents::JabberAgent
Agents::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
开发效率高(共享代码库)低(跨服务协调)
扩展性垂直扩展为主水平扩展灵活

对于个人自动化场景,大单体的复杂度完全可控,且避免了分布式系统的各种陷阱。

参考来源