forked from oskardudycz/EventSourcing.NetCore
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replaced MediatR event bus with the custom one to enable scoping, tra…
…cing etc. Plugged that fully into Marten and EventStoreDB
- Loading branch information
1 parent
810ae76
commit a28a3e6
Showing
32 changed files
with
188 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,86 @@ | ||
using Core.Events.External; | ||
using MediatR; | ||
using System.Collections.Concurrent; | ||
using System.Reflection; | ||
using Core.Tracing; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Polly; | ||
|
||
namespace Core.Events; | ||
|
||
public interface IEventBus | ||
{ | ||
Task Publish(IEvent @event, CancellationToken ct); | ||
Task Publish(IEvent[] events, CancellationToken ct); | ||
Task Publish(object @event, CancellationToken ct); | ||
} | ||
|
||
public class EventBus: IEventBus | ||
{ | ||
private readonly IMediator mediator; | ||
private readonly IExternalEventProducer externalEventProducer; | ||
private readonly IServiceProvider serviceProvider; | ||
private readonly Func<IServiceProvider, EventEnvelope?, TracingScope> createTracingScope; | ||
private readonly AsyncPolicy retryPolicy; | ||
private static readonly ConcurrentDictionary<Type, MethodInfo> PublishMethods = new(); | ||
|
||
public EventBus( | ||
IMediator mediator, | ||
IExternalEventProducer externalEventProducer | ||
IServiceProvider serviceProvider, | ||
Func<IServiceProvider, EventEnvelope?, TracingScope> createTracingScope, | ||
AsyncPolicy retryPolicy | ||
) | ||
{ | ||
this.mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); | ||
this.externalEventProducer = externalEventProducer?? throw new ArgumentNullException(nameof(externalEventProducer)); | ||
this.serviceProvider = serviceProvider; | ||
this.createTracingScope = createTracingScope; | ||
this.retryPolicy = retryPolicy; | ||
} | ||
|
||
public async Task Publish(IEvent[] events, CancellationToken ct) | ||
private async Task Publish<TEvent>(TEvent @event, CancellationToken ct) | ||
{ | ||
foreach (var @event in events) | ||
var eventEnvelope = @event as EventEnvelope; | ||
// You can consider adding here a retry policy for event handling | ||
using var scope = serviceProvider.CreateScope(); | ||
using var tracingScope = createTracingScope(serviceProvider, eventEnvelope); | ||
|
||
var eventHandlers = | ||
scope.ServiceProvider.GetServices<IEventHandler<TEvent>>(); | ||
|
||
foreach (var eventHandler in eventHandlers) | ||
{ | ||
await Publish(@event, ct); | ||
await retryPolicy.ExecuteAsync(async token => | ||
{ | ||
await eventHandler.Handle(@event, token); | ||
}, ct); | ||
} | ||
} | ||
|
||
public async Task Publish(IEvent @event, CancellationToken ct) | ||
public async Task Publish(object @event, CancellationToken ct) | ||
{ | ||
// if it's an event envelope, publish also just event data | ||
// thanks to that both handlers with envelope and without will be called | ||
if (@event is EventEnvelope(var data, _)) | ||
await (Task)GetGenericPublishFor(data) | ||
.Invoke(this, new[] { data, ct })!; | ||
|
||
await (Task)GetGenericPublishFor(@event) | ||
.Invoke(this, new[] { @event, ct })!; | ||
} | ||
|
||
private static MethodInfo GetGenericPublishFor(object @event) => | ||
PublishMethods.GetOrAdd(@event.GetType(), eventType => | ||
typeof(EventBus) | ||
.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic) | ||
.Single(m => m.Name == nameof(Publish) && m.GetGenericArguments().Any()) | ||
.MakeGenericMethod(eventType) | ||
); | ||
} | ||
|
||
public static class EventBusExtensions | ||
{ | ||
public static IServiceCollection AddEventBus(this IServiceCollection services, AsyncPolicy? asyncPolicy = null) | ||
{ | ||
await mediator.Publish(@event, ct); | ||
services.AddScoped<IEventBus, EventBus>(sp => | ||
new EventBus( | ||
sp, | ||
sp.GetRequiredService<ITracingScopeFactory>().CreateTraceScope, | ||
asyncPolicy ?? Policy.NoOpAsync() | ||
) | ||
); | ||
|
||
if (@event is IExternalEvent externalEvent) | ||
await externalEventProducer.Publish(externalEvent, ct); | ||
return services; | ||
} | ||
} |
Oops, something went wrong.