Files
git.stella-ops.org/src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo/JobRunDocument.cs
2025-10-28 15:10:40 +02:00

120 lines
4.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using StellaOps.Concelier.Core.Jobs;
namespace StellaOps.Concelier.Storage.Mongo;
[BsonIgnoreExtraElements]
public sealed class JobRunDocument
{
[BsonId]
public string Id { get; set; } = string.Empty;
[BsonElement("kind")]
public string Kind { get; set; } = string.Empty;
[BsonElement("status")]
public string Status { get; set; } = JobRunStatus.Pending.ToString();
[BsonElement("trigger")]
public string Trigger { get; set; } = string.Empty;
[BsonElement("parameters")]
public BsonDocument Parameters { get; set; } = new();
[BsonElement("parametersHash")]
[BsonIgnoreIfNull]
public string? ParametersHash { get; set; }
[BsonElement("createdAt")]
public DateTime CreatedAt { get; set; }
[BsonElement("startedAt")]
[BsonIgnoreIfNull]
public DateTime? StartedAt { get; set; }
[BsonElement("completedAt")]
[BsonIgnoreIfNull]
public DateTime? CompletedAt { get; set; }
[BsonElement("error")]
[BsonIgnoreIfNull]
public string? Error { get; set; }
[BsonElement("timeoutMs")]
[BsonIgnoreIfNull]
public long? TimeoutMs { get; set; }
[BsonElement("leaseMs")]
[BsonIgnoreIfNull]
public long? LeaseMs { get; set; }
}
internal static class JobRunDocumentExtensions
{
public static JobRunDocument FromRequest(JobRunCreateRequest request, Guid id)
{
return new JobRunDocument
{
Id = id.ToString(),
Kind = request.Kind,
Status = JobRunStatus.Pending.ToString(),
Trigger = request.Trigger,
Parameters = request.Parameters is { Count: > 0 }
? BsonDocument.Parse(JsonSerializer.Serialize(request.Parameters))
: new BsonDocument(),
ParametersHash = request.ParametersHash,
CreatedAt = request.CreatedAt.UtcDateTime,
TimeoutMs = request.Timeout?.MillisecondsFromTimespan(),
LeaseMs = request.LeaseDuration?.MillisecondsFromTimespan(),
};
}
public static JobRunSnapshot ToSnapshot(this JobRunDocument document)
{
var parameters = document.Parameters?.ToDictionary() ?? new Dictionary<string, object?>();
return new JobRunSnapshot(
Guid.Parse(document.Id),
document.Kind,
Enum.Parse<JobRunStatus>(document.Status, ignoreCase: true),
DateTime.SpecifyKind(document.CreatedAt, DateTimeKind.Utc),
document.StartedAt.HasValue ? DateTime.SpecifyKind(document.StartedAt.Value, DateTimeKind.Utc) : null,
document.CompletedAt.HasValue ? DateTime.SpecifyKind(document.CompletedAt.Value, DateTimeKind.Utc) : null,
document.Trigger,
document.ParametersHash,
document.Error,
document.TimeoutMs?.MillisecondsToTimespan(),
document.LeaseMs?.MillisecondsToTimespan(),
parameters);
}
public static Dictionary<string, object?> ToDictionary(this BsonDocument document)
{
return document.Elements.ToDictionary(
static element => element.Name,
static element => element.Value switch
{
BsonString s => (object?)s.AsString,
BsonBoolean b => b.AsBoolean,
BsonInt32 i => i.AsInt32,
BsonInt64 l => l.AsInt64,
BsonDouble d => d.AsDouble,
BsonNull => null,
BsonArray array => array.Select(v => v.IsBsonDocument ? ToDictionary(v.AsBsonDocument) : (object?)v.ToString()).ToArray(),
BsonDocument doc => ToDictionary(doc),
_ => element.Value.ToString(),
});
}
private static long MillisecondsFromTimespan(this TimeSpan timeSpan)
=> (long)timeSpan.TotalMilliseconds;
private static TimeSpan MillisecondsToTimespan(this long milliseconds)
=> TimeSpan.FromMilliseconds(milliseconds);
}