Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent double configuration of options #438

Merged
merged 3 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class AzureDevOpsEventSerializer : AbstractEventSerializer
{
private readonly JsonSerializer serializer = JsonSerializer.CreateDefault();

public AzureDevOpsEventSerializer(IOptionsMonitor<EventBusOptions> optionsAccessor,
public AzureDevOpsEventSerializer(IOptionsMonitor<EventBusSerializationOptions> optionsAccessor,
ILoggerFactory loggerFactory)
: base(optionsAccessor, loggerFactory) { }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class NewtonsoftJsonSerializer : AbstractEventSerializer
/// <param name="optionsAccessor"></param>
/// <param name="loggerFactory"></param>
public NewtonsoftJsonSerializer(IOptions<NewtonsoftJsonSerializerOptions> serializerOptionsAccessor,
IOptionsMonitor<EventBusOptions> optionsAccessor,
IOptionsMonitor<EventBusSerializationOptions> optionsAccessor,
ILoggerFactory loggerFactory)
: base(optionsAccessor, loggerFactory)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal class IotHubEventSerializer : AbstractEventSerializer
private static readonly Type BaseType = typeof(IotHubEvent<,,>);
private static readonly ConcurrentDictionary<Type, MappedTypes> typeMaps = new();

public IotHubEventSerializer(IOptionsMonitor<EventBusOptions> optionsAccessor,
public IotHubEventSerializer(IOptionsMonitor<EventBusSerializationOptions> optionsAccessor,
ILoggerFactory loggerFactory)
: base(optionsAccessor, loggerFactory) { }

Expand Down
26 changes: 23 additions & 3 deletions src/Tingle.EventBus/DependencyInjection/EventBusBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ public EventBusBuilder(IServiceCollection services)
/// </summary>
public IServiceCollection Services { get; }

/// <summary>
/// Configure options for EventBus
/// </summary>
/// <summary>Configure options for the EventBus.</summary>
/// <param name="configure"></param>
/// <returns></returns>
public EventBusBuilder Configure(Action<EventBusOptions> configure)
Expand All @@ -59,6 +57,28 @@ public EventBusBuilder Configure(Action<EventBusOptions> configure)
return this;
}

/// <summary>Configure readiness options for the EventBus.</summary>
/// <param name="configure"></param>
/// <returns></returns>
public EventBusBuilder ConfigureReadiness(Action<EventBusReadinessOptions> configure)
{
if (configure is null) throw new ArgumentNullException(nameof(configure));

Services.Configure(configure);
return this;
}

/// <summary>Configure serialization options for the EventBus.</summary>
/// <param name="configure"></param>
/// <returns></returns>
public EventBusBuilder ConfigureSerialization(Action<EventBusSerializationOptions> configure)
{
if (configure is null) throw new ArgumentNullException(nameof(configure));

Services.Configure(configure);
return this;
}

/// <summary>
/// Register a transport to be used by the bus.
/// </summary>
Expand Down
80 changes: 48 additions & 32 deletions src/Tingle.EventBus/DependencyInjection/EventBusConfigureOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ namespace Microsoft.Extensions.DependencyInjection;
/// <summary>
/// A class to finish configure non-trivial defaults of instances of <see cref="EventBusOptions"/>.
/// </summary>
internal class EventBusConfigureOptions : IConfigureOptions<EventBusOptions>, IPostConfigureOptions<EventBusOptions>
internal class EventBusConfigureOptions : IConfigureOptions<EventBusOptions>,
IPostConfigureOptions<EventBusOptions>,
IPostConfigureOptions<EventBusReadinessOptions>,
IConfigureOptions<EventBusSerializationOptions>,
IPostConfigureOptions<EventBusSerializationOptions>
{
private readonly IHostEnvironment environment;
private readonly IEnumerable<IEventConfigurator> configurators;
Expand All @@ -25,50 +29,20 @@ public void Configure(EventBusOptions options)
{
// Set the default ConsumerNamePrefix
options.Naming.ConsumerNamePrefix ??= environment.ApplicationName;

// Setup HostInfo
if (options.HostInfo == null)
{
var entry = System.Reflection.Assembly.GetEntryAssembly() ?? System.Reflection.Assembly.GetCallingAssembly();
options.HostInfo = new HostInfo
{
ApplicationName = environment.ApplicationName,
ApplicationVersion = entry.GetName().Version?.ToString(),
EnvironmentName = environment.EnvironmentName,
LibraryVersion = typeof(EventBus).Assembly.GetName().Version?.ToString(),
MachineName = Environment.MachineName,
OperatingSystem = Environment.OSVersion.ToString(),
};
}
}

/// <inheritdoc/>
public void PostConfigure(string name, EventBusOptions options)
{
// Check bounds for readiness timeout
var ticks = options.Readiness.Timeout.Ticks;
if (options.Readiness.Enabled)
{
ticks = Math.Max(ticks, TimeSpan.FromSeconds(5).Ticks); // must be more than 5 seconds
ticks = Math.Min(ticks, TimeSpan.FromMinutes(15).Ticks); // must be less than 15 minutes
options.Readiness.Timeout = TimeSpan.FromTicks(ticks);
}

// Check bounds for duplicate detection duration, if duplicate detection is enabled
if (options.EnableDeduplication)
{
ticks = options.DuplicateDetectionDuration.Ticks;
var ticks = options.DuplicateDetectionDuration.Ticks;
ticks = Math.Max(ticks, TimeSpan.FromSeconds(20).Ticks); // must be more than 20 seconds
ticks = Math.Min(ticks, TimeSpan.FromDays(7).Ticks); // must be less than 7 days
options.DuplicateDetectionDuration = TimeSpan.FromTicks(ticks);
}

// Ensure we have HostInfo set
if (options.HostInfo == null)
{
throw new InvalidOperationException($"'{nameof(options.HostInfo)}' must be set.");
}

// Ensure there is at least one registered transport
if (options.RegisteredTransportNames.Count == 0)
{
Expand Down Expand Up @@ -126,4 +100,46 @@ public void PostConfigure(string name, EventBusOptions options)
}
}
}

/// <inheritdoc/>
public void PostConfigure(string name, EventBusReadinessOptions options)
{
// Check bounds for readiness timeout
var ticks = options.Timeout.Ticks;
if (options.Enabled)
{
ticks = Math.Max(ticks, TimeSpan.FromSeconds(5).Ticks); // must be more than 5 seconds
ticks = Math.Min(ticks, TimeSpan.FromMinutes(15).Ticks); // must be less than 15 minutes
options.Timeout = TimeSpan.FromTicks(ticks);
}
}

/// <inheritdoc/>
public void Configure(EventBusSerializationOptions options)
{
// Setup HostInfo
if (options.HostInfo == null)
{
var entry = System.Reflection.Assembly.GetEntryAssembly() ?? System.Reflection.Assembly.GetCallingAssembly();
options.HostInfo = new HostInfo
{
ApplicationName = environment.ApplicationName,
ApplicationVersion = entry.GetName().Version?.ToString(),
EnvironmentName = environment.EnvironmentName,
LibraryVersion = typeof(EventBus).Assembly.GetName().Version?.ToString(),
MachineName = Environment.MachineName,
OperatingSystem = Environment.OSVersion.ToString(),
};
}
}

/// <inheritdoc/>
public void PostConfigure(string name, EventBusSerializationOptions options)
{
// Ensure we have HostInfo set
if (options.HostInfo == null)
{
throw new InvalidOperationException($"'{nameof(options.HostInfo)}' must be set.");
}
}
}
29 changes: 0 additions & 29 deletions src/Tingle.EventBus/DependencyInjection/EventBusOptions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using Polly.Retry;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using Tingle.EventBus;
using Tingle.EventBus.Configuration;
using Tingle.EventBus.Serialization;
using Tingle.EventBus.Transports;

namespace Microsoft.Extensions.DependencyInjection;
Expand All @@ -19,38 +17,11 @@ public class EventBusOptions
/// </summary>
public TimeSpan? StartupDelay { get; set; }

/// <summary>
/// Gets the <see cref="EventBusReadinessOptions"/> for the Event Bus.
/// </summary>
public EventBusReadinessOptions Readiness { get; } = new EventBusReadinessOptions();

/// <summary>
/// Gets the <see cref="EventBusNamingOptions"/> for the Event Bus.
/// </summary>
public EventBusNamingOptions Naming { get; } = new EventBusNamingOptions();

/// <summary>
/// The options to use for serialization.
/// </summary>
public JsonSerializerOptions SerializerOptions { get; set; } = new JsonSerializerOptions
{
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals
| System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString,
WriteIndented = false, // less data used
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault
| System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,

PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip,
};

/// <summary>
/// The information about the host where the EventBus is running.
/// </summary>
public HostInfo? HostInfo { get; set; }

/// <summary>
/// Indicates if the messages/events produced require guard against duplicate messages.
/// If <see langword="true"/>, duplicate messages having the same <see cref="EventContext.Id"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Text.Json;
using Tingle.EventBus.Serialization;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Specified options for serialization.
/// </summary>
public class EventBusSerializationOptions
{
/// <summary>
/// The options to use for serialization.
/// </summary>
public JsonSerializerOptions SerializerOptions { get; set; } = new JsonSerializerOptions
{
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals
| System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString,
WriteIndented = false, // less data used
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault
| System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,

PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip,
};

/// <summary>
/// The information about the host where the EventBus is running.
/// </summary>
public HostInfo? HostInfo { get; set; }
}
21 changes: 9 additions & 12 deletions src/Tingle.EventBus/EventBus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,19 +230,16 @@ public async Task StartAsync(CancellationToken cancellationToken)

private async Task StartTransportsAsync(CancellationToken cancellationToken)
{
if (options.Readiness.Enabled)
try
{
try
{
// Perform readiness check before starting bus.
logger.StartupReadinessCheck();
await readinessProvider.WaitReadyAsync(cancellationToken: cancellationToken);
}
catch (Exception ex)
{
logger.StartupReadinessCheckFailed(ex);
throw; // re-throw to prevent from getting healthy
}
// Perform readiness check before starting bus.
logger.StartupReadinessCheck();
await readinessProvider.WaitReadyAsync(cancellationToken: cancellationToken);
}
catch (Exception ex)
{
logger.StartupReadinessCheckFailed(ex);
throw; // re-throw to prevent from getting healthy
}

// Start the bus and its transports
Expand Down
4 changes: 2 additions & 2 deletions src/Tingle.EventBus/Readiness/DefaultReadinessProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ internal class DefaultReadinessProvider : IReadinessProvider, IHealthCheckPublis

private HealthReport? healthReport;

public DefaultReadinessProvider(IOptions<EventBusOptions> optionsAccessor,
public DefaultReadinessProvider(IOptions<EventBusReadinessOptions> optionsAccessor,
ILogger<DefaultReadinessProvider> logger)
{
options = optionsAccessor?.Value?.Readiness ?? throw new ArgumentNullException(nameof(optionsAccessor));
options = optionsAccessor?.Value ?? throw new ArgumentNullException(nameof(optionsAccessor));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

Expand Down
4 changes: 2 additions & 2 deletions src/Tingle.EventBus/Serialization/AbstractEventSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public abstract class AbstractEventSerializer : IEventSerializer
/// </summary>
/// <param name="optionsAccessor"></param>
/// <param name="loggerFactory"></param>
protected AbstractEventSerializer(IOptionsMonitor<EventBusOptions> optionsAccessor, ILoggerFactory loggerFactory)
protected AbstractEventSerializer(IOptionsMonitor<EventBusSerializationOptions> optionsAccessor, ILoggerFactory loggerFactory)
{
OptionsAccessor = optionsAccessor ?? throw new ArgumentNullException(nameof(optionsAccessor));

Expand All @@ -39,7 +39,7 @@ protected AbstractEventSerializer(IOptionsMonitor<EventBusOptions> optionsAccess
protected abstract IList<string> SupportedMediaTypes { get; }

///
protected IOptionsMonitor<EventBusOptions> OptionsAccessor { get; }
protected IOptionsMonitor<EventBusSerializationOptions> OptionsAccessor { get; }

///
protected ILogger Logger { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class DefaultJsonEventSerializer : AbstractEventSerializer
/// </summary>
/// <param name="optionsAccessor">The options for configuring the serializer.</param>
/// <param name="loggerFactory"></param>
public DefaultJsonEventSerializer(IOptionsMonitor<EventBusOptions> optionsAccessor,
public DefaultJsonEventSerializer(IOptionsMonitor<EventBusSerializationOptions> optionsAccessor,
ILoggerFactory loggerFactory)
: base(optionsAccessor, loggerFactory) { }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class XmlEventSerializer : AbstractEventSerializer
/// </summary>
/// <param name="optionsAccessor">The options for configuring the serializer.</param>
/// <param name="loggerFactory"></param>
public XmlEventSerializer(IOptionsMonitor<EventBusOptions> optionsAccessor,
public XmlEventSerializer(IOptionsMonitor<EventBusSerializationOptions> optionsAccessor,
ILoggerFactory loggerFactory)
: base(optionsAccessor, loggerFactory) { }

Expand Down