using Microsoft.EntityFrameworkCore; using w4c_workflows.Data; using w4c_workflows.Models; namespace w4c_workflows.Services.Runs; /// /// Persists durable/handler checkpoint state. The checkpoint /// records the instance's position (TaskId = the next task to run) and /// the input to feed it (StateJson), enabling resume after an external /// event. The instance id is a run id for durable workflows and a stable /// per-workflow id for handler workflows. /// 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 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); } }