using System.Collections.Concurrent; namespace w4c_workflows.Services; /// /// In-memory lease service for lite/self-hosted mode where Redis is not available. /// Uses a ConcurrentDictionary with TTL tracking. Not distributed — only works /// for a single-process deployment (which is the lite mode use case). /// public sealed class InMemoryLeaseService : ILeaseService { private record Lease(string Owner, DateTime ExpiresAt); private readonly ConcurrentDictionary _leases = new(); public Task AcquireAsync(string tenantId, string runId, string owner, TimeSpan ttl) { var key = $"{tenantId}:{runId}"; var lease = new Lease(owner, DateTime.UtcNow + ttl); return Task.FromResult(_leases.TryAdd(key, lease)); } public Task RenewAsync(string tenantId, string runId, string owner, TimeSpan ttl) { var key = $"{tenantId}:{runId}"; if (!_leases.TryGetValue(key, out var current) || current.Owner != owner) return Task.FromResult(false); _leases[key] = new Lease(owner, DateTime.UtcNow + ttl); return Task.FromResult(true); } public Task ReleaseAsync(string tenantId, string runId, string owner) { var key = $"{tenantId}:{runId}"; // Remove only if the owner still matches (compare-and-delete). return Task.FromResult(_leases.TryRemove(key, out var lease) && lease.Owner == owner); } }