milhojas / eventsourcing
一个用于启动事件源模式的简单库
Requires
- php: ^5.6 || ^7.0
- doctrine/dbal: ^2.5
- milhojas/messaging: ^1.1
- ramsey/uuid: ^3.5
- symfony/console: ^3.2
- symfony/yaml: ^3.2
Requires (Dev)
- mikey179/vfsstream: ^1.6
- phpspec/phpspec: ^3.2
- phpunit/phpunit: ^5.7
README
一个简单的事件源库
这是一个正在进行中的项目。
事件源是一种处理应用程序状态管理的方法。我们不是保留域实体的当前状态,而是存储导致该状态的序列事件或更改。
这为我们自动提供了系统完整变更历史。正如Fowler所说,我们可以通过一个巧妙的日志系统实现相同的效果,但事件源是基于这样一个事实:域对象完全通过事件进行管理,因此我们可以
- 在任意时刻重新运行事件来重建系统的状态。
- 在任意时刻查询系统状态。
- 重新播放事件以修复错误。
https://martinfowler.com.cn/eaaDev/EventSourcing.html
事件源失败的一个方面是查找事物。例如,一个简单的按条件查找非常难以编写。因此,事件源最好与CQRS模式结合使用。
CQRS模式(命令查询责任分离)中,写操作和读操作是完全分离的,由不同的代理管理,并通过事件进行通信。这意味着我们有一个写模型和一个读模型,它们可以独立生活和演化。
以下是一个示例来更好地理解这一点
想象我们的系统发送一个创建博客文章的命令,包括相应的标题、正文和作者数据。文章创建后,会触发一个事件来宣布已创建了一个新的文章(甚至可以触发额外的事件,如文章已发布事件)。事件存储保留此类事件(写模型),并通过消息总线将事件传递给系统。几个监听器可能随后对此事件做出响应,根据应用需求创建几个相应的读模型。例如:构建完整的文章静态视图,或更新数据库中发布的文章列表表,以便对其执行查询。
这种方法的优点之一是,你可以通过添加新的监听器或重新运行事件故事来更改现有的监听器来创建新的视图。这些更改不仅反映在应用它们的时间点上,而且你可以从开始重建整个系统。
## 安装
使用Composer依赖
composer require milhojas/eventsourcing
设置
你需要一个文件来配置与数据库服务器的连接。项目根目录下的预定义位置是
app/config/database.yml
config/database.yml
config/config.yml
database.yml
config.yml
结构与Symfony应用中的结构相同。
doctrine:
dbal:
default_connection: 'example'
connections:
test:
driver: 'pdo_mysql'
user: 'root'
password: 'root'
dbname: 'testmilhojas'
host: 'localhost'
charset: utf8mb4
travis:
driver: 'pdo_mysql'
user: 'root'
dbname: 'testmilhojas'
host: 'localhost'
charset: utf8mb4
已知问题:事件源不能使用Symfony doctrine:dbal配置数据
在数据库中创建事件表
运行以下命令
bin/eventsourcing events:setup
使用-v标志查看正在发生的事情
bin/eventsourcing events:setup -v
已知问题:表名为'events',无法配置
然后你就可以运行了。
## 关键概念
事件
事件是一个消息,它传达了过去发生的事情,并且对系统的任何其他部分都可能是有趣的。系统的任何部分都可以引发事件,系统的任何其他部分都可以监听该事件。
在事件源范式中,域实体通过引发事件来传达它们的状态变化。实际上,它们被构建成这样,即它们将事件应用于状态更改。我们使用“传统”方法来封装这一点,例如,通过公开实体的公共接口,通过命令来管理它们。
事件包含有关变更所需的所有信息。例如,UserAddProductToBasket 事件必须包含有关用户、产品、购物车和产品数量的信息。
事件消息
事件消息是事件的封装。它携带事件本身及其元数据信息,例如id、实体信息和版本,以及任意元数据。
内部,事件消息使用事件封装对象(已弃用)和实体对象,这些对象携带重建实际实体所需的最小数据(类名、id和版本)。
注意:为了清晰起见,实体可以重命名为EntityMetadata。
事件流
事件流是一系列事件消息的集合,可以构建具体的EventSourcedEntity。
事件源实体
在我们的实现中,事件源实体是通过事件源来工作的实体。EventSourcedEntity是一个抽象基类,它提供了实现此功能的基本工具。这些工具包括
- 一个重建构造函数方法,该方法获取事件流并将其应用于实体以重新生成它。
- 事件流和存储实体将引发的事件的方法。
- 一个用于传达已应用事件的方法。
- 版本跟踪。
事件源实体是版本化的,因为每个事件都意味着实体的一个新版本。这应该得到控制,以确保在需要时正确地版本化状态。
事件存储
正如其名所示,事件存储是存储事件的地方。事件存储本身是一个抽象概念。我们提供基于内存的事件存储和基于数据库的事件存储。严格来说,事件存储保持事件消息。
事件存储可以看作是一个平面表,存储事件和元数据信息,以便在需要时重放。我们可以为所有实体使用一个独特的事件存储,也可以不使用。我们的实现是基本的,但它可以扩展以支持其他存储。您可以将实体“存储”为存储应用于它们的事件,并且您可以通过读取它们存储的所有事件来“读取”实体,直到达到所需的版本。
快照
存储许多事件并必须检索所有这些事件以重建实体可能是某些系统中的巨大且缓慢的任务。解决此问题的一个解决方案是创建一个快照系统,该系统可以在实体历史的某个点上“固定”其实体的状态,这样我们只需要检索一小部分新事件来重建它。
迄今为止,我们没有提供快照。基本思想是在对象的故事中确定一个我们可以用作起点并从那里获取新事件的点。例如,想象一个博客系统,当帖子被标记为发布时,我们会快照帖子,因为我们不期望在此之后更改它们。
更多文档即将推出...