基于事件驱动架构构建微服务第8部分:在应用程序上实现事件溯源
原文鏈接:https://logcorner.com/building-microservices-through-event-driven-architecture-part8-implementing-eventsourcing-on-application/
在本文中,我將討論應(yīng)用程序上的事件溯源實(shí)現(xiàn)。
該層圍繞領(lǐng)域并實(shí)現(xiàn)用例(特定于應(yīng)用程序的業(yè)務(wù)規(guī)則)。
它編排數(shù)據(jù)流并使用領(lǐng)域模型和基礎(chǔ)架構(gòu),并且不依賴于數(shù)據(jù)庫、UI或特殊框架。
出于我們的事件溯源系統(tǒng)的目的,我將從聚合中取出所有未提交的事件并調(diào)用倉儲的函數(shù),該函數(shù)負(fù)責(zé)將事件保存在事件存儲中。所以我會調(diào)用IEventStoreRepository 的AppendAsync(EventStore @event)函數(shù)。
因?yàn)槲疫€沒有實(shí)現(xiàn)更新,所以我不會關(guān)心聚合版本,(我有一個創(chuàng)建語音的post方法,所以聚合版本將始終等于0)。當(dāng)我實(shí)現(xiàn)更新時,我會關(guān)注應(yīng)用層和表現(xiàn)層中的聚合版本。
事件溯源接口
我可以定義兩個接口IEventSourcingSubscriber和IEventSourcingHandler,您可以使用另一種命名約定,但現(xiàn)在我保留它們原樣。
Subscribe 一個函數(shù),它從聚合中獲取所有未提交的事件,并為每個事件調(diào)用一個函數(shù)Handle,該函數(shù)將事件和當(dāng)前聚合版本作為輸入。
Handle是將事件序列化為字符串并調(diào)用IEventStoreRepository的AppendAsync(EventStore @event)的函數(shù)。
事件溯源實(shí)現(xiàn)
事件資源訂閱者實(shí)現(xiàn)
所以第一個測試應(yīng)該是:沒有未提交事件的訂閱不應(yīng)該調(diào)用Handle
我沒有未完成的事件,我什么也不做。然后斷言部分將如下所示:
mockEventSourcingHandler.Verify(m?=>?m.Handle(It.IsAny<Event>(),It.IsAny<long>()),?Times.Never,?“Handle?must?not?be?called”);測試用例1:沒有未提交事件的訂閱不應(yīng)調(diào)用Handle:
到這里,我將完成我的函數(shù)的實(shí)現(xiàn)
測試用例2:訂閱未提交的事件應(yīng)該只調(diào)用一次Handle:
mockEventSourcingHandler.Verify(m?=>?m.Handle(It.IsAny<Event>(),It.IsAny<long>()),?Times.Once,?“Handle?must?be?called?only?once”).在Assert部分,我可以驗(yàn)證Handle函數(shù)僅被調(diào)用一次。
EventSourcingSubscriber的最終實(shí)現(xiàn)應(yīng)該是這樣的:
我為每個事件調(diào)用Handle函數(shù)。
事件源處理程序?qū)崿F(xiàn)
測試用例3:處理空事件應(yīng)該引發(fā)EventNullException:
我模擬了一些依賴項(xiàng)并驗(yàn)證如果事件為空,那么Handle應(yīng)該引發(fā)異常。
下面是測試的實(shí)現(xiàn)。
測試用例34:處理事件應(yīng)調(diào)用AppendAsync:
這里我驗(yàn)證如果事件不為空,那么Handle應(yīng)該調(diào)用AppendAsync
下面是測試的實(shí)現(xiàn)。您可以觀察到我使用 IEventSerializer 接口將事件序列化為 json 字符串,此 json 字符串將作為事件流的有效負(fù)載。
更新REGISTERSPEECHUSECASE
然后更新RegisterSpeechUseCase并調(diào)用Subscribe函數(shù):await _domainEventSubscriber.Subscribe(speech);
更新PRESENTATION
打開Startup.cs文件并配置一些依賴注入
打開appsettings.Development.json并更新ConnectionStrings以使用適當(dāng)?shù)臄?shù)據(jù)庫服務(wù)器、數(shù)據(jù)庫名稱和憑據(jù)。
創(chuàng)建數(shù)據(jù)庫的腳本位于LogCorner.EduSync.Speech.Database項(xiàng)目中
使用POSTAMAN測試
使用VISUAL STUDIO測試本地代碼
選擇LogCorner.EduSync.Speech.Presentation項(xiàng)目并點(diǎn)擊F5
啟動postman并運(yùn)行以下HTTP Post
Endpoint?:?http://localhost:62694/api/speechMethod?:?POSTContent-Type:?application/jsonBody?:?{ “Title”:”Le?Lorem?Ipsum?est?simplement?du?faux?texte”, “Description”:”Le?Lorem?Ipsum?est?simplement?du?faux?texte?employé?dans?la?composition?et?la?mise?en?page?avant?impression.?Le?Lorem?Ipsum?est?le?faux?texte?standard?de?l’imprimerie?depuis?les?années?1500,?quand?un?imprimeur?anonyme?assembla?ensemble?des?morceaux?de?texte?pour?réaliser?un?livre?spécimen?de?polices?de?texte”, “Url”:”http://www.yahoo_1.fr”, “Type”:”3″ }打開Sql Server Management Studio并運(yùn)行以下命令:
SELECT * FROM [LogCorner.EduSync.Speech.Data].[dbo].[Speech] SELECT * FROM [LogCorner.EduSync.Speech.Data].[dbo].[EventStore]
結(jié)果應(yīng)該是這樣的:
應(yīng)該在Speech表和EventStore表上有記錄,版本始終為零,因?yàn)楸窘坛滩话ǜ隆?/p>
使用Docker測試本地代碼
找到\LogCorner.EduSync.Command\src文件夾(docker-compose.yml文件所在的文件夾)并運(yùn)行以下命令
docker-compose?build docker-compose?up docker?ps?–all?–format?“table?{{.ID}}\t{{.Image}}\t{{.Names}}”啟動postman并運(yùn)行以下 HTTP Post
最后,像這樣檢查正在運(yùn)行的容器:
通過運(yùn)行以下命令打開bash shell(其中0b是logcorner.edusync.speech.presentation.data容器Id的首字母)
Docker?exec?-it?0b?“bash”連接到sql server linux
/opt/mssql-tools/bin/sqlcmd?-S?localhost?-U?SA?-P?‘PassW0rd’運(yùn)行sql查詢
use?[LogCorner.EduSync.Speech.Database] goselect?*?from?[dbo].[Speech] goselect?*?from?[dbo].[eventstore] go應(yīng)該在Speech表和EventStore表上有記錄,版本始終為零,因?yàn)楸窘坛滩话ǜ隆?/p>
本文的源代碼可在此處獲得 (Feature/Task/EventSourcingApplication)
https://github.com/logcorner/LogCorner.EduSync.Speech.Command/tree/Feature/Task/EventSourcingApplication
總結(jié)
以上是生活随笔為你收集整理的基于事件驱动架构构建微服务第8部分:在应用程序上实现事件溯源的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多线程环境下,程序真是危机四伏
- 下一篇: C#新版本风格项目文件(SDK风格项目