日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于事件驱动架构构建微服务第9部分:处理更新

發(fā)布時間:2023/12/4 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于事件驱动架构构建微服务第9部分:处理更新 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文鏈接:https://logcorner.com/building-microservices-through-event-driven-architecture-part10-handling-updates-and-deletes/

在本文中,我將討論如何處理事件溯源系統(tǒng)上的更新。

在前面的步驟中,我將系統(tǒng)的所有業(yè)務變化存儲為事件,而不是存儲當前狀態(tài)。我通過將所有事件應用于聚合來重建當前狀態(tài)。

我已經建立了一個領域事件列表:過去發(fā)生的業(yè)務變化以通用語言表達:例如ThePackageHasBeenDeliveredToCustomer。

領域事件是不可變的,當事件發(fā)生時它不能改變。

因此,要糾正事件中的錯誤,我必須創(chuàng)建一個具有正確值的補償事件,例如銀行帳戶交易。

聚合記錄已提交的事件并保護業(yè)務不變量。這是事務邊界。為了處理并發(fā),我將使用帶有版本控制的樂觀并發(fā)控制 (OCC)。

在不獲取鎖的情況下,每個事務都會驗證沒有其他事務修改了它所讀取的數(shù)據(jù)。如果數(shù)據(jù)沒有改變,則提交事務,如果數(shù)據(jù)被其他人改變,則事務回滾并可以重新啟動。

使用版本控制,用戶讀取聚合的當前狀態(tài),然后發(fā)送帶有版本號的命令,如果版本號與聚合的當前版本匹配,則提交事務。

如果版本號與聚合的當前版本不匹配,在這種情況下,這意味著數(shù)據(jù)已被其他人更新。所以用戶應該再次讀取數(shù)據(jù)以獲得正確的版本并重試。

在本教程中,我將展示如何更新語音實體。它具有以下屬性:標題、描述、網址和類型。所以每個屬性的更新都是一個事件,應該存儲在事件存儲中。

處理領域模型的更新

處理更新標題

測試用例1:當title為null或為空時,ChangeTitle應引發(fā)ArgumentNullAggregateException:

在這里,我將測試如果Title為NullOrEmpty,則系統(tǒng)應該引發(fā)異常。

測試用例2:當預期版本不等于聚合版本時的ChangeTitle應該引發(fā)ConcurrencyException:

在這里我將測試如果預期版本不等于聚合版本,則系統(tǒng)應該引發(fā)異常。

因為我創(chuàng)建了一個新語音,聚合版本等于0,所以如果我將expectedVersion設置為1,測試應該會引發(fā)異常。

測試用例3:具有有效參數(shù)的ChangeTitle應應用SpeechTitleChangedEvent:

在這里我將測試,如果沒有錯誤,則應將newTitle應用于演講的標題。換句話說:Speech.Title = “更新后新標題的值”

由于Apply函數(shù)將事件應用于聚合,因此語音的標題應等于SpeechTitleChangedEvent值的標題。

ChangeTitle最終實現(xiàn):

ChangeTitle的最終實現(xiàn)應該是這樣的。

很簡單,我的標題不為空或為空,應用SpeechTitleChangedEvent。apply函數(shù)使用事件SpeechTitleChangedEvent的值設置演講標題。

檢查聚合版本的代碼是在前面的步驟中開發(fā)的(參見aggregateroot.cs類)

public?void?ValidateVersion(long?expectedVersion) { if?(Version?!=?expectedVersion) { throw?new?ConcurrencyException($@”Invalid?version?specified?:?expectedVersion?=?{Version}??but?originalVersion?=???{expectedVersion}.”); } }

處理更新DESCRIPTION、URL和TYPE

ChangeDescription、ChangeUrl和ChangeType應遵循與ChangeTitle相同的場景

處理申請更新

處理更新標題

測試用例1:當Command為空時處理更新應該引發(fā)ApplicationArgumentNullException :

在這里我將測試如果updateCommand為空,那么系統(tǒng)應該引發(fā)異常。

所以我應該模擬所有外部依賴項:IUnitOfWork、ISpeechRepository和IEventSourcingSubscriber

我將提供一個空命令并驗證是否引發(fā)了ApplicationArgumentNullException。

測試用例2:當語音不存在時處理更新應該引發(fā)ApplicationNotFoundException:

這里我將測試如果要更新的語音不存在,那么系統(tǒng)應該引發(fā)異常(ApplicationNotFoundException)。

我必須安排我的存儲庫,以便它返回帶有模擬的空語音:

moqEventStoreRepository.Setup(m?=>?m.GetByIdAsync<Domain.SpeechAggregate.Speech>(command.SpeechId)) .Returns(Task.FromResult((Domain.SpeechAggregate.Speech)null));

就像這樣。

測試用例3:當命令不為空時處理更新應更新語音標題:

這里我測試一下,如果命令不為空,并且數(shù)據(jù)庫中存在要更新的語音,則應該更新標題。

驗證語音標題是否被修改的一種方法是在將其發(fā)送到存儲庫之前檢查它的值,它應該等于新標題的值:

moqSpeechRepository.Verify(m?=> m.UpdateAsync(It.Is<Domain.SpeechAggregate.Speech>(n?=> n.Title.Value.Equals(command.Title) )),Times.Once);

測試用例4:當預期版本不等于聚合版本時處理更新應該引發(fā)ConcurrencyException:

在這里我將測試如果預期版本不等于聚合版本,那么系統(tǒng)應該引發(fā)異常。

聚合等于零,因為我實例化了一個新的語音,然后如果expectedversion不等于零,則系統(tǒng)應該引發(fā)ConcurrencyException。

處理倉儲更新

處理更新

測試用例1:當Speech為空時處理更新應該引發(fā)RepositoryArgumentNullException :

測試用例2:當語音不存在時處理更新應該引發(fā)NotFoundRepositoryException

測試用例3:當語音有效且存在時處理更新應執(zhí)行更新

以及最終的實現(xiàn)

處理PRESENTATION的更新

處理更新

測試用例1:當ModelState無效時更新語音應返回BadRequest:

測試用例2:發(fā)生異常時的UpdateSpeech應引發(fā)InternalServerError

同上注冊語音(ExceptionMiddleware)

測試用例3:當ModelState有效且沒有錯誤時更新語音應該返回Ok

以及最終的實現(xiàn)

用POSTMAN測試

按F5并啟動postman和sql server。

讓我們啟動sql server看看發(fā)生了什么 讓我們運行一個select查詢,你可以看到[dbo].[Speech]和[dbo].[EventStore]這兩個表是空的。

讓我們啟動postman并運行一個post請求來創(chuàng)建一個演講:http://localhost:62694/api/speech

postman腳本在這里:LogCorner.EduSync.Command\src\Postman\BLOG.postman_collection.json

現(xiàn)在我應該有一個新創(chuàng)建的演講和一個事件LogCorner.EduSync.Speech.Domain.Events.SpeechCreatedEvent, LogCorner.EduSync.Speech.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 請注意,版本等于 0。對于每個新語音,版本應為零。

如果我檢查有效載荷,我必須看到我的事件

{ “Title”:?{ “Value”:?“Le?Lorem?Ipsum?est?simplement?du?faux?texte” }, “Url”:?{ “Value”:?“http://www.yahoo_1.fr” }, “Description”:?{ “Value”:?“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” }, “Type”:?{ “Value”:?3 }, “AggregateId”:?“7c8ea8a0-1900-4616-9739-7cb008d37f74”, “EventId”:?“a688cc8a-ed56-4662-bbad-81e66ed917a0”, “AggregateVersion”:?0, “OcurrendOn”:?“2020-01-19T15:49:59.3913833Z” }

為了更新演講的標題,我運行以下請求 http://localhost:62694/api/speech 這是一個PUT請求。

我拿到了新建語音的標識符CF17D255-9991-4B7B-B08E-F65B54AA9335 讓我們從sql復制并將其粘貼到請求正文中。

好的,現(xiàn)在我可以運行put查詢

回到sql server驗證結果

SELECT * FROM [dbo].[Speech]

SELECT * FROM [dbo].[EventStore]

我應該看到更新的標題和一個新事件LogCorner.EduSync.Speech.Domain.Events.SpeechTitleChangedEvent。

版本應為 1,有效負載應為更新事件

{ “Title”:?“UPDATE_1__Le?Lorem?Ipsum?est?simplement?du?faux?texte”, “AggregateId”:?“7c8ea8a0-1900-4616-9739-7cb008d37f74”, “EventId”:?“de253f69-ea89-4a54-8927-e09553cc43c7”, “AggregateVersion”:?1, “OcurrendOn”:?“2020-01-19T15:55:14.1734365Z” }

本文的源代碼可在此處獲得 (Feature/Task/EventSourcingApplication)

https://github.com/logcorner/LogCorner.EduSync.Speech.Command/tree/Feature/EventSourcingHandlingUpdates

總結

以上是生活随笔為你收集整理的基于事件驱动架构构建微服务第9部分:处理更新的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。