目录
事件溯源简介
例子
如何使用
选择的技术
与其他事件溯源实现的比较
要求
路线图
- 下载最新的存储库存档
一个库,用于演示将事件溯源作为Azure Functions的数据持久性机制。
在最简单的情况下,事件溯源是一种存储状态(对于实体)的方式,它通过存储该实体发生的所有事件的顺序历史来工作。对实体的更改将作为附加到实体事件流末尾的新事件写入。
当查询或业务流程需要使用实体的当前状态时,它通过在事件流上运行投影来获得此状态,这是一段非常简单的代码,对于每个事件,它决定(a)我是否关心这种类型事件和(b)如果是这样,当我收到它时我该怎么办。
例子这里有一个基本的“零售银行账户”示例(作为Blazor前端)(github上的源存储库),它演示了对事件流的不同类型的操作,并且该存储库中包含的源代码。这是一个完全无服务器的系统,没有“缩放到零”的底层数据库。
如何使用该库允许您与实体的事件流进行交互,而无需在Azure Functions本身中进行任何额外的管道——既可以访问事件流,也可以通过在执行 Azure Functions时实例化的绑定变量来运行投影。
要将事件添加到事件流,请使用事件流属性和类,因此:
[FunctionName("OpenAccount")]
public static async Task OpenAccountRun(
[HttpTrigger(AuthorizationLevel.Function, "POST",
Route = "OpenAccount/{accountnumber}")]HttpRequestMessage req,
string accountnumber,
[EventStream("Bank", "Account",
"{accountnumber}")] EventStream bankAccountEvents)
{
if (await bankAccountEvents.Exists())
{
return req.CreateResponse(System.Net.HttpStatusCode.Forbidden ,
$"Account {accountnumber} already exists");
}
else
{
// Get request body
AccountOpeningData data = await req.Content.ReadAsAsync();
// Append a "created" event
DateTime dateCreated = DateTime.UtcNow;
Account.Events.Opened evtOpened = new Account.Events.Opened()
{ LoggedOpeningDate = dateCreated };
if (! string.IsNullOrWhiteSpace( data.Commentary))
{
evtOpened.Commentary = data.Commentary;
}
await bankAccountEvents.AppendEvent(evtOpened);
return req.CreateResponse(System.Net.HttpStatusCode.Created ,
$"Account {accountnumber} created");
}
}
要从事件流中获取值,您可以使用Projection属性和类:
[FunctionName("GetBalance")]
public static async Task GetBalanceRun(
[HttpTrigger(AuthorizationLevel.Function, "GET",
Route = "GetBalance/{accountnumber}")]HttpRequestMessage req,
string accountnumber,
[Projection("Bank", "Account",
"{accountnumber}", nameof(Balance))] Projection prjBankAccountBalance)
{
string result = $"No balance found for account {accountnumber}";
if (null != prjBankAccountBalance)
{
Balance projectedBalance = await prjBankAccountBalance.Process();
if (null != projectedBalance )
{
result = $"Balance for account {accountnumber} is
${projectedBalance.CurrentBalance}
(As at {projectedBalance.CurrentSequenceNumber}) ";
}
}
return req.CreateResponse(System.Net.HttpStatusCode.OK, result);
}
这两个属性的所有属性都设置为AutoResolve,以便可以在运行时设置。
选择的技术对于生产用途,尤其是对于更高容量的流,我推荐使用Azure Tables后端。
或者,因为事件流本质上是一个只能追加的系统,所以底层的存储技术可以是AppendBlob——一种特殊类型的Blob存储,它只允许将块附加到Blob的末尾。每个Blob最多可以存储50,000个事件,并且容器路径可以以与任何其他Azure Blob存储相同的方式嵌套。
存储技术和存储目标的选择可以通过应用程序上的配置设置,在每个域/实体的基础上进行切换。
Azure Functions代码基于Azure Functions SDK 2.0版,并使用C#编写。
与其他事件溯源实现的比较在这个库中,必须按需检索实体的状态——这是为了允许函数应用程序被旋转为空,并且实际上允许多个独立的Azure Functions应用程序使用相同的底层事件流,而不必有任何“永远在线”的一致性服务。
要求为了使用这个库,你需要一个能够创建存储容器和托管Azure Functions应用程序的Azure帐户。
如果您想使用通知功能,您还需要设置库将通知推送到的事件网格主题。
路线图当前版本允许在Azure表存储(推荐)或AppendBlob中存储和投影事件流支持的实体。这包括在多写多读场景中安全执行此操作所需的并发保护。
它还具有传出通知——实际上是更改提要——每当创建新实体或将新事件附加到现有实体的事件流时都会引发。这是通过事件网格完成的,以允许将这些事件溯源支持的实体大规模组装到生态系统中。
下一阶段是让通知派生触发器可以监听这些传出通知并在它们发生时触发无服务器功能,并为在Azure无服务器上创建CQRS系统提供支架。
本文最初发布于GitHub - MerrionComputing/EventsSourcing-on-Azure-Functions: A library to demonstrate doing Event Sourcing as a data persistence mechanism for Azure Functions
https://www.codeproject.com/Articles/5205463/Event-Sourcing-on-Azure-Functions