Files
git.stella-ops.org/src/JobEngine/StellaOps.Scheduler.WebService/Schedules/InMemorySchedulerServices.cs

159 lines
5.3 KiB
C#

using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
using System.Collections.Concurrent;
using System.Collections.Immutable;
namespace StellaOps.Scheduler.WebService.Schedules;
internal sealed class InMemoryScheduleRepository : IScheduleRepository
{
private readonly ConcurrentDictionary<string, Schedule> _schedules = new(StringComparer.Ordinal);
public Task UpsertAsync(
Schedule schedule,
CancellationToken cancellationToken = default)
{
_schedules[schedule.Id] = schedule;
return Task.CompletedTask;
}
public Task<Schedule?> GetAsync(
string tenantId,
string scheduleId,
CancellationToken cancellationToken = default)
{
if (_schedules.TryGetValue(scheduleId, out var schedule) &&
string.Equals(schedule.TenantId, tenantId, StringComparison.Ordinal))
{
return Task.FromResult<Schedule?>(schedule);
}
return Task.FromResult<Schedule?>(null);
}
public Task<IReadOnlyList<Schedule>> ListAsync(
string tenantId,
ScheduleQueryOptions? options = null,
CancellationToken cancellationToken = default)
{
options ??= new ScheduleQueryOptions();
var query = _schedules.Values
.Where(schedule => string.Equals(schedule.TenantId, tenantId, StringComparison.Ordinal));
if (!options.IncludeDisabled)
{
query = query.Where(schedule => schedule.Enabled);
}
var result = query
.OrderBy(schedule => schedule.Name, StringComparer.Ordinal)
.Take(options.Limit ?? int.MaxValue)
.ToArray();
return Task.FromResult<IReadOnlyList<Schedule>>(result);
}
public Task<bool> SoftDeleteAsync(
string tenantId,
string scheduleId,
string deletedBy,
DateTimeOffset deletedAt,
CancellationToken cancellationToken = default)
{
if (_schedules.TryGetValue(scheduleId, out var schedule) &&
string.Equals(schedule.TenantId, tenantId, StringComparison.Ordinal))
{
_schedules.TryRemove(scheduleId, out _);
return Task.FromResult(true);
}
return Task.FromResult(false);
}
}
internal sealed class InMemoryRunSummaryService : IRunSummaryService
{
private readonly ConcurrentDictionary<(string TenantId, string ScheduleId), RunSummaryProjection> _summaries = new();
public Task<RunSummaryProjection> ProjectAsync(Run run, CancellationToken cancellationToken = default)
{
var scheduleId = run.ScheduleId ?? string.Empty;
var updatedAt = run.FinishedAt ?? run.StartedAt ?? run.CreatedAt;
var counters = new RunSummaryCounters(
Total: 0,
Planning: 0,
Queued: 0,
Running: 0,
Completed: 0,
Error: 0,
Cancelled: 0,
TotalDeltas: 0,
TotalNewCriticals: 0,
TotalNewHigh: 0,
TotalNewMedium: 0,
TotalNewLow: 0);
var projection = new RunSummaryProjection(
run.TenantId,
scheduleId,
updatedAt,
null,
ImmutableArray<RunSummarySnapshot>.Empty,
counters);
_summaries[(run.TenantId, scheduleId)] = projection;
return Task.FromResult(projection);
}
public Task<RunSummaryProjection?> GetAsync(string tenantId, string scheduleId, CancellationToken cancellationToken = default)
{
_summaries.TryGetValue((tenantId, scheduleId), out var projection);
return Task.FromResult<RunSummaryProjection?>(projection);
}
public Task<IReadOnlyList<RunSummaryProjection>> ListAsync(string tenantId, CancellationToken cancellationToken = default)
{
var projections = _summaries.Values
.Where(summary => string.Equals(summary.TenantId, tenantId, StringComparison.Ordinal))
.ToArray();
return Task.FromResult<IReadOnlyList<RunSummaryProjection>>(projections);
}
}
internal sealed class InMemorySchedulerAuditService : ISchedulerAuditService
{
private readonly TimeProvider _timeProvider;
private readonly StellaOps.Determinism.IGuidProvider _guidProvider;
public InMemorySchedulerAuditService(
TimeProvider? timeProvider = null,
StellaOps.Determinism.IGuidProvider? guidProvider = null)
{
_timeProvider = timeProvider ?? TimeProvider.System;
_guidProvider = guidProvider ?? StellaOps.Determinism.SystemGuidProvider.Instance;
}
public Task<AuditRecord> WriteAsync(SchedulerAuditEvent auditEvent, CancellationToken cancellationToken = default)
{
var occurredAt = auditEvent.OccurredAt ?? _timeProvider.GetUtcNow();
var record = new AuditRecord(
auditEvent.AuditId ?? $"audit_{_guidProvider.NewGuid():N}",
auditEvent.TenantId,
auditEvent.Category,
auditEvent.Action,
occurredAt,
auditEvent.Actor,
auditEvent.EntityId,
auditEvent.ScheduleId,
auditEvent.RunId,
auditEvent.CorrelationId,
auditEvent.Metadata?.ToImmutableSortedDictionary(StringComparer.OrdinalIgnoreCase) ?? ImmutableSortedDictionary<string, string>.Empty,
auditEvent.Message);
return Task.FromResult(record);
}
}