【问题标题】:Where in Hexagonal Architecture do periodic background tasks fit?在六边形架构中,周期性后台任务适合哪里?
【发布时间】:2021-08-15 05:44:02
【问题描述】:

我正在使用 golang 开发一个程序,我正在构建基于六边形架构的程序。我想我的脑子里大部分时间都围绕着这个想法,但有些东西我就是想不通。

该程序的功能是监控多个 IP 摄像机的警报事件,接收器可以通过 HTTP2.0 PUSH REQUEST 接收实时警报事件流。 (以防万一这不是技术术语,我的服务从 GET 请求建立 TCP/HTTP 连接并保持打开状态,当摄像头触发警报事件时,摄像头将其推回服务)

架构层次

适配器

  • HTTP 处理程序
  • 内存中 JSON 存储

端口

  • 设备服务接口
  • 事件服务接口
  • DeviceRepo 接口
  • EventRepo 接口

服务

  • 设备服务
  • 事件服务

  • 设备域
  • 事件域

用户通过 API 向系统添加设备,请求中包含所需的监控时间表(接收器应每天启动和停止的时间)和 url。

调度器负责定期检查接收器是否要根据其调度启动。如果它打算为某个设备运行,它会为该设备启动一个接收器。

接收器建立与 IP 摄像机的连接并循环处理警报事件并将其传递给 EventService 的警报事件流。

EventService 接收事件,并负责处理事件,根据领域逻辑,决定是发送邮件还是忽略它。它还将所有事件保存到 eventrepo。

我不确定它们位于何处的两部分代码是调度器和接收器。他们也应该如此; 一种。两者都在同一个包中并放置在 Adaptors 层 湾。 适配器层中的接收器和服务层中的调度器 C。 服务层中的调度器和接收器?

我只是感到困惑,因为接收器不是由用户直接启动的,而是由一个不断检查条件的运行循环启动的。但对于不同品牌的相机,我也可能有不同的接收器。这是一个实现细节,这意味着接收器应该在适配器层中。这让我觉得选项 b 是最好的。

我可能想多了,但请告诉我你们认为最好的选择是什么,或者建议一个更好的选择。

【问题讨论】:

    标签: go architecture domain-driven-design clean-architecture hexagonal-architecture


    【解决方案1】:

    如果对你有帮助,我的设计如下:

    司机演员:

    • 人类用户:使用驱动程序端口与应用程序交互:“用于添加设备”
    • 设备(IP 摄像头):使用另一个驱动程序端口向应用发送警报事件:“用于接收警报事件”

    驱动的演员:

    • 设备(IP 摄像头):应用程序使用驱动端口“检查设备”与设备交互,以便根据设备的时间表每天启动和停止它。
    • 警告收件人:当收到警报事件且未被忽略时,应用会向他们发送一封电子邮件。
    • 报警事件存储:用于保存应用接收到的报警事件。

    应用程序(“警报监视器”)执行以下业务逻辑:

    • 维护必须监控的设备集合(“用于添加设备”)。
    • 它有一个“worker”(调度程序)定期检查设备状态并根据设备的调度启动/停止它们。
    • 它处理从设备接收到的警报事件。当收到警报事件时,应用程序要么发送电子邮件,要么忽略它。并将事件存储在存储库中。

    所以对我来说:

    • 调度程序是业务逻辑的一部分。
    • 接收器是设备的适配器。它涉及 http 的东西。

    图片如下:

    【讨论】:

      【解决方案2】:

      “调度器负责定期检查接收器是否要根据其调度启动”

      最终,对于应用程序而言,人类是否按周期按下“autoStartReceivers”按钮或它是由调度进程完成的并不重要。因此,这是一个基础架构问题,调度程序是一个驱动适配器。您可能有一个 ReceiverService.autoStartReceivers 服务命令,调度程序会定期调用该命令。

      现在对于Receiver,我想说这取决于实现。如果Receiver 不知道基础架构/供应商特定的细节,而只是协调,那么它可能属于应用程序/服务层。

      例如,接收器可能使用抽象的EventSource(HTTP、WebSockets 等)并使用EventDecoder(特定于供应商)来调整事件,然后将它们中继到EventProcessor,那么它真的只是正在做编排EventSource & EventDecoder 将是适配器。但是,如果Receiver 知道特定的基础架构细节,那么它就会成为一个适配器。

      最终,以上所有内容都支持您的事件处理核心领域的逻辑。核心域逻辑并不真正关心事件是如何被捕获的,并且可能也不关心结果操作是如何进行的。因此,最简单形式的核心域可能是actions = process(event) 纯函数。

      【讨论】:

      • 更正Receiver 将基于供应商特定的详细信息。这个想法是如果我要更换设备,就能够将Receiver 换成不同的,Receiver 将与EventService 对话。所以Receiver 是一个驱动适配器是有道理的。但我忘了提到的是我想要控制Receiver、停止、启动的能力。这使它听起来像一个驱动适配器?适配器可以既是驱动适配器又是驱动适配器?还是应该有另一个驱动适配器说ReceiverManager可以与Receivers通信?
      • 当然一个适配器可以同时是驱动和驱动。它将对驱动程序端口具有可配置的依赖关系,并且还将实现驱动端口。在我的解决方案的图片中,网络摄像机的驱动适配器是接收器。
      【解决方案3】:

      一个。都在同一个包里,放在 Adapters 层

      b. Adapters层的receiver和Service层的scheduler

      c。 Service 层中的调度器和接收器?

      接收器和调度器都是适配器。我不认为它们必须放在同一个包中,但你可以这样做。所以a对我来说是最好的答案,因为...

      接收器将您的应用程序与外部设备 - ip camara 连接起来。因此接收器是EventService 端口的适配器。

      调度器通过DeviceService端口间接管理接收器的生命周期。它启用或禁用 ip camara,这会导致接收器的连接和断开连接。

      从您的应用程序核心的角度来看,调度程序只是另一个适配器,它告诉DeviceService 端口启用或禁用某些 ip camara。这也可以由单击 UI 中的按钮的用户来完成。调度器只是用户的技术辅助,它根据调度执行用户想要的任务。因此调度器也是一个适配器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-01
        • 2015-01-17
        • 2015-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多