在 ActiveJob 和 Controller 之间共享数据

Share data between ActiveJob and Controller

应用程序每隔 n 秒请求一个远程 JSON 文件,该文件提供交易系统中证券的实时价格。 JSON 有一个包含我需要的数据的块 (marketdata) 和一个包含当前 dataversionversionseqnum)的块。

现在我使用ActionController::Live(在客户端使用EventSource)将更新的数据推送到浏览器。所有操作都在一种方法中完成:

  1. 正在打开 SSE 连接;
  2. 形成动态URL;
  3. 正在从远程服务器拉取新数据;
  4. comparing/reassigningseqnum值;
  5. 根据需要更新数据库。

所以我现在的目标是将拉取和更新数据库 (ActiveJob) 与将更新的值推送到浏览器 (ActionController::Live) 分开。为此,我需要:

所以基本上我有两个问题:

考虑到您可能有多个 rails 进程 运行,我相信您很难让 activejob 直接与 rails controller 对话某种方式。

绝对存储 seqnumversion,无论如何我都不会依赖 updated_at,随机更新它太容易了,所以最终将东西发送到没有任何真正理由的客户。同样在这种情况下,它们似乎是非常可靠的字段,可以指出文件是否已更新。

有轮询

话虽这么说,您想 "signal" ActionController::Live 以某种方式,恐怕在这里投票是您唯一的选择,除非在您的客户端有特定的时刻需要知道文件是否已更新,在这种情况下你可能想使用 websockets 或类似的东西。

所以,像

cached_request = YourCachedRequest.latest # Assuming it returns a single record
updated        = true
loop do
  if updated
    updated = false
    response.stream.write cached_request.serialize_in_some_way
  end
  current_version = cached_request.version # use seqnum too if you need
  cached_request = cached_request.reload
  updated = true if cached_request.version > current_version
  sleep 20.0
end

没有轮询

如果你想要一个不涉及轮询的选项,我相信你只能选择 websockets。但是你有一个更有效的选择:

创建一个迷你应用程序(evenmachine/sinatra/something light),客户端将在其中进行轮询(您可以通过您的主应用程序将其分发到这个迷你应用程序的不同节点),这个应用程序的目的只是为了将消息从您的主应用程序重新路由到轮询客户端。

现在,您可以为主应用程序创建一个内部 API 端点,它仅供延迟作业使用。仅当延迟作业注意到获取的 JSON 实际上相对于当前存储的作业已更新时,它才会到达此端点。如果是这种情况,它将到达您的主应用程序 API 端点,该端点又会向您的所有迷你应用程序发送一条消息(同样,可能通过 HTTP API 端点,这次是在您的迷你应用程序上)实例,然后将它们发送给您的客户。

通过这种方式,您不会使主服务器过载,而只会使这些可能 局部中断 的迷你节点过载(这是一个很大的优势,而不是有一个很大的系统中断)。