From 5093ac2f3c1fa1122dfedf247733eef688c8d7a6 Mon Sep 17 00:00:00 2001 From: Jerry Bai Date: Sat, 25 Apr 2020 14:59:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Eventual2PC.code-workspace | 8 ++ Makefile | 9 ++ README.md | 106 +++++++++++++++++- src/Eventual2PC.sln | 34 ++++++ ...InitiatorAllParticipantPreCommitSucceed.cs | 26 +++++ ...nInitiatorAnyParticipantPreCommitFailed.cs | 26 +++++ ...ctionInitiatorCommittedParticipantAdded.cs | 24 ++++ ...nitiatorPreCommitFailedParticipantAdded.cs | 24 ++++ ...itiatorPreCommitSucceedParticipantAdded.cs | 24 ++++ ...tionInitiatorRolledbackParticipantAdded.cs | 24 ++++ ...ransactionInitiatorTransactionCompleted.cs | 24 ++++ ...ITransactionInitiatorTransactionStarted.cs | 19 ++++ .../ITransactionParticipantCommitted.cs | 17 +++ .../ITransactionParticipantPreCommitFailed.cs | 35 ++++++ ...ITransactionParticipantPreCommitSucceed.cs | 17 +++ .../ITransactionParticipantRolledback.cs | 17 +++ src/Eventual2PC/Eventual2PC.csproj | 22 ++++ src/Eventual2PC/ITransactionInitiator.cs | 45 ++++++++ src/Eventual2PC/ITransactionParticipant.cs | 26 +++++ src/Eventual2PC/ITransactionPreparation.cs | 44 ++++++++ src/Eventual2PC/TransactionParticipantInfo.cs | 56 +++++++++ src/Eventual2PC/TransactionPreparationBase.cs | 74 ++++++++++++ src/Eventual2PC/TransactionPreparationInfo.cs | 65 +++++++++++ .../UnknownTransactionPreparationException.cs | 29 +++++ 24 files changed, 794 insertions(+), 1 deletion(-) create mode 100644 Eventual2PC.code-workspace create mode 100644 Makefile create mode 100644 src/Eventual2PC.sln create mode 100644 src/Eventual2PC/Events/ITransactionInitiatorAllParticipantPreCommitSucceed.cs create mode 100644 src/Eventual2PC/Events/ITransactionInitiatorAnyParticipantPreCommitFailed.cs create mode 100644 src/Eventual2PC/Events/ITransactionInitiatorCommittedParticipantAdded.cs create mode 100644 src/Eventual2PC/Events/ITransactionInitiatorPreCommitFailedParticipantAdded.cs create mode 100644 src/Eventual2PC/Events/ITransactionInitiatorPreCommitSucceedParticipantAdded.cs create mode 100644 src/Eventual2PC/Events/ITransactionInitiatorRolledbackParticipantAdded.cs create mode 100644 src/Eventual2PC/Events/ITransactionInitiatorTransactionCompleted.cs create mode 100644 src/Eventual2PC/Events/ITransactionInitiatorTransactionStarted.cs create mode 100644 src/Eventual2PC/Events/ITransactionParticipantCommitted.cs create mode 100644 src/Eventual2PC/Events/ITransactionParticipantPreCommitFailed.cs create mode 100644 src/Eventual2PC/Events/ITransactionParticipantPreCommitSucceed.cs create mode 100644 src/Eventual2PC/Events/ITransactionParticipantRolledback.cs create mode 100644 src/Eventual2PC/Eventual2PC.csproj create mode 100644 src/Eventual2PC/ITransactionInitiator.cs create mode 100644 src/Eventual2PC/ITransactionParticipant.cs create mode 100644 src/Eventual2PC/ITransactionPreparation.cs create mode 100644 src/Eventual2PC/TransactionParticipantInfo.cs create mode 100644 src/Eventual2PC/TransactionPreparationBase.cs create mode 100644 src/Eventual2PC/TransactionPreparationInfo.cs create mode 100644 src/Eventual2PC/UnknownTransactionPreparationException.cs diff --git a/Eventual2PC.code-workspace b/Eventual2PC.code-workspace new file mode 100644 index 0000000..876a149 --- /dev/null +++ b/Eventual2PC.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c3f8f68 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +all: pack + +pack: build + mkdir -p `pwd`/packages + dotnet pack -c Release `pwd`/src/Eventual2PC/ + mv `pwd`/src/Eventual2PC/bin/Release/*.nupkg `pwd`/packages/ + +build: + dotnet build -c Release `pwd`/src/Eventual2PC/ diff --git a/README.md b/README.md index 199a35a..48ac6b0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,106 @@ # Eventual2PC -最终一致性二阶段提交范式,简化多聚合根之间交互事务的实现。 + +最终一致性二阶段提交范式,简化多聚合根之间交互事务的实现。任何基于cqrs + eda 实现多聚合根最终一致性的框架,都可使用。 + +## 安装 + +``` +dotnet add package Eventual2PC +``` + +## 范式 + +### 术语定义 + +- `Initiator`: 作为事务发起方,它是聚合根 + +- `Participant`: 作为事务参与方(仅被修改的聚合根,新增的,不会产生业务失败问题),它是聚合根 + +- `Preparation`: 事务准备,对应一个具体的业务修改动作;同一个 `Participant` 参与多个事务时,应定义多个事务准备 + +- `Transaction`: 2PC事务,从开始事务,到事务完成,贯穿整个事务生命周期;可以只是一个标识ID(通常使用 `TransactionStarted` 事件的ID),也可以使用代表事务的聚合根(如银行转账的转账事务聚合根) + +- `ProcessManager`: CQRS中的概念,作为事务相关消息路由的角色,负责响应 `DomainEvent`、`DomainException` 消息,并发送 `Command` 消息 + +#### Initiator 事件定义 + +- `TransactionStarted`: 事务已发起事件 + +- `PreCommitSucceedParticipantAdded`: 预提交成功的参与者已添加事件 + +- `PreCommitFailedParticipantAdded`: 预提交失败的参与者已添加事件 + +- `AllParticipantPreCommitSucceed`: 所有参与者预提交已成功事件 + +- `AnyParticipantPreCommitFailed`: 任意一个参与者预提交已失败事件 + +- `CommittedParticipantAdded`: 已提交的参与者已添加事件(Option) + +- `RolledbackParticipantAdded`: 已回滚的参与者已添加事件(Option) + +- `TransactionCompleted`: 事务已完成事件(Option),并包含是否事务已提交的状态 + +#### Participant 事件定义 + +- `PreCommitSucceed`: 预提交已成功事件 + +- `PreCommitFailed`: 预提交已失败事件(或领域异常消息) + +- `Committed`: 已提交事件 + +- `Rolledback`: 已回滚事件 + + +### 规范 + +- 一个聚合根,可以同时扮演 `Initiator` 和 `Transaction`的角色,如银行转账事务聚合根 + +- 一个聚合根,可以同时扮演事务A中的 `Participant` 和事务B的 `Initiator` + +- 一个 `Participant`,参与多少个事务,需对应定义多少个`Preparation` + +- `Participant` 的聚合根实例,允许同时参与多个不同的事务;也可以通过业务代码,在 `PreCommit` 时,判断是否存在其他类型的 `Preparation` 来阻止参与多个事务 + +- `Initiator` 必须发布事件 `TransactionStarted`、`PreCommitSucceedParticipantAdded`、`PreCommitFailedParticipantAdded`、`AllParticipantPreCommitSucceed`、`AnyParticipantPreCommitFailed` + +- `Participant` 必须发布事件 `PreCommitSucceed`、`PreCommitFailed`、`Committed`、`Rolledback` + +- 如果需要关注 `Transaction` 是否已完成,则 `Initiator` 需要发布事件 `CommittedParticipantAdded`、`RolledbackParticipantAdded`、`TransactionCompleted` + +### 处理流程 + +- `Initiator` 发布 `TransactionStarted` 事件; + +- `ProcessManager` 响应 `TransactionStarted` 事件,并发送 `PreCommit` 命令; + +- `Participant` 接受命令 `PreCommit`,如果成功,则发布 `PreCommitSucceed` 事件;如果失败,则发布 `PreCommitFailed` 事件(或领域异常); + +- `ProcessManager` 响应 `PreCommitSucceed`,并发送 `AddPreCommitSucceedParticipant` 命令; + +- `ProcessManager` 响应 `PreCommitFailed`,并发送 `AddPreCommitFailedParticipant` 命令; + +- `Initiator` 接受命令 `AddPreCommitSucceedParticipant`,发布 `PreCommitSucceedParticipantAdded` 事件;如果所有 `Participant` 的 `PreCommit` 都已处理完成,则发布 `AllParticipantPreCommitSucceed` 事件; + +- `Initiator` 接受命令 `AddPreCommitFailedParticipant`,发布 `PreCommitFailedParticipantAdded` 事件;如果所有 `Participant` 的 `PreCommit` 都已处理完成,则发布 `AnyParticipantPreCommitFailed` 事件; + +- `ProcessManager` 响应 `AllParticipantPreCommitSucceed`,并发送 `Commit` 命令; + +- `ProcessManager` 响应 `AnyParticipantPreCommitFailed`,并发送 `Rollback` 命令; + +- `Participant` 接受命令 `Commit`,并发布 `Committed` 事件; + +- `Participant` 接受命令 `Rollback`,并发布 `Rolledback` 事件; + +- `ProcessManager` 响应 `Committed`,并发送 `AddCommittedParticipant` 命令; + +- `ProcessManager` 响应 `Rolledback`,并发送 `AddRolledbackParticipant` 命令; + +- `Initiator` 接受命令 `AddCommittedParticipant`,发布 `CommittedParticipantAdded` 事件;如果所有 `Participant` 的 `Commit` 都已处理完成,则发布 `TransactionCompleted` 事件; + +- `Initiator` 接受命令 `AddRolledbackParticipant`,发布 `RolledbackParticipantAdded` 事件;如果所有 `Participant` 的 `Rolledback` 都已处理完成,则发布 `TransactionCompleted` 事件。 + +## 发布历史 + +### 1.0.0(2020/4/25) + +- 初始版本 diff --git a/src/Eventual2PC.sln b/src/Eventual2PC.sln new file mode 100644 index 0000000..88bc75a --- /dev/null +++ b/src/Eventual2PC.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Eventual2PC", "Eventual2PC\Eventual2PC.csproj", "{FB832C09-5CB6-4A1D-A11D-F7E10D94E333}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Debug|x64.ActiveCfg = Debug|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Debug|x64.Build.0 = Debug|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Debug|x86.ActiveCfg = Debug|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Debug|x86.Build.0 = Debug|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Release|Any CPU.Build.0 = Release|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Release|x64.ActiveCfg = Release|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Release|x64.Build.0 = Release|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Release|x86.ActiveCfg = Release|Any CPU + {FB832C09-5CB6-4A1D-A11D-F7E10D94E333}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/Eventual2PC/Events/ITransactionInitiatorAllParticipantPreCommitSucceed.cs b/src/Eventual2PC/Events/ITransactionInitiatorAllParticipantPreCommitSucceed.cs new file mode 100644 index 0000000..d6443a7 --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionInitiatorAllParticipantPreCommitSucceed.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace Eventual2PC.Events +{ + /// + /// 事务参与方所有预提交已成功事件接口 + /// + public interface ITransactionInitiatorAllParticipantPreCommitSucceed + where TInitiator : class, ITransactionInitiator + { + /// + /// 事务ID + /// + string TransactionId { get; } + + /// + /// 事务类型 + /// + byte TransactionType { get; } + + /// + /// 事务参与方信息 + /// + IEnumerable TransactionParticipants { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionInitiatorAnyParticipantPreCommitFailed.cs b/src/Eventual2PC/Events/ITransactionInitiatorAnyParticipantPreCommitFailed.cs new file mode 100644 index 0000000..badee4b --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionInitiatorAnyParticipantPreCommitFailed.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace Eventual2PC.Events +{ + /// + /// 事务参与方任意一个预提交已失败的事件接口 + /// + public interface ITransactionInitiatorAnyParticipantPreCommitFailed + where TInitiator : class, ITransactionInitiator + { + /// + /// 事务ID + /// + string TransactionId { get; } + + /// + /// 事务类型 + /// + byte TransactionType { get; } + + /// + /// 成功预提交的事务参与方信息 + /// + IEnumerable PreCommitSucceedTransactionParticipants { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionInitiatorCommittedParticipantAdded.cs b/src/Eventual2PC/Events/ITransactionInitiatorCommittedParticipantAdded.cs new file mode 100644 index 0000000..2603d37 --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionInitiatorCommittedParticipantAdded.cs @@ -0,0 +1,24 @@ +namespace Eventual2PC.Events +{ + /// + /// 已提交的事务参与方已添加事件接口 + /// + public interface ITransactionInitiatorCommittedParticipantAdded + where TInitiator : class, ITransactionInitiator + { + /// + /// 事务ID + /// + string TransactionId { get; } + + /// + /// 事务类型 + /// + byte TransactionType { get; } + + /// + /// 事务参与方信息 + /// + TransactionParticipantInfo TransactionParticipant { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionInitiatorPreCommitFailedParticipantAdded.cs b/src/Eventual2PC/Events/ITransactionInitiatorPreCommitFailedParticipantAdded.cs new file mode 100644 index 0000000..b5bcf3a --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionInitiatorPreCommitFailedParticipantAdded.cs @@ -0,0 +1,24 @@ +namespace Eventual2PC.Events +{ + /// + /// 预提交失败的事务参与方已添加事件接口 + /// + public interface ITransactionInitiatorPreCommitFailedParticipantAdded + where TInitiator : class, ITransactionInitiator + { + /// + /// 事务ID + /// + string TransactionId { get; } + + /// + /// 事务类型 + /// + byte TransactionType { get; } + + /// + /// 事务参与方信息 + /// + TransactionParticipantInfo TransactionParticipant { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionInitiatorPreCommitSucceedParticipantAdded.cs b/src/Eventual2PC/Events/ITransactionInitiatorPreCommitSucceedParticipantAdded.cs new file mode 100644 index 0000000..ef1e6b6 --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionInitiatorPreCommitSucceedParticipantAdded.cs @@ -0,0 +1,24 @@ +namespace Eventual2PC.Events +{ + /// + /// 预提交成功的事务参与方已添加事件接口 + /// + public interface ITransactionInitiatorPreCommitSucceedParticipantAdded + where TInitiator : class, ITransactionInitiator + { + /// + /// 事务ID + /// + string TransactionId { get; } + + /// + /// 事务类型 + /// + byte TransactionType { get; } + + /// + /// 事务参与方信息 + /// + TransactionParticipantInfo TransactionParticipant { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionInitiatorRolledbackParticipantAdded.cs b/src/Eventual2PC/Events/ITransactionInitiatorRolledbackParticipantAdded.cs new file mode 100644 index 0000000..cdb8aca --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionInitiatorRolledbackParticipantAdded.cs @@ -0,0 +1,24 @@ +namespace Eventual2PC.Events +{ + /// + /// 已回滚的事务参与方已添加事件接口 + /// + public interface ITransactionInitiatorRolledbackParticipantAdded + where TInitiator : class, ITransactionInitiator + { + /// + /// 事务ID + /// + string TransactionId { get; } + + /// + /// 事务类型 + /// + byte TransactionType { get; } + + /// + /// 事务参与方信息 + /// + TransactionParticipantInfo TransactionParticipant { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionInitiatorTransactionCompleted.cs b/src/Eventual2PC/Events/ITransactionInitiatorTransactionCompleted.cs new file mode 100644 index 0000000..c5045a0 --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionInitiatorTransactionCompleted.cs @@ -0,0 +1,24 @@ +namespace Eventual2PC.Events +{ + /// + /// 事务已完成事件接口 + /// + public interface ITransactionInitiatorTransactionCompleted + where TInitiator : class, ITransactionInitiator + { + /// + /// 事务ID + /// + string TransactionId { get; } + + /// + /// 事务类型 + /// + byte TransactionType { get; } + + /// + /// 事务是否成功 + /// + bool IsCommitSuccess { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionInitiatorTransactionStarted.cs b/src/Eventual2PC/Events/ITransactionInitiatorTransactionStarted.cs new file mode 100644 index 0000000..e2a28ec --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionInitiatorTransactionStarted.cs @@ -0,0 +1,19 @@ +namespace Eventual2PC.Events +{ + /// + /// 事务已开始事件接口 + /// + public interface ITransactionInitiatorTransactionStarted + where TInitiator : class, ITransactionInitiator + { + /// + /// 事务ID + /// + string TransactionId { get; } + + /// + /// 事务类型 + /// + byte TransactionType { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionParticipantCommitted.cs b/src/Eventual2PC/Events/ITransactionParticipantCommitted.cs new file mode 100644 index 0000000..21c76c8 --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionParticipantCommitted.cs @@ -0,0 +1,17 @@ +namespace Eventual2PC.Events +{ + /// + /// 事务参与者已提交事件 + /// + /// + /// + public interface ITransactionParticipantCommitted + where TParticipant : class, ITransactionParticipant + where TTransactionPreparation : class, ITransactionPreparation + { + /// + /// 事务准备 + /// + TTransactionPreparation TransactionPreparation { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionParticipantPreCommitFailed.cs b/src/Eventual2PC/Events/ITransactionParticipantPreCommitFailed.cs new file mode 100644 index 0000000..119b880 --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionParticipantPreCommitFailed.cs @@ -0,0 +1,35 @@ +namespace Eventual2PC.Events +{ + /// + /// 事务参与者预提交失败事件(或领域异常) + /// + /// + /// + public interface ITransactionParticipantPreCommitFailed + where TParticipant : class, ITransactionParticipant + where TTransactionPreparation : class, ITransactionPreparation + { + /// + /// 事务准备 + /// + TTransactionPreparation TransactionPreparation { get; } + } + + /// + /// 事务参与者预提交失败事件(或领域异常) + /// + /// + public interface ITransactionParticipantPreCommitFailed + where TParticipant : class, ITransactionParticipant + { + /// + /// 事务准备类型 + /// + string TransactionPreparationType { get; } + + /// + /// 事务准备 + /// + TransactionPreparationInfo TransactionPreparation { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionParticipantPreCommitSucceed.cs b/src/Eventual2PC/Events/ITransactionParticipantPreCommitSucceed.cs new file mode 100644 index 0000000..f82001a --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionParticipantPreCommitSucceed.cs @@ -0,0 +1,17 @@ +namespace Eventual2PC.Events +{ + /// + /// 事务参与者预提交成功事件 + /// + /// + /// + public interface ITransactionParticipantPreCommitSucceed + where TParticipant : class, ITransactionParticipant + where TTransactionPreparation : class, ITransactionPreparation + { + /// + /// 事务准备 + /// + TTransactionPreparation TransactionPreparation { get; } + } +} diff --git a/src/Eventual2PC/Events/ITransactionParticipantRolledback.cs b/src/Eventual2PC/Events/ITransactionParticipantRolledback.cs new file mode 100644 index 0000000..06ca2bd --- /dev/null +++ b/src/Eventual2PC/Events/ITransactionParticipantRolledback.cs @@ -0,0 +1,17 @@ +namespace Eventual2PC.Events +{ + /// + /// 事务参与者已回滚事件 + /// + /// + /// + public interface ITransactionParticipantRolledback + where TParticipant : class, ITransactionParticipant + where TTransactionPreparation : class, ITransactionPreparation + { + /// + /// 事务准备 + /// + TTransactionPreparation TransactionPreparation { get; } + } +} diff --git a/src/Eventual2PC/Eventual2PC.csproj b/src/Eventual2PC/Eventual2PC.csproj new file mode 100644 index 0000000..ead2d84 --- /dev/null +++ b/src/Eventual2PC/Eventual2PC.csproj @@ -0,0 +1,22 @@ + + + + netstandard2.0 + true + false + false + MIT + https://github.com/berkaroad/Eventual2PC + https://github.com/berkaroad/Eventual2PC + Jerry Bai + Eventual2PC + 1.0.0 + 1.0.0 + Eventual2PC + 最终一致性二阶段提交范式,简化多聚合根之间交互事务的实现。 + 2pc eventual transaction processmanager saga eda + 最终一致性二阶段提交范式,简化多聚合根之间交互事务的实现。任何基于cqrs + eda 实现多聚合根最终一致性的框架,都可使用。 + + + + diff --git a/src/Eventual2PC/ITransactionInitiator.cs b/src/Eventual2PC/ITransactionInitiator.cs new file mode 100644 index 0000000..36a800c --- /dev/null +++ b/src/Eventual2PC/ITransactionInitiator.cs @@ -0,0 +1,45 @@ +namespace Eventual2PC +{ + /// + /// 事务发起方 + /// + public interface ITransactionInitiator + { + /// + /// 添加预提交成功的参与者信息 + /// + /// 事务ID + /// 事务类型 + /// 事务参与方信息 + void AddPreCommitSuccessParticipant(string transactionId, byte transactionType, TransactionParticipantInfo participantInfo); + + /// + /// 添加预提交失败的参与者信息 + /// + /// 事务ID + /// 事务类型 + /// 事务参与方信息 + void AddPreCommitFailedParticipant(string transactionId, byte transactionType, TransactionParticipantInfo participantInfo); + + /// + /// 添加已提交的参与者信息 + /// + /// 事务ID + /// 事务类型 + /// 事务参与方信息 + void AddCommittedParticipant(string transactionId, byte transactionType, TransactionParticipantInfo participantInfo); + + /// + /// 添加已回滚的参与者信息 + /// + /// + /// 事务类型 + /// 事务参与方信息 + void AddRolledbackParticipant(string transactionId, byte transactionType, TransactionParticipantInfo participantInfo); + + /// + /// 是否事务在处理中 + /// + bool IsTransactionProcessing { get; } + } +} diff --git a/src/Eventual2PC/ITransactionParticipant.cs b/src/Eventual2PC/ITransactionParticipant.cs new file mode 100644 index 0000000..ca7c4c3 --- /dev/null +++ b/src/Eventual2PC/ITransactionParticipant.cs @@ -0,0 +1,26 @@ +namespace Eventual2PC +{ + /// + /// 事务参与方 + /// + public interface ITransactionParticipant + { + /// + /// 预提交(产生预提交成功的领域事件,或抛出领域异常) + /// + /// + void PreCommit(ITransactionPreparation transactionPreparation); + + /// + /// 提交(预提交反馈成功后,才能提交) + /// + /// + void Commit(string transactionId); + + /// + /// 回滚(由事务发起方进行回滚) + /// + /// + void Rollback(string transactionId); + } +} diff --git a/src/Eventual2PC/ITransactionPreparation.cs b/src/Eventual2PC/ITransactionPreparation.cs new file mode 100644 index 0000000..55d4395 --- /dev/null +++ b/src/Eventual2PC/ITransactionPreparation.cs @@ -0,0 +1,44 @@ +namespace Eventual2PC +{ + /// + /// 事务准备 + /// + public interface ITransactionPreparation + { + /// + /// 事务参与方ID + /// + string ParticipantId { get; } + + /// + /// 事务参与方类型 + /// + byte ParticipantType { get; } + + /// + /// 事务ID + /// + string TransactionId { get; } + + /// + /// 事务类型 + /// + byte TransactionType { get; } + + /// + /// 事务发起方ID + /// + string InitiatorId { get; } + + /// + /// 事务发起方类型 + /// + byte InitiatorType { get; } + + /// + /// 获取准备信息 + /// + /// + TransactionPreparationInfo GetTransactionPreparationInfo(); + } +} diff --git a/src/Eventual2PC/TransactionParticipantInfo.cs b/src/Eventual2PC/TransactionParticipantInfo.cs new file mode 100644 index 0000000..116d11e --- /dev/null +++ b/src/Eventual2PC/TransactionParticipantInfo.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Eventual2PC +{ + /// + /// 事务参与方信息 + /// + [Serializable] + public sealed class TransactionParticipantInfo + { + /// + /// 事务准备 + /// + /// 事务参与方ID + /// 事务参与方类型 + public TransactionParticipantInfo(string participantId, byte participantType) + { + ParticipantId = participantId; + ParticipantType = participantType; + } + + /// + /// 事务参与方ID + /// + public string ParticipantId { get; private set; } + + /// + /// 事务参与方类型 + /// + public byte ParticipantType { get; private set; } + + /// + /// 参与者是否已存在 + /// + /// 参与者信息列表 + /// + public bool IsParticipantAlreadyExists(IEnumerable participants) + { + return participants != null && participants.Any(a => a.ParticipantId == ParticipantId); + } + + /// + /// 验证必须不存在 + /// + /// 参与者信息列表 + public void ValidateParticipantMustNotExists(IEnumerable participants) + { + if (IsParticipantAlreadyExists(participants)) + { + throw new ApplicationException($"{ParticipantId} has already exists."); + } + } + } +} diff --git a/src/Eventual2PC/TransactionPreparationBase.cs b/src/Eventual2PC/TransactionPreparationBase.cs new file mode 100644 index 0000000..64a8b87 --- /dev/null +++ b/src/Eventual2PC/TransactionPreparationBase.cs @@ -0,0 +1,74 @@ +using System; + +namespace Eventual2PC +{ + /// + /// 事务准备 + /// + [Serializable] + public abstract class TransactionPreparationBase : ITransactionPreparation + { + /// + /// 事务准备 + /// + protected TransactionPreparationBase() {} + + /// + /// 事务准备 + /// + /// 事务参与方ID + /// 事务参与方类型 + /// 事务ID + /// 事务类型 + /// 事务发起方ID + /// 事务发起方类型 + protected TransactionPreparationBase(string participantId, byte participantType, string transactionId, byte transactionType, string initiatorId, byte initiatorType) + { + ParticipantId = participantId; + ParticipantType = participantType; + TransactionId = transactionId; + TransactionType = transactionType; + InitiatorId = initiatorId; + InitiatorType = initiatorType; + } + + /// + /// 事务参与方ID + /// + public string ParticipantId { get; protected set; } + + /// + /// 事务参与方类型 + /// + public byte ParticipantType { get; protected set; } + + /// + /// 事务ID + /// + public string TransactionId { get; protected set; } + + /// + /// 事务类型 + /// + public byte TransactionType { get; protected set; } + + /// + /// 事务发起方ID + /// + public string InitiatorId { get; protected set; } + + /// + /// 事务发起方类型 + /// + public byte InitiatorType { get; protected set; } + + /// + /// 获取准备信息 + /// + /// + public TransactionPreparationInfo GetTransactionPreparationInfo() + { + return new TransactionPreparationInfo(ParticipantId, ParticipantType, TransactionId, TransactionType, InitiatorId, InitiatorType); + } + } +} diff --git a/src/Eventual2PC/TransactionPreparationInfo.cs b/src/Eventual2PC/TransactionPreparationInfo.cs new file mode 100644 index 0000000..61b4454 --- /dev/null +++ b/src/Eventual2PC/TransactionPreparationInfo.cs @@ -0,0 +1,65 @@ +using System; + +namespace Eventual2PC +{ + /// + /// 事务准备信息 + /// + [Serializable] + public sealed class TransactionPreparationInfo + { + /// + /// 事务准备信息 + /// + public TransactionPreparationInfo() { } + + /// + /// 事务准备 + /// + /// 事务参与方ID + /// 事务参与方类型 + /// 事务ID + /// 事务类型 + /// 事务发起方ID + /// 事务发起方类型 + public TransactionPreparationInfo(string participantId, byte participantType, string transactionId, byte transactionType, string initiatorId, byte initiatorType) + { + ParticipantId = participantId; + ParticipantType = participantType; + TransactionId = transactionId; + TransactionType = transactionType; + InitiatorId = initiatorId; + InitiatorType = initiatorType; + } + + /// + /// 事务参与方ID + /// + public string ParticipantId { get; private set; } + + /// + /// 事务参与方类型 + /// + public byte ParticipantType { get; private set; } + + /// + /// 事务ID + /// + public string TransactionId { get; private set; } + + /// + /// 事务类型 + /// + public byte TransactionType { get; private set; } + + /// + /// 事务发起方ID + /// + public string InitiatorId { get; private set; } + + /// + /// 事务发起方类型 + /// + public byte InitiatorType { get; private set; } + } +} diff --git a/src/Eventual2PC/UnknownTransactionPreparationException.cs b/src/Eventual2PC/UnknownTransactionPreparationException.cs new file mode 100644 index 0000000..3763cd8 --- /dev/null +++ b/src/Eventual2PC/UnknownTransactionPreparationException.cs @@ -0,0 +1,29 @@ +using System; + +namespace Eventual2PC +{ + /// + /// 未知的TransactionPreparation异常 + /// + [Serializable] + public sealed class UnknownTransactionPreparationException : ApplicationException + { + /// + /// 未知的TransactionPreparation异常 + /// + public UnknownTransactionPreparationException() : base() { } + + /// + /// 未知的TransactionPreparation异常 + /// + /// + public UnknownTransactionPreparationException(string message) : base(message) { } + + /// + /// 未知的TransactionPreparation异常 + /// + /// + /// + public UnknownTransactionPreparationException(string message, Exception innerException) : base(message, innerException) { } + } +}