我正在使用帶有 RabbitMQ 傳輸和 EntityFramework 存盤庫的 MassTransit Saga 狀態機。
我的問題如下 - 當用戶在我的 REST API(.NET 6 Minimal API)中點擊一個端點時,作為我的業務邏輯的一部分,我將一個事件發布到狀態機,這會改變狀態。因此,我想通過回應將當前(新)狀態回傳給最終用戶,這是不可能的(或者我找不到解決方案)。 請注意,我的狀態機實作在同一個 REST API 專案中。
所以,我有什么:最初,我找不到從存盤中獲取當前狀態的任何內容(在我的例子中是 SQL Server DB)。所以我創建了一個 EF 方法來做到這一點:
public class StateRepository<StateInstance> : IStateRepository<StateInstance> where StateInstance : SqlServerStateInstance
{
protected readonly DbContext _stateDBContext;
public StateRepository(DbContext stateDBContext)
{
_stateDBContext = stateDBContext;
}
public async Task<StateInstance> GetCurrentStateAsync (Guid correlationId)
{
return await _stateDBContext.Set<StateInstance>().Where(i => i.CorrelationId == correlationId).FirstOrDefaultAsync();
}
}
哪個作業正常...如果我已經設定了狀態。:)
因此,我添加了一個中間件,它呼叫 Repository 通過 ID 獲取狀態并將其設定在 Response 的標頭中:
internal class StateMiddleware
{
private readonly RequestDelegate _next;
public StateMiddleware(RequestDelegate next, ILogger<StateMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task Invoke(HttpContext context, IStateHandler stateHandler)
{
await _next(context);
string state = await stateHandler.GetCurrentState(correlationID);
context.Response.Headers.Add("X-State", state ?? "NULL?!?");
}
}
注冊的WebApplication.UseMiddleware<StateMiddleware>();
但是當我發布一個事件(從任何端點)來更新狀態時,比如:
app.MapPost(RoutePrefix "/sm/call-event/{userId}", async (IPublishEndpoint _publishEndpoint, Guid userId, StateEvents evn) =>
{
switch (evn)
{
case StateEvents.Initiate:
{
await _publishEndpoint.Publish<StateInstance>(new
{
CorrelationId = userId
}, default);
break;
}
case StateEvents.CollectEmail:
{
await _publishEndpoint.Publish<CollectEmailData>(new
{
ActiveAccountExists = false,
CorrelationId = userId
}, default);
break;
}
case StateEvents.ConfirmPass:
{
await _publishEndpoint.Publish<ConfirmPass>(new
{
CorrelationId = userId
}, default);
break;
}
}
return Results.Ok();
})
狀態是NULL(如果我用 呼叫端點StateEvents.Initiate)或前一個值(使用列舉中的任何其他值)。
這是我的公共交通配置:
services.AddMassTransit(cfg=> {
cfg.AddSagaStateMachine<MyStateMachine, MyStateInstance>()
.EntityFrameworkRepository(r =>
{
r.ConcurrencyMode = ConcurrencyMode.Optimistic; //requires RowVersion!
r.AddDbContext<DbContext, StateRepository>((provider, builder) =>
{
builder.UseSqlServer(connectionString, m =>
{
m.MigrationsAssembly(typeof(StateRepository).Assembly.GetName().Name);
m.MigrationsHistoryTable($"__{typeof(StateRepository).Name}");
});
});
});
cfg.UsingRabbitMq((context, x) =>
{
x.ConfigureEndpoints(context);
x.Host("localhost",
h =>
{
h.Username("guest");
h.Password("guest");
}
);
});
});
services.AddMassTransitHostedService();
我知道狀態機是基于事件的,它是異步的,但是有什么解決方法,或者?
謝謝!
uj5u.com熱心網友回復:
您永遠不應該直接訪問該 saga 存盤庫以獲取該型別的資訊。實體的當前狀態和任何其他資料都歸 saga 所有。嘗試讀取/訪問狀態,或者在最壞的情況下修改狀態,是被誤導的,并且可能會引入各種不一致。
MassTransit 有一個訪問saga 狀態的簡單工具。您可以定義由 saga 處理的請求協定,允許 saga 本身以當前狀態/詳細資訊進行回應。該請求甚至可以指定為只讀,這樣它就不會修改狀態(或嘗試保存未修改的狀態)。
下面顯示的示例具有回應請求的狀態檢查:
class ReadOnlyStateMachine :
MassTransitStateMachine<ReadOnlyInstance>
{
public ReadOnlyStateMachine()
{
InstanceState(x => x.CurrentState);
Event(() => StatusCheckRequested, x =>
{
x.ReadOnly = true;
});
Initially(
When(Started)
.Then(context => context.Instance.StatusText = "Started")
.Respond(context => new StartupComplete {CorrelationId = context.Instance.CorrelationId})
.TransitionTo(Running)
);
During(Running,
When(StatusCheckRequested)
.Respond(context => new Status
{
CorrelationId = context.Instance.CorrelationId,
StatusText = context.Instance.StatusText
})
.Then(context => context.Instance.StatusText = "Running") // this change won't be saved
);
}
public State Running { get; private set; }
public Event<Start> Started { get; private set; }
public Event<CheckStatus> StatusCheckRequested { get; private set; }
}
在控制器中,只需使用請求客戶端即可獲取狀態機的狀態:
public class SomeController
{
public SomeController(IRequestClient<CheckStatus> client)
{
_client = client;
}
public async Task<IActionResult> DoSomething(Guid id)
{
var response = await _client.GetResponse<Status>(new { CorrelationId = id});
}
}
這應該足以讓你開始。如果沒有,這里是一個控制器示例,以及相應的事件和處理程式。(該示例沒有在事件上設定 ReadOnly 屬性,但您應該添加它)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/452586.html
標籤:。网 .net-core 实体框架核心 轨道交通 传奇
上一篇:C#函式回傳值后不停止
