w4c-workflows-api/Services/Runs/DurableStateStore.cs

71 lines
2.1 KiB
C#
Raw Normal View History

using Microsoft.EntityFrameworkCore;
using w4c_workflows.Data;
using w4c_workflows.Models;
namespace w4c_workflows.Services.Runs;
/// <summary>
/// Persists <c>durable</c>/<c>handler</c> checkpoint state. The checkpoint
/// records the instance's position (<c>TaskId</c> = the next task to run) and
/// the input to feed it (<c>StateJson</c>), enabling resume after an external
/// event. The instance id is a run id for <c>durable</c> workflows and a stable
/// per-workflow id for <c>handler</c> workflows.
/// </summary>
public class DurableStateStore
{
private readonly WorkflowsDbContext _db;
public DurableStateStore(WorkflowsDbContext db)
{
_db = db;
}
public async Task CheckpointAsync(
string instanceId,
Guid taskId,
string? stateJson,
string? correlationId,
CancellationToken ct)
{
var existing = await _db.DurableStates
.FirstOrDefaultAsync(d => d.InstanceId == instanceId, ct);
var now = DateTime.UtcNow;
if (existing == null)
{
_db.DurableStates.Add(new DurableState
{
InstanceId = instanceId,
TaskId = taskId,
StateJson = stateJson,
CheckpointAt = now,
CorrelationId = correlationId,
});
}
else
{
existing.TaskId = taskId;
existing.StateJson = stateJson;
existing.CheckpointAt = now;
if (!string.IsNullOrWhiteSpace(correlationId))
existing.CorrelationId = correlationId;
}
await _db.SaveChangesAsync(ct);
}
public Task<DurableState?> GetAsync(string instanceId, CancellationToken ct)
=> _db.DurableStates.FirstOrDefaultAsync(d => d.InstanceId == instanceId, ct);
public async Task ClearAsync(string instanceId, CancellationToken ct)
{
var existing = await _db.DurableStates
.FirstOrDefaultAsync(d => d.InstanceId == instanceId, ct);
if (existing == null)
return;
_db.DurableStates.Remove(existing);
await _db.SaveChangesAsync(ct);
}
}