Rust中的事件溯源 - ariseyhun
Rust 是一種與事件溯源藝術相結合的令人難以置信的語言。
這篇博文的目的是介紹我一直在全職工作的一個名為Thalo的專案。
它是一個 Rust 庫,提供構建事件源系統所需的一切。
目前,Thalo 提供:
- 具有基本聚合、事件、事件儲存和事件流特徵的核心板條箱,以及一些派生宏
- 測試庫(Given-When-Then)
- Postgres、記憶體和檔案事件儲存
- 卡夫卡事件流
您可以透過克隆專案並在單獨的終端選項卡中執行客戶端和伺服器來執行示例。
$ git clone git@github.com:thalo-rs/thalo.git && cd thalo $ cargo run -p example-protobuf --bin server # In separate terminal tab $ cargo run -p example-protobuf --bin client |
由於Thalo提供的派生宏,編寫聚合體並不費力,但我仍然覺得缺少一些東西。我已經研究了CloudEvents和AsyncAPI作為定義聚合模式的選擇,但它們似乎並不擅長這樣做。
ESDL
事件源模式定義語言是一種模式語言,用於定義集合體、命令、事件和型別,可用於在Rust中生成程式碼,大大簡化了集合體的模板。網址
examples > bank-account > B bank-account.esdl 1 aggregate BankAccount { open_account(initial_balance: Float!): OpenedAccount! 3 deposit_funds(amount: Float!): DepositedFunds! 4 withdraw_funds(amount: Float!): WithdrewFunds! 5 } 6 7 event OpenedAccount { 8 initial_balance: Float! 9 } 10 11 event DepositedFunds { 12 amount: Float! 13 } 14 15 event WithdrewFunds { 16 I amount: Float! ¹⁷ } 18 |
如果你熟悉GraphQL,它是不言自明的,但讓我們一行一行地看下去。
- aggregate BankAccount {
一個esdl檔案總是必須精確地定義一個聚合體,在我們的例子中名為BankAccount。 - open_account(initial_balance: Float!): OpenedAccount!
我們定義了一個名為open_account的命令,它需要一個初始餘額的浮動值,併產生一個OpenedAccount事件。
注意!這意味著型別是必須的,不能是未定義/空/無。 - deposited_funds(amount: Float!): DepositedFunds!
withdrew_funds(amount: Float!): WithdrewFunds!: WithdrewFunds!
如上所述,這些也是接受一個金額並返回一個事件的命令。 - event OpenedAccount {
這裡我們定義了OpenedAccount事件和它的可用欄位。 - initial_balance: Float!
開戶事件有一個初始餘額,要求有一個浮動值。
......其餘的就很好解釋了。
在這一點上,我們有一個用於事件源的Rust庫,和一個用於定義聚合的模式語言。如果我們把這兩者結合起來,我們就可以用esdl檔案來實現模式,而用Rust來透過程式碼生成來實現。
為了從這個esdl檔案中生成Rust程式碼,我們可以使用build.rs檔案並使用esdl crate進行編譯。
// build.rs fn main() -> Result<(), Box<dyn std::error::Error>> { esdl::configure() .add_schema_file("./bank-account.esdl")? .compile()?; Ok(()) } |
而在我們的Rust程式碼中,我們可以使用Thalo提供的宏來匯入它。
thalo::include_aggregate!("BankAccount"); |
這將包括生成的程式碼,其中包括:
- trait BankAccountCommand
- enum BankAccountEvent
- struct OpenedAccountEvent
- struct DepositedFundsEvent
- struct WithdrewFundsEvent
由此,我們可以開始執行命令:
use thalo::aggregate::{Aggregate, TypeId}; #[derive(Aggregate, Clone, Debug, Default, PartialEq, TypeId)] pub struct BankAccount { id: String, opened: bool, balance: f64, } impl BankAccountCommand for BankAccount { type Error = (); fn open_account(&self, initial_balance: f64) -> Result<OpenedAccountEvent, Self::Error> { ... } fn deposit_funds(&self, amount: f64) -> Result<DepositedFundsEvent, Self::Error> { ... } fn withdraw_funds(&self, amount: f64) -> Result<WithdrewFundsEvent, Self::Error> { ... } } |
然後用apply函式來更新聚合狀態:
fn apply(bank_account: &mut BankAccount, event: BankAccountEvent) { use BankAccountEvent::*; match event { OpenedAccount(OpenedAccountEvent { initial_balance }) => {}, DepositedFunds(DepositedFundsEvent { amount }) => {}, WithdrewFunds(WithdrewFundsEvent { amount }) => {}, } } |
Thalo和ESDL將讓您在為事件源系統編寫乾淨且一致的聚合方面領先一步。
我正在積極地全職開發 Thalo,並希望在未來幾個月內釋出一些實質性的東西,敬請期待!
相關文章
- 事件流與事件溯源事件
- 事件協作和事件溯源事件
- PHP 事件溯源PHP事件
- .NET Core中的事件溯源開源專案事件
- 剖玄析微聚合 - 事件溯源事件
- Chronicle事件溯源的最佳實踐事件
- Python的事件溯源開源庫Python事件
- 事件溯源中的時間和時間建模 - Tomasz Jaskula事件
- 事件溯源全指南 - Arkwrite事件
- 事件消費者之 Saga - 事件溯源事件
- 事件消費者之 Reactor - 事件溯源事件React
- 事件消費者之 Projector - 事件溯源事件Project
- .NET的事件溯源構建庫:Eventuous事件
- 使用Kafka實現事件溯源Kafka事件
- 事件溯源與流水賬的結賬模式事件模式
- MySQL的事件溯源Event Sourcing表結構MySql事件
- 事件溯源:是來自事件的狀態與作為狀態的事件? - verraes事件
- 如何在Java後端中實現事件驅動架構:從事件匯流排到事件溯源Java後端事件架構
- .NET分散式Orleans - 6 - 事件溯源分散式事件
- Spring Boot和EventStoreDB事件溯源案例Spring Boot事件
- Occcurrent:JVM事件溯源工具庫包JVM事件
- 從 CRUD 遷移到事件溯源的祕訣 - eventstore事件
- 拯救祭天的程式設計師——事件溯源模式程式設計師事件模式
- 審計系統的一劑良方——事件溯源事件
- HomeAway分享雲端事件溯源經驗事件
- Java反應式事件溯源:領域Java事件
- 從入門到放棄 - 事件溯源事件
- 從增刪改查到事件溯源 - PHP事件PHP
- 如何讓客戶方便地使用事件溯源?事件溯源有什麼好處?- daryush_d事件
- 使用Datomic實現沒有麻煩的事件溯源事件
- 事件溯源的優點並不能兌現 - Jimmy Bogard事件
- 函式化事件溯源的決策者模式 - thinkbeforecoding函式事件模式
- Java中的事件溯源簡介:包含學習進度的練習工具包Java事件
- 事件溯源的好處在於可在軟體中捕獲現實世界 – Jessitron事件
- 無伺服器與事件溯源結合的演示案例:將事件溯源作為Azure函式的資料持久化機制的庫伺服器事件函式持久化
- 事件溯源:投影或投射模式 -Kacper Gunia事件模式
- 如何遷移到微服務和事件溯源EventSourcing微服務事件
- 說服您的CTO使用事件溯源 -Event Store Blog事件