109 lines
4.3 KiB
C#
109 lines
4.3 KiB
C#
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using StellaOps.Messaging;
|
|
using StellaOps.Messaging.Abstractions;
|
|
using StellaOps.Scheduler.WebService.Options;
|
|
using System.Globalization;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace StellaOps.Scheduler.WebService.GraphJobs.Events;
|
|
|
|
/// <summary>
|
|
/// Transport-agnostic implementation of <see cref="IGraphJobCompletionPublisher"/> using StellaOps.Messaging abstractions.
|
|
/// Works with any configured transport (Valkey, PostgreSQL, InMemory).
|
|
/// </summary>
|
|
internal sealed class MessagingGraphJobEventPublisher : IGraphJobCompletionPublisher
|
|
{
|
|
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web)
|
|
{
|
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
|
};
|
|
|
|
private readonly IOptionsMonitor<SchedulerEventsOptions> _options;
|
|
private readonly IEventStream<GraphJobCompletedEvent> _eventStream;
|
|
private readonly ILogger<MessagingGraphJobEventPublisher> _logger;
|
|
|
|
public MessagingGraphJobEventPublisher(
|
|
IOptionsMonitor<SchedulerEventsOptions> options,
|
|
IEventStreamFactory eventStreamFactory,
|
|
ILogger<MessagingGraphJobEventPublisher> logger)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(options);
|
|
ArgumentNullException.ThrowIfNull(eventStreamFactory);
|
|
|
|
_options = options;
|
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
|
|
var eventsOptions = options.CurrentValue?.GraphJobs ?? new GraphJobEventsOptions();
|
|
var streamKey = string.IsNullOrWhiteSpace(eventsOptions.Stream) ? "stella.events" : eventsOptions.Stream;
|
|
var maxStreamLength = eventsOptions.MaxStreamLength > 0 ? eventsOptions.MaxStreamLength : (long?)null;
|
|
|
|
_eventStream = eventStreamFactory.Create<GraphJobCompletedEvent>(new EventStreamOptions
|
|
{
|
|
StreamName = streamKey,
|
|
MaxLength = maxStreamLength,
|
|
ApproximateTrimming = true,
|
|
});
|
|
|
|
_logger.LogInformation("Initialized messaging graph job event publisher for stream {Stream}.", streamKey);
|
|
}
|
|
|
|
public async Task PublishAsync(GraphJobCompletionNotification notification, CancellationToken cancellationToken)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(notification);
|
|
|
|
var options = _options.CurrentValue?.GraphJobs ?? new GraphJobEventsOptions();
|
|
if (!options.Enabled)
|
|
{
|
|
_logger.LogDebug("Graph job events disabled; skipping emission for {JobId}.", notification.Job.Id);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var envelope = GraphJobEventFactory.Create(notification);
|
|
|
|
var publishOptions = new EventPublishOptions
|
|
{
|
|
TenantId = envelope.Tenant,
|
|
MaxStreamLength = options.MaxStreamLength > 0 ? options.MaxStreamLength : null,
|
|
Headers = new Dictionary<string, string>
|
|
{
|
|
["kind"] = envelope.Kind,
|
|
["occurredAt"] = envelope.Timestamp.ToString("O", CultureInfo.InvariantCulture),
|
|
["jobId"] = notification.Job.Id,
|
|
["status"] = notification.Status.ToString()
|
|
}
|
|
};
|
|
|
|
var publishTask = _eventStream.PublishAsync(envelope, publishOptions, cancellationToken);
|
|
|
|
if (options.PublishTimeoutSeconds > 0)
|
|
{
|
|
var timeout = TimeSpan.FromSeconds(options.PublishTimeoutSeconds);
|
|
await publishTask.AsTask().WaitAsync(timeout, cancellationToken).ConfigureAwait(false);
|
|
}
|
|
else
|
|
{
|
|
await publishTask.ConfigureAwait(false);
|
|
}
|
|
|
|
_logger.LogDebug("Published graph job event {JobId} to stream.", notification.Job.Id);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to publish graph job completion for {JobId}; logging payload instead.", notification.Job.Id);
|
|
LogEnvelope(notification);
|
|
}
|
|
}
|
|
|
|
private void LogEnvelope(GraphJobCompletionNotification notification)
|
|
{
|
|
var envelope = GraphJobEventFactory.Create(notification);
|
|
var json = JsonSerializer.Serialize(envelope, SerializerOptions);
|
|
_logger.LogInformation("{EventJson}", json);
|
|
}
|
|
}
|