Commit 7ef7a1a7 by dingsongjie

完成 90%

parent 92eeb084
......@@ -7,13 +7,19 @@ namespace Pole.Sagas.Client.Abstraction
{
Task SagaStarted(string sagaId, string serviceName, DateTime addTime);
Task SagaEnded(string sagaId, DateTime ExpiresAt);
Task ActivityExecuting(string activityId,string activityName, string sagaId, byte[] parameterData, int order, DateTime addTime,int executeTimes);
Task ActivityExecuting(string activityId,string activityName, string sagaId, byte[] parameterData, int order, DateTime addTime);
Task ActivityExecuteAborted(string activityId);
/// <summary>
///
/// </summary>
/// <param name="activityId"></param>
/// <param name="sagaId">sagaId 不为空 服务端会set saga.status=ended</param>
/// <param name="errors"></param>
/// <returns></returns>
Task ActivityCompensateAborted(string activityId, string sagaId, string errors);
Task ActivityExecuted(string activityId);
Task ActivityCompensated(string activityId);
Task ActivityOvertimeCompensated(string activityId,bool compensated);
Task ActivityExecuteOvertime(string activityId,string name,byte [] parameterData,DateTime addTime);
Task ActivityRevoked(string activityId);
Task ActivityCompensating(string activityId,int compensateTimes);
}
}
......@@ -17,7 +17,7 @@ namespace Pole.Sagas.Client
public Type ActivityDataType { get; set; }
public object DataObj { get; set; }
public int Order { get; set; }
public int ExecuteTimes { get; set; }
public int OvertimeCompensateTimes { get; set; }
public int CompensateTimes { get; set; }
public ActivityStatus ActivityStatus { get; set; }
public IServiceProvider ServiceProvider { get; set; }
......
......@@ -44,18 +44,6 @@ namespace Pole.Sagas.Client
}
}
public async Task ActivityExecuted(string activityId)
{
var result = await sagaClient.ActivityExecutedAsync(new Server.Grpc.ActivityExecutedRequest
{
ActivityId = activityId,
});
if (!result.IsSuccess)
{
throw new SagasServerException(result.Errors);
}
}
public async Task ActivityExecuteAborted(string activityId)
{
var result = await sagaClient.ActivityExecuteAbortedAsync(new Server.Grpc.ActivityExecuteAbortedRequest
......@@ -68,7 +56,7 @@ namespace Pole.Sagas.Client
}
}
public async Task ActivityExecuting(string activityId, string activityName, string sagaId, byte[] parameterData, int order, DateTime addTime, int executeTimes)
public async Task ActivityExecuting(string activityId, string activityName, string sagaId, byte[] parameterData, int order, DateTime addTime)
{
var result = await sagaClient.ActivityExecutingAsync(new Server.Grpc.ActivityExecutingRequest
{
......@@ -136,11 +124,12 @@ namespace Pole.Sagas.Client
}
}
public async Task ActivityCompensating(string activityId, int compensateTimes)
public async Task ActivityOvertimeCompensated(string activityId, bool compensated)
{
var result = await sagaClient.ActivityCompensatingAsync(new Server.Grpc.ActivityCompensatingRequest
var result = await sagaClient.ActivityOvertimeCompensatedAsync(new Server.Grpc.ActivityOvertimeCompensatedRequest
{
ActivityId = activityId,
Compensated= compensated
});
if (!result.IsSuccess)
{
......
......@@ -58,7 +58,7 @@ namespace Pole.Sagas.Client
sagas.ForEach(async sagaEntity =>
{
var saga = sagaRestorer.CreateSaga(sagaEntity);
await saga.Compensate();
await saga.CompensateWhenRetry();
});
}
}
......
......@@ -8,6 +8,8 @@ namespace Pole.Sagas.Client
{
public string ServiceName { get; set; }
public int PreSagasGrpcStreamingResponseLimitCount { get; set; } = 20;
public int MaxCompensateTimes { get; set; } = 10;
public int MaxOvertimeCompensateTimes { get; set; } = 10;
public int CompeletedSagaExpiredAfterSeconds { get; set; } = 60 * 10;
public int SagasTimeOutSeconds { get; set; } = 60;
public string SagasServerHost { get; set; }
......
......@@ -118,15 +118,20 @@ namespace Pole.Sagas.Client
var result = await RecursiveExecuteActivity(executeActivity);
return result;
}
internal async Task Compensate()
/// <summary>
/// if true should ended this sagas ,if false do nothing continue retry
/// </summary>
/// <returns></returns>
internal async Task<bool> CompensateWhenRetry()
{
this.currentCompensateOrder = CurrentMaxOrder+1;
this.currentCompensateOrder = CurrentMaxOrder + 1;
var compensateActivity = GetNextCompensateActivity();
if (compensateActivity == null)
{
return ;
return true;
}
await RecursiveCompensateActivity(compensateActivity);
return true;
}
private ActivityWapper GetNextExecuteActivity()
......@@ -151,11 +156,27 @@ namespace Pole.Sagas.Client
private async Task RecursiveCompensateActivity(ActivityWapper activityWapper)
{
var activityId = activityWapper.Id;
if (activityWapper.ActivityStatus == ActivityStatus.ExecutingOvertime)
{
activityWapper.OvertimeCompensateTimes++;
}
else
{
activityWapper.CompensateTimes++;
}
try
{
await eventSender.ActivityCompensating(activityId, activityWapper.CompensateTimes);
await activityWapper.InvokeCompensate();
await eventSender.ActivityCompensated(activityId);
if (activityWapper.ActivityStatus == ActivityStatus.ExecutingOvertime)
{
// 超时 补偿次数已到
var isCompensated = activityWapper.CompensateTimes == poleSagasOption.MaxOvertimeCompensateTimes;
await eventSender.ActivityOvertimeCompensated(activityId, isCompensated);
}
else
{
await eventSender.ActivityCompensated(activityId);
}
var compensateActivity = GetNextCompensateActivity();
if (compensateActivity == null)
{
......@@ -165,19 +186,27 @@ namespace Pole.Sagas.Client
}
catch (Exception exception)
{
await eventSender.ActivityCompensateAborted(activityId, Id, exception.InnerException != null ? exception.InnerException.Message + exception.StackTrace : exception.Message + exception.StackTrace);
// todo: 超时操作 如果出错可能 减少 补偿次数 这里 先不做处理
if (activityWapper.CompensateTimes == poleSagasOption.MaxCompensateTimes)
{
// 此时 结束 saga 并且设置状态 为 Error
await eventSender.ActivityCompensateAborted(activityId, Id, exception.InnerException != null ? exception.InnerException.Message + exception.StackTrace : exception.Message + exception.StackTrace);
}
else
{
await eventSender.ActivityCompensateAborted(activityId, string.Empty, exception.InnerException != null ? exception.InnerException.Message + exception.StackTrace : exception.Message + exception.StackTrace);
}
}
}
private async Task<ActivityExecuteResult> RecursiveExecuteActivity(ActivityWapper activityWapper)
{
var activityId = snowflakeIdGenerator.NextId();
activityWapper.Id = activityId;
activityWapper.ExecuteTimes++;
activityWapper.CancellationTokenSource = new System.Threading.CancellationTokenSource(2 * 1000);
try
{
var bytesContent = serializer.SerializeToUtf8Bytes(activityWapper.DataObj, activityWapper.ActivityDataType);
await eventSender.ActivityExecuting(activityId, activityWapper.Name, Id, bytesContent, activityWapper.Order, DateTime.UtcNow, activityWapper.ExecuteTimes);
await eventSender.ActivityExecuting(activityId, activityWapper.Name, Id, bytesContent, activityWapper.Order, DateTime.UtcNow);
var result = await activityWapper.InvokeExecute();
if (!result.IsSuccess)
{
......@@ -185,7 +214,6 @@ namespace Pole.Sagas.Client
await CompensateActivity(result, currentExecuteOrder);
return result;
}
await eventSender.ActivityExecuted(activityId);
var executeActivity = GetNextExecuteActivity();
if (executeActivity == null)
{
......
......@@ -44,7 +44,7 @@ namespace Pole.Sagas.Server.Processor
private async Task ProcessInternal()
{
var tables = new[] { sagaStorageInitializer.GetSagaTableName(), sagaStorageInitializer.GetOvertimeCompensationGuaranteeTableName() };
var tables = new[] { sagaStorageInitializer.GetSagaTableName() };
foreach (var table in tables)
{
......
......@@ -51,20 +51,6 @@ namespace Pole.Sagas.Server.Services
}
return commonResponse;
}
public override async Task<CommonResponse> ActivityExecuted(ActivityExecutedRequest request, ServerCallContext context)
{
CommonResponse commonResponse = new CommonResponse();
try
{
await sagaStorage.ActivityExecuted(request.ActivityId);
commonResponse.IsSuccess = true;
}
catch (Exception ex)
{
commonResponse.Errors = CombineError(ex);
}
return commonResponse;
}
public override async Task<CommonResponse> ActivityExecuteAborted(ActivityExecuteAbortedRequest request, ServerCallContext context)
{
CommonResponse commonResponse = new CommonResponse();
......@@ -98,7 +84,7 @@ namespace Pole.Sagas.Server.Services
CommonResponse commonResponse = new CommonResponse();
try
{
await sagaStorage.ActivityExecuting(request.ActivityId, request.ActivityName, request.SagaId, request.ParameterData.ToByteArray(), request.Order, Convert.ToDateTime(request.AddTime), request.ExecuteTimes);
await sagaStorage.ActivityExecuting(request.ActivityId, request.ActivityName, request.SagaId, request.ParameterData.ToByteArray(), request.Order, Convert.ToDateTime(request.AddTime));
commonResponse.IsSuccess = true;
}
catch (Exception ex)
......@@ -149,20 +135,6 @@ namespace Pole.Sagas.Server.Services
}
return commonResponse;
}
public override async Task<CommonResponse> ActivityCompensating(ActivityCompensatingRequest request, ServerCallContext context)
{
CommonResponse commonResponse = new CommonResponse();
try
{
await sagaStorage.ActivityCompensating(request.ActivityId, request.CompensateTimes);
commonResponse.IsSuccess = true;
}
catch (Exception ex)
{
commonResponse.Errors = CombineError(ex);
}
return commonResponse;
}
public override async Task GetSagas(GetSagasRequest request, IServerStreamWriter<GetSagasResponse> responseStream, ServerCallContext context)
{
while (!context.CancellationToken.IsCancellationRequested)
......@@ -202,7 +174,22 @@ namespace Pole.Sagas.Server.Services
await responseStream.WriteAsync(getSagasResponse);
}
}
public override async Task<CommonResponse> ActivityOvertimeCompensated(ActivityOvertimeCompensatedRequest request, ServerCallContext context)
{
CommonResponse commonResponse = new CommonResponse();
try
{
await sagaStorage.ActivityOvertimeCompensated(request.ActivityId, request.Compensated);
commonResponse.IsSuccess = true;
}
catch (Exception ex)
{
commonResponse.Errors = CombineError(ex);
}
return commonResponse;
}
private string CombineError(Exception exception)
{
return exception.InnerException != null ? exception.InnerException.Message + exception.StackTrace : exception.Message + exception.StackTrace;
......
......@@ -31,10 +31,6 @@ namespace Pole.Sagas.Storage.PostgreSql
{
return $"\"{options.SchemaName}\".\"{options.SagaTableName}\"";
}
public string GetOvertimeCompensationGuaranteeTableName()
{
return $"\"{options.SchemaName}\".\"{options.OvertimeCompensationGuaranteeTableName}\"";
}
public async Task InitializeAsync(CancellationToken cancellationToken)
{
......@@ -69,7 +65,7 @@ CREATE TABLE IF NOT EXISTS {GetActivityTableName()}(
""SagaId"" varchar(20) COLLATE ""pg_catalog"".""default"" NOT NULL,
""Order"" int4 NOT NULL,
""Status"" varchar(10) COLLATE ""pg_catalog"".""default"" NOT NULL,
""ExecuteTimes"" int4 NOT NULL,
""OvertimeCompensateTimes"" int4 NOT NULL,
""ParameterData"" bytea NOT NULL,
""CompensateErrors"" varchar(1024) COLLATE ""pg_catalog"".""default"",
""CompensateTimes"" int4 NOT NULL,
......@@ -84,19 +80,6 @@ ALTER TABLE ""{GetActivityTableName()}"" ADD CONSTRAINT ""Activities_pkey"" PRIM
ALTER TABLE ""{GetActivityTableName()}"" ADD CONSTRAINT ""Activities_SagaId_fkey"" FOREIGN KEY (""SagaId"") REFERENCES {GetSagaTableName()} (""Id"") ON DELETE CASCADE ON UPDATE NO ACTION;
CREATE TABLE IF NOT EXISTS {GetOvertimeCompensationGuaranteeTableName()}(
""Id"" varchar(20) COLLATE ""pg_catalog"".""default"" NOT NULL,
""Name"" varchar(255) COLLATE ""pg_catalog"".""default"" NOT NULL,
""Status"" varchar(10) COLLATE ""pg_catalog"".""default"" NOT NULL,
""CompensateTimes"" int4 NOT NULL,
""ParameterData"" bytea NOT NULL,
""CompensateErrors"" varchar(1024) COLLATE ""pg_catalog"".""default"",
""AddTime"" timestamp NOT NULL,
""ExpiresAt"" timestamp,
);
ALTER TABLE ""{GetActivityTableName()}"" ADD CONSTRAINT ""OCG - Activities_pkey"" PRIMARY KEY (""Id"");
";
return batchSql;
}
......
......@@ -12,15 +12,14 @@ namespace Pole.Sagas.Core.Abstraction
{
Task SagaStarted(string sagaId, string serviceName,DateTime addTime);
Task SagaEnded(string sagaId, DateTime ExpiresAt);
Task ActivityExecuting(string activityId, string activityName,string sagaId, byte[] ParameterData, int order,DateTime addTime,int executeTimes);
Task ActivityExecuting(string activityId, string activityName,string sagaId, byte[] ParameterData, int order,DateTime addTime);
Task ActivityExecuteAborted(string activityId);
Task ActivityCompensateAborted(string activityId, string sagaId, string errors);
Task ActivityExecuted(string activityId);
Task ActivityCompensated(string activityId);
Task ActivityExecuteOvertime(string activityId, string name, byte[] parameterData, DateTime addTime);
Task ActivityRevoked(string activityId);
Task ActivityCompensating(string activityId, int compensateTimes);
IAsyncEnumerable<SagasGroupEntity> GetSagas(DateTime dateTime, int limit);
Task<int> DeleteExpiredData(string tableName,DateTime ExpiredAt, int batchCount);
Task ActivityOvertimeCompensated(string activityId, bool compensated);
}
}
......@@ -11,6 +11,5 @@ namespace Pole.Sagas.Core.Abstraction
Task InitializeAsync(CancellationToken cancellationToken);
string GetSagaTableName();
string GetActivityTableName();
string GetOvertimeCompensationGuaranteeTableName();
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Pole.Sagas.Core
{
public enum OvertimeCompensationGuaranteeActivityStatus
{
Executing,
Executed,
Error
}
}
......@@ -10,12 +10,11 @@ service Saga {
rpc ActivityExecuting (ActivityExecutingRequest) returns (CommonResponse);
rpc ActivityExecuteAborted (ActivityExecuteAbortedRequest) returns (CommonResponse);
rpc ActivityCompensateAborted (ActivityCompensateAbortedRequest) returns (CommonResponse);
rpc ActivityExecuted (ActivityExecutedRequest) returns (CommonResponse);
rpc ActivityCompensated (ActivityCompensatedRequest) returns (CommonResponse);
rpc ActivityExecuteOvertime (ActivityExecuteOvertimeRequest) returns (CommonResponse);
rpc ActivityRevoked (ActivityRevokedRequest) returns (CommonResponse);
rpc ActivityCompensating (ActivityCompensatingRequest) returns (CommonResponse);
rpc GetSagas (GetSagasRequest) returns (stream GetSagasResponse);
rpc ActivityOvertimeCompensated (ActivityOvertimeCompensatedRequest) returns (CommonResponse);
}
message CommonResponse{
......@@ -39,7 +38,6 @@ message ActivityExecutingRequest {
int32 order = 4;
string addTime = 5;
string activityName = 6;
int32 executeTimes = 7;
}
message ActivityExecuteAbortedRequest {
string activityId = 1;
......@@ -91,4 +89,8 @@ message GetSagasResponse{
}
}
}
message ActivityOvertimeCompensatedRequest {
string activityId = 1;
bool compensated = 2;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment