复杂作业聚合

Complicated job aggregate

我的工作流程非常复杂,我不是 100% 清楚在哪里处理什么。 我不想有代码,这只是谁负责什么的问题。

给定如下:

  1. 有根目录"C:\server"
  2. 里面有两个目录"ftp"和"backup"

想象一下以下过程:

  1. 外部客户将文件发送到 ftp 目录。
  2. 导入器应用程序获取文件,现在乐趣开始了。
  3. 必须为此文件创建作业聚合。
  4. 命令 "CreateJob(string file)" 被触发。 ?。文件必须从 ftp 移动到备份。在 CommandHandler 内部或在 Aggregate 内部或在 JobCreated 事件上?
  5. StartJob(Guid jobId) 被调用。必须创建第三个文件夹 "in-progress",必须将文件从备份复制到进行中。谁做的?

所以我不清楚如果聚合在没有正确的文件系统的情况下无法正常工作,那么文件系统的事情必须在哪里处理。 因为我的第一种方法是在基础结构 layer/lib 中执行此操作,它会侦听来自作业层的事件。但似乎不是100%正确?!

最重要的是,重放有什么用? 您无法重播已移动的 things/files,您必须以某种方式模拟客户将文件发送到 ftp 文件夹...

感谢解答

I have a very complicated job process and it's not 100% clear to me where to handle what. I don't want to have code, it just the question who is responsible for what.

通常的答案是领域模型——也就是 "aggregate" 做出决定并保存它们。观察这些决定,一些事件处理程序会产生副作用。

And top of this, what is with replaying? You can't replay things/files that where moved, you have to somehow simulate that a customer sends the file to the ftp folder...

您将事件重播到聚合,以便它恢复到它做出最后决定时的状态。这与重播 副作用 不同——这是在其他地方处理副作用的部分动机。

当然,在可能的情况下,您希望副作用是幂等的,这样重复的消息就不会造成问题。但是注意,从模型的角度来看,副作用成功与否其实并不重要

The file have to be moved from ftp to backup. Inside the CommandHandler or inside the Aggregate or on JobCreated event?

在这种情况下,我将文件移动到 Application 服务中的目标文件夹,该服务将命令发送到 Aggregate(或调用 Aggregate, 是一样的) 命令发送Aggregate 之前。这样,如果文件系统存在一些问题(没有足够的权限或 space 不可用等),则不会发送命令。这类问题不应该影响到我们 Aggregate。我们最保护它不受基础设施的影响。事实上,我们应该将 Aggregate 与其他任何东西隔离开来;它必须仅包含用于决定生成哪些事件的纯业务逻辑

Because my first approach was to do that inside an Infrastructure layer/lib which listen to the events from the job layer. But it seems not 100% correct?!

的确,这对我来说似乎过于工程化了。你必须亲亲。

StartJob(Guid jobId) get's called. A third folder have to be created "in-progress", File have to be copied from backup to in-progress. Who does it?

调用 StartJob 的人可以在调用 StartJob 之前进行移动。同样,保持 Aggregate 纯净。在这种情况下,这取决于您的 framework/domain 详细信息。

And top of this, what is with replaying? You can't replay things/files that where moved, you have to somehow simulate that a customer sends the file to the ftp folder...

事件从事件存储中加载并在两种情况下重播:

  1. 在每个命令发送到 Aggregate 之前,Aggregate Repository 从事件存储中加载所有事件然后它 应用 他们每个人都到 Aggregate,可能在聚合上调用一些 applyThisEvent(TheEvent) 方法。因此,此方法应该没有副作用(纯),否则您会在每次执行命令时一次又一次改变外部世界,而您不希望这样。

  2. 向用户呈现数据的read-modelsprojectionsquery-models)监听这些事件并更新保存数据的数据库表用户看到的。事件在生成后以及每次重新创建读取模型时都会发送到这些读取模型。当您 发明 一个新的 read-model 时,您必须将 aggregates 之前生成的所有事件传递给它,以便构建 correct/complete 状态在他们。如果您的阅读模型的事件侦听器有副作用,您认为当您 重播 那些很久以前的事件时会发生什么?外面的世界一次又一次地被修改,你不想要那样!读取模型只解释事件,它们不会生成其他事件,也不会改变外部世界。

当事件到达另一种类型的模型时,还有一种特殊的第三种情况,Saga。一个Saga必须只接收一次事件!这就是你想在 Because my first approach was to do that inside an Infrastructure layer/lib which listen to the events from the job layer 中使用的情况。你可以在你的情况下这样做,但不是 KISS。