【问题标题】:What design pattern should be used for a workflow like this?什么样的设计模式应该用于这样的工作流程?
【发布时间】:2019-01-26 03:53:24
【问题描述】:

假设我有这样的工作流程

          (1) Check for latest commit in a GitHub repo
                             |
                             |
                    (2) Is new commit?
                            / \
                        No /   \ Yes
                          /     \
                         /       \
                      End         \
                                   \
                                    \
                                  (3) Download all files
                                  /       |       \
                                 /        |        \
                     (4i) Process file i  .      Process file N
                                \         .         /
                                 \        .        /
                                  \       .       /
                                   \      .      /
                                    \     .     /
                                        End

我想拥有以下微服务:

  • (A) 提交检查器
  • (B) 文件下载器
  • (C) 文件处理器

我的问题是这些微服务中的每一个是否应该是顺序工作流中的一个链接,或者这些微服务是否应该只包含功能并且一个单独的“无所不知”微服务来执行工作流。

在第一种情况下,它可能看起来像

A: (1),(2) ====> B:(3) ====> C:(4i),(4ii),...,(4N)

每个链接在队列中写入一条消息,该消息被下一个链接接收。

因为 (2) 在 A 中,这意味着 A 正在决定是否调用 B。我想您可以说服务是紧密耦合的。

在我建议的其他实现中,将有一个单独的服务 X 来执行控制流并简单地将数据插入 A、B、C,这将执行单个任务,例如

A: Get latest commit
B: Download all files by commit
C: Process single file

然后 X 将拥有/执行的逻辑

  • (2),即决定是终止工作流还是进行下一步
  • 决定并行处理下载的文件

哪个实现更好?

我的另一个问题是关于存储的。 Is new commit? 部分意味着我保留了提交记录,以便我可以判断我检查的内容是否是我以前没有检查过的。 谁应该保存提交记录?应该考虑在 A 的存储中还是单独的“工作流存储”中?

【问题讨论】:

    标签: design-patterns architecture workflow microservices soa


    【解决方案1】:

    这不是微服务。那是 pico 服务,恕我直言,它们太小了,可以激发微服务所需的所有额外维护和管理。在GOTO Conference 2014Martin Fowler 的精彩演讲中,他建议每个微服务推荐几个全职开发人员。如果您至少没有一个可以全职使用该服务,那么它就太小了。

    为简单起见,您可以改用基于消息的架构,其中每个内部服务订阅来自其他内部服务的消息。

    例如,当下载完成时,您可以从FileDownloader 发送一个FileDownloaded 事件,FileProcessor 已订阅该事件。这样一来,它们之间也没有紧密耦合。

    至于消息传递库,您可以使用我的messaging library

    【讨论】:

      【解决方案2】:

      我的处理方式是成为Chain of Responsibilities,其中每个节点负责检查条件或执行工作

      例如,您的第一阶段是一个合乎逻辑的决定:

      1. “新提交?” {true|false} D
      2. 如果为真,“做事”会停止吗? (访客?)

      因此,每个节点都有可能执行终止函数(可能/可能不返回结果;我的功能主义者说应该)。

      从编码的角度来看,它可能看起来像这样:

      interface Responsibility<I> {
          fun apply(context:I) : Unit?
      }
      
      class GitRepo{
          val files = setOf<URI>()
          val commiters = setOf<String>()
          fun hasNewCommit() = true
      
      }
      
      abstract class Chained<I,N>(protected val next:Responsibility<N>) : Responsibility<I> {
      
      
      }
      class CheckCommited(next:Responsibility<Set<URI>>) : Chained<GitRepo,Set<URI>>(next) {
          override fun apply(gr:GitRepo) = when(gr.hasNewCommit()) {
              true -> next.apply(gr.files)
              false -> null
          }
      }
      class DownLoadFiles(next:Responsibility<Set<URL>>) : Chained<Set<URI>,Set<URL>>(next) {
          override fun apply(uris:Set<URI>) {
              next.apply(uris.map { downLoad(it) }.toSet())
          }
          fun downLoad(uri:URI): URL {
              return uri.toURL()
          }
      }
      
      class NotifyPeople(val people: Set<String>) : Responsibility<Set<URL>> {
      
          override fun apply(context: Set<URL>): Unit? {
              people.forEach {  context.forEach { sendMail(it.toString()) }}
          }
      
          private fun sendMail(email: String) {
      
          }
      }
      
      val root = CheckCommited(DownLoadFiles(NotifyPeople(setOf("joe@company.com","suzy@someplace.other"))))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-22
        相关资源
        最近更新 更多