Browse Source

Merge pull request #16333 from abpframework/DistributedEventSentAndReceived

Inform when a new distributed message received or sent.
pull/16520/head
Halil İbrahim Kalkan 3 years ago
committed by GitHub
parent
commit
034e451e6a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Controllers/AbpAspNetCoreMvcDaprEventsController.cs
  2. 10
      framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventReceived.cs
  3. 10
      framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventSent.cs
  4. 10
      framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventSource.cs
  5. 101
      framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs
  6. 40
      framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs
  7. 56
      framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs
  8. 49
      framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs
  9. 41
      framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs
  10. 93
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs
  11. 28
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus.cs
  12. 8
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs
  13. 42
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs
  14. 2
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbDateTimeSerializer.cs
  15. 22
      framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/DistributedEventHandles.cs
  16. 44
      framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs

3
framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Controllers/AbpAspNetCoreMvcDaprEventsController.cs

@ -21,6 +21,7 @@ public class AbpAspNetCoreMvcDaprEventsController : AbpController
var daprSerializer = HttpContext.RequestServices.GetRequiredService<IDaprSerializer>(); var daprSerializer = HttpContext.RequestServices.GetRequiredService<IDaprSerializer>();
var body = (await JsonDocument.ParseAsync(HttpContext.Request.Body)); var body = (await JsonDocument.ParseAsync(HttpContext.Request.Body));
var id = body.RootElement.GetProperty("id").GetString();
var pubSubName = body.RootElement.GetProperty("pubsubname").GetString(); var pubSubName = body.RootElement.GetProperty("pubsubname").GetString();
var topic = body.RootElement.GetProperty("topic").GetString(); var topic = body.RootElement.GetProperty("topic").GetString();
var data = body.RootElement.GetProperty("data").GetRawText(); var data = body.RootElement.GetProperty("data").GetRawText();
@ -32,7 +33,7 @@ public class AbpAspNetCoreMvcDaprEventsController : AbpController
var distributedEventBus = HttpContext.RequestServices.GetRequiredService<DaprDistributedEventBus>(); var distributedEventBus = HttpContext.RequestServices.GetRequiredService<DaprDistributedEventBus>();
var eventData = daprSerializer.Deserialize(data, distributedEventBus.GetEventType(topic)); var eventData = daprSerializer.Deserialize(data, distributedEventBus.GetEventType(topic));
await distributedEventBus.TriggerHandlersAsync(distributedEventBus.GetEventType(topic), eventData); await distributedEventBus.TriggerHandlersAsync(id, distributedEventBus.GetEventType(topic), eventData);
return Ok(); return Ok();
} }
} }

10
framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventReceived.cs

@ -0,0 +1,10 @@
namespace Volo.Abp.EventBus.Distributed;
public class DistributedEventReceived
{
public DistributedEventSource Source { get; set; }
public string EventName { get; set; }
public object EventData { get; set; }
}

10
framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventSent.cs

@ -0,0 +1,10 @@
namespace Volo.Abp.EventBus.Distributed;
public class DistributedEventSent
{
public DistributedEventSource Source { get; set; }
public string EventName { get; set; }
public object EventData { get; set; }
}

10
framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/DistributedEventSource.cs

@ -0,0 +1,10 @@
namespace Volo.Abp.EventBus.Distributed;
public enum DistributedEventSource
{
Direct,
Inbox,
Outbox
}

101
framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs

@ -9,6 +9,7 @@ using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
using Volo.Abp.AzureServiceBus; using Volo.Abp.AzureServiceBus;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
@ -21,13 +22,13 @@ namespace Volo.Abp.EventBus.Azure;
[ExposeServices(typeof(IDistributedEventBus), typeof(AzureDistributedEventBus))] [ExposeServices(typeof(IDistributedEventBus), typeof(AzureDistributedEventBus))]
public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDependency public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDependency
{ {
private readonly AbpAzureEventBusOptions _options; protected AbpAzureEventBusOptions Options { get; }
private readonly IAzureServiceBusMessageConsumerFactory _messageConsumerFactory; protected IAzureServiceBusMessageConsumerFactory MessageConsumerFactory { get; }
private readonly IPublisherPool _publisherPool; protected IPublisherPool PublisherPool { get; }
private readonly IAzureServiceBusSerializer _serializer; protected IAzureServiceBusSerializer Serializer { get; }
private readonly ConcurrentDictionary<Type, List<IEventHandlerFactory>> _handlerFactories; protected ConcurrentDictionary<Type, List<IEventHandlerFactory>> HandlerFactories { get; }
private readonly ConcurrentDictionary<string, Type> _eventTypes; protected ConcurrentDictionary<string, Type> EventTypes { get; }
private IAzureServiceBusMessageConsumer _consumer; protected IAzureServiceBusMessageConsumer Consumer { get; private set; }
public AzureDistributedEventBus( public AzureDistributedEventBus(
IServiceScopeFactory serviceScopeFactory, IServiceScopeFactory serviceScopeFactory,
@ -40,31 +41,33 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
IAzureServiceBusSerializer serializer, IAzureServiceBusSerializer serializer,
IAzureServiceBusMessageConsumerFactory messageConsumerFactory, IAzureServiceBusMessageConsumerFactory messageConsumerFactory,
IPublisherPool publisherPool, IPublisherPool publisherPool,
IEventHandlerInvoker eventHandlerInvoker) IEventHandlerInvoker eventHandlerInvoker,
ILocalEventBus localEventBus)
: base(serviceScopeFactory, : base(serviceScopeFactory,
currentTenant, currentTenant,
unitOfWorkManager, unitOfWorkManager,
abpDistributedEventBusOptions, abpDistributedEventBusOptions,
guidGenerator, guidGenerator,
clock, clock,
eventHandlerInvoker) eventHandlerInvoker,
localEventBus)
{ {
_options = abpAzureEventBusOptions.Value; Options = abpAzureEventBusOptions.Value;
_serializer = serializer; Serializer = serializer;
_messageConsumerFactory = messageConsumerFactory; MessageConsumerFactory = messageConsumerFactory;
_publisherPool = publisherPool; PublisherPool = publisherPool;
_handlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>(); HandlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>();
_eventTypes = new ConcurrentDictionary<string, Type>(); EventTypes = new ConcurrentDictionary<string, Type>();
} }
public void Initialize() public void Initialize()
{ {
_consumer = _messageConsumerFactory.CreateMessageConsumer( Consumer = MessageConsumerFactory.CreateMessageConsumer(
_options.TopicName, Options.TopicName,
_options.SubscriberName, Options.SubscriberName,
_options.ConnectionName); Options.ConnectionName);
_consumer.OnMessageReceived(ProcessEventAsync); Consumer.OnMessageReceived(ProcessEventAsync);
SubscribeHandlers(AbpDistributedEventBusOptions.Handlers); SubscribeHandlers(AbpDistributedEventBusOptions.Handlers);
} }
@ -75,24 +78,31 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
{ {
return; return;
} }
var eventType = _eventTypes.GetOrDefault(eventName); var eventType = EventTypes.GetOrDefault(eventName);
if (eventType == null) if (eventType == null)
{ {
return; return;
} }
if (await AddToInboxAsync(message.MessageId, eventName, eventType, message.Body.ToArray())) var eventData = Serializer.Deserialize(message.Body.ToArray(), eventType);
if (await AddToInboxAsync(message.MessageId, eventName, eventType, eventData))
{ {
return; return;
} }
var eventData = _serializer.Deserialize(message.Body.ToArray(), eventType); await TriggerHandlersDirectAsync(eventType, eventData);
await TriggerHandlersAsync(eventType, eventData);
} }
public async override Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig) public async override Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig)
{ {
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
await PublishAsync(outgoingEvent.EventName, outgoingEvent.EventData, outgoingEvent.Id); await PublishAsync(outgoingEvent.EventName, outgoingEvent.EventData, outgoingEvent.Id);
} }
@ -100,9 +110,9 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
{ {
var outgoingEventArray = outgoingEvents.ToArray(); var outgoingEventArray = outgoingEvents.ToArray();
var publisher = await _publisherPool.GetAsync( var publisher = await PublisherPool.GetAsync(
_options.TopicName, Options.TopicName,
_options.ConnectionName); Options.ConnectionName);
using var messageBatch = await publisher.CreateMessageBatchAsync(); using var messageBatch = await publisher.CreateMessageBatchAsync();
@ -120,6 +130,13 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
throw new AbpException( throw new AbpException(
"The message is too large to fit in the batch. Set AbpEventBusBoxesOptions.OutboxWaitingEventMaxCount to reduce the number"); "The message is too large to fit in the batch. Set AbpEventBusBoxesOptions.OutboxWaitingEventMaxCount to reduce the number");
} }
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
} }
await publisher.SendMessagesAsync(messageBatch); await publisher.SendMessagesAsync(messageBatch);
@ -127,15 +144,15 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
public async override Task ProcessFromInboxAsync(IncomingEventInfo incomingEvent, InboxConfig inboxConfig) public async override Task ProcessFromInboxAsync(IncomingEventInfo incomingEvent, InboxConfig inboxConfig)
{ {
var eventType = _eventTypes.GetOrDefault(incomingEvent.EventName); var eventType = EventTypes.GetOrDefault(incomingEvent.EventName);
if (eventType == null) if (eventType == null)
{ {
return; return;
} }
var eventData = _serializer.Deserialize(incomingEvent.EventData, eventType); var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
var exceptions = new List<Exception>(); var exceptions = new List<Exception>();
await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig); await TriggerHandlersFromInboxAsync(eventType, eventData, exceptions, inboxConfig);
if (exceptions.Any()) if (exceptions.Any())
{ {
ThrowOriginalExceptions(eventType, exceptions); ThrowOriginalExceptions(eventType, exceptions);
@ -144,7 +161,7 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
protected override byte[] Serialize(object eventData) protected override byte[] Serialize(object eventData)
{ {
return _serializer.Serialize(eventData); return Serializer.Serialize(eventData);
} }
public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory) public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory)
@ -225,7 +242,7 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
protected virtual Task PublishAsync(string eventName, object eventData) protected virtual Task PublishAsync(string eventName, object eventData)
{ {
var body = _serializer.Serialize(eventData); var body = Serializer.Serialize(eventData);
return PublishAsync(eventName, body, null); return PublishAsync(eventName, body, null);
} }
@ -245,16 +262,16 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
message.MessageId = (eventId ?? GuidGenerator.Create()).ToString("N"); message.MessageId = (eventId ?? GuidGenerator.Create()).ToString("N");
} }
var publisher = await _publisherPool.GetAsync( var publisher = await PublisherPool.GetAsync(
_options.TopicName, Options.TopicName,
_options.ConnectionName); Options.ConnectionName);
await publisher.SendMessageAsync(message); await publisher.SendMessageAsync(message);
} }
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType) protected override IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType)
{ {
return _handlerFactories return HandlerFactories
.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key)) .Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key))
.Select(handlerFactory => .Select(handlerFactory =>
new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value)) new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value))
@ -266,14 +283,20 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
return handlerEventType == targetEventType || handlerEventType.IsAssignableFrom(targetEventType); return handlerEventType == targetEventType || handlerEventType.IsAssignableFrom(targetEventType);
} }
protected override Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
EventTypes.GetOrAdd(eventName, eventType);
return base.OnAddToOutboxAsync(eventName, eventType, eventData);
}
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType) private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType)
{ {
return _handlerFactories.GetOrAdd( return HandlerFactories.GetOrAdd(
eventType, eventType,
type => type =>
{ {
var eventName = EventNameAttribute.GetNameOrDefault(type); var eventName = EventNameAttribute.GetNameOrDefault(type);
_eventTypes[eventName] = type; EventTypes.GetOrAdd(eventName, eventType);
return new List<IEventHandlerFactory>(); return new List<IEventHandlerFactory>();
} }
); );

40
framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs

@ -8,6 +8,7 @@ using Microsoft.Extensions.Options;
using Volo.Abp.Dapr; using Volo.Abp.Dapr;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
@ -37,8 +38,9 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
IEventHandlerInvoker eventHandlerInvoker, IEventHandlerInvoker eventHandlerInvoker,
IDaprSerializer serializer, IDaprSerializer serializer,
IOptions<AbpDaprEventBusOptions> daprEventBusOptions, IOptions<AbpDaprEventBusOptions> daprEventBusOptions,
IAbpDaprClientFactory daprClientFactory) IAbpDaprClientFactory daprClientFactory,
: base(serviceScopeFactory, currentTenant, unitOfWorkManager, abpDistributedEventBusOptions, guidGenerator, clock, eventHandlerInvoker) ILocalEventBus localEventBus)
: base(serviceScopeFactory, currentTenant, unitOfWorkManager, abpDistributedEventBusOptions, guidGenerator, clock, eventHandlerInvoker, localEventBus)
{ {
Serializer = serializer; Serializer = serializer;
DaprEventBusOptions = daprEventBusOptions.Value; DaprEventBusOptions = daprEventBusOptions.Value;
@ -141,6 +143,13 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
public override async Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig) public override async Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig)
{ {
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
await PublishToDaprAsync(outgoingEvent.EventName, Serializer.Deserialize(outgoingEvent.EventData, GetEventType(outgoingEvent.EventName))); await PublishToDaprAsync(outgoingEvent.EventName, Serializer.Deserialize(outgoingEvent.EventData, GetEventType(outgoingEvent.EventName)));
} }
@ -150,10 +159,27 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
foreach (var outgoingEvent in outgoingEventArray) foreach (var outgoingEvent in outgoingEventArray)
{ {
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
await PublishToDaprAsync(outgoingEvent.EventName, Serializer.Deserialize(outgoingEvent.EventData, GetEventType(outgoingEvent.EventName))); await PublishToDaprAsync(outgoingEvent.EventName, Serializer.Deserialize(outgoingEvent.EventData, GetEventType(outgoingEvent.EventName)));
} }
} }
public virtual async Task TriggerHandlersAsync(string messageId, Type eventType, object eventData)
{
if (await AddToInboxAsync(messageId, EventNameAttribute.GetNameOrDefault(eventType), eventType, eventData))
{
return;
}
await TriggerHandlersDirectAsync(eventType, eventData);
}
public async override Task ProcessFromInboxAsync(IncomingEventInfo incomingEvent, InboxConfig inboxConfig) public async override Task ProcessFromInboxAsync(IncomingEventInfo incomingEvent, InboxConfig inboxConfig)
{ {
var eventType = EventTypes.GetOrDefault(incomingEvent.EventName); var eventType = EventTypes.GetOrDefault(incomingEvent.EventName);
@ -164,7 +190,7 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType); var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
var exceptions = new List<Exception>(); var exceptions = new List<Exception>();
await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig); await TriggerHandlersFromInboxAsync(eventType, eventData, exceptions, inboxConfig);
if (exceptions.Any()) if (exceptions.Any())
{ {
ThrowOriginalExceptions(eventType, exceptions); ThrowOriginalExceptions(eventType, exceptions);
@ -176,6 +202,12 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
return Serializer.Serialize(eventData); return Serializer.Serialize(eventData);
} }
protected override Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
EventTypes.GetOrAdd(eventName, eventType);
return base.OnAddToOutboxAsync(eventName, eventType, eventData);
}
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType) private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType)
{ {
return HandlerFactories.GetOrAdd( return HandlerFactories.GetOrAdd(
@ -183,7 +215,7 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
type => type =>
{ {
var eventName = EventNameAttribute.GetNameOrDefault(type); var eventName = EventNameAttribute.GetNameOrDefault(type);
EventTypes[eventName] = type; EventTypes.GetOrAdd(eventName, eventType);
return new List<IEventHandlerFactory>(); return new List<IEventHandlerFactory>();
} }
); );

56
framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs

@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.Kafka; using Volo.Abp.Kafka;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
@ -40,7 +41,8 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
IProducerPool producerPool, IProducerPool producerPool,
IGuidGenerator guidGenerator, IGuidGenerator guidGenerator,
IClock clock, IClock clock,
IEventHandlerInvoker eventHandlerInvoker) IEventHandlerInvoker eventHandlerInvoker,
ILocalEventBus localEventBus)
: base( : base(
serviceScopeFactory, serviceScopeFactory,
currentTenant, currentTenant,
@ -48,7 +50,8 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
abpDistributedEventBusOptions, abpDistributedEventBusOptions,
guidGenerator, guidGenerator,
clock, clock,
eventHandlerInvoker) eventHandlerInvoker,
localEventBus)
{ {
AbpKafkaEventBusOptions = abpKafkaEventBusOptions.Value; AbpKafkaEventBusOptions = abpKafkaEventBusOptions.Value;
MessageConsumerFactory = messageConsumerFactory; MessageConsumerFactory = messageConsumerFactory;
@ -80,15 +83,14 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
} }
var messageId = message.GetMessageId(); var messageId = message.GetMessageId();
var eventData = Serializer.Deserialize(message.Value, eventType);
if (await AddToInboxAsync(messageId, eventName, eventType, message.Value)) if (await AddToInboxAsync(messageId, eventName, eventType, eventData))
{ {
return; return;
} }
var eventData = Serializer.Deserialize(message.Value, eventType); await TriggerHandlersDirectAsync(eventType, eventData);
await TriggerHandlersAsync(eventType, eventData);
} }
public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory) public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory)
@ -177,11 +179,18 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
unitOfWork.AddOrReplaceDistributedEvent(eventRecord); unitOfWork.AddOrReplaceDistributedEvent(eventRecord);
} }
public override Task PublishFromOutboxAsync( public override async Task PublishFromOutboxAsync(
OutgoingEventInfo outgoingEvent, OutgoingEventInfo outgoingEvent,
OutboxConfig outboxConfig) OutboxConfig outboxConfig)
{ {
return PublishAsync( await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
await PublishAsync(
AbpKafkaEventBusOptions.TopicName, AbpKafkaEventBusOptions.TopicName,
outgoingEvent.EventName, outgoingEvent.EventName,
outgoingEvent.EventData, outgoingEvent.EventData,
@ -192,19 +201,26 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
); );
} }
public override Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig) public async override Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig)
{ {
var producer = ProducerPool.Get(AbpKafkaEventBusOptions.ConnectionName); var producer = ProducerPool.Get(AbpKafkaEventBusOptions.ConnectionName);
var outgoingEventArray = outgoingEvents.ToArray(); var outgoingEventArray = outgoingEvents.ToArray();
foreach (var outgoingEvent in outgoingEventArray) foreach (var outgoingEvent in outgoingEventArray)
{ {
var messageId = outgoingEvent.Id.ToString("N"); var messageId = outgoingEvent.Id.ToString("N");
var headers = new Headers var headers = new Headers
{ {
{ "messageId", System.Text.Encoding.UTF8.GetBytes(messageId)} { "messageId", System.Text.Encoding.UTF8.GetBytes(messageId)}
}; };
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
producer.Produce( producer.Produce(
AbpKafkaEventBusOptions.TopicName, AbpKafkaEventBusOptions.TopicName,
new Message<string, byte[]> new Message<string, byte[]>
@ -214,8 +230,6 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
Headers = headers Headers = headers
}); });
} }
return Task.CompletedTask;
} }
public async override Task ProcessFromInboxAsync( public async override Task ProcessFromInboxAsync(
@ -230,7 +244,7 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType); var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
var exceptions = new List<Exception>(); var exceptions = new List<Exception>();
await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig); await TriggerHandlersFromInboxAsync(eventType, eventData, exceptions, inboxConfig);
if (exceptions.Any()) if (exceptions.Any())
{ {
ThrowOriginalExceptions(eventType, exceptions); ThrowOriginalExceptions(eventType, exceptions);
@ -251,9 +265,9 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
} }
private Task<DeliveryResult<string, byte[]>> PublishAsync( private Task<DeliveryResult<string, byte[]>> PublishAsync(
string topicName, string topicName,
string eventName, string eventName,
byte[] body, byte[] body,
Headers headers) Headers headers)
{ {
var producer = ProducerPool.Get(AbpKafkaEventBusOptions.ConnectionName); var producer = ProducerPool.Get(AbpKafkaEventBusOptions.ConnectionName);
@ -268,6 +282,12 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
}); });
} }
protected override Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
EventTypes.GetOrAdd(eventName, eventType);
return base.OnAddToOutboxAsync(eventName, eventType, eventData);
}
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType) private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType)
{ {
return HandlerFactories.GetOrAdd( return HandlerFactories.GetOrAdd(
@ -275,7 +295,7 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
type => type =>
{ {
var eventName = EventNameAttribute.GetNameOrDefault(type); var eventName = EventNameAttribute.GetNameOrDefault(type);
EventTypes[eventName] = type; EventTypes.GetOrAdd(eventName, eventType);
return new List<IEventHandlerFactory>(); return new List<IEventHandlerFactory>();
} }
); );

49
framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs

@ -9,6 +9,7 @@ using RabbitMQ.Client;
using RabbitMQ.Client.Events; using RabbitMQ.Client.Events;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.RabbitMQ; using Volo.Abp.RabbitMQ;
@ -47,7 +48,8 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
IUnitOfWorkManager unitOfWorkManager, IUnitOfWorkManager unitOfWorkManager,
IGuidGenerator guidGenerator, IGuidGenerator guidGenerator,
IClock clock, IClock clock,
IEventHandlerInvoker eventHandlerInvoker) IEventHandlerInvoker eventHandlerInvoker,
ILocalEventBus localEventBus)
: base( : base(
serviceScopeFactory, serviceScopeFactory,
currentTenant, currentTenant,
@ -55,7 +57,8 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
distributedEventBusOptions, distributedEventBusOptions,
guidGenerator, guidGenerator,
clock, clock,
eventHandlerInvoker) eventHandlerInvoker,
localEventBus)
{ {
ConnectionPool = connectionPool; ConnectionPool = connectionPool;
Serializer = serializer; Serializer = serializer;
@ -98,16 +101,14 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
return; return;
} }
var eventBytes = ea.Body.ToArray(); var eventData = Serializer.Deserialize(ea.Body.ToArray(), eventType);
if (await AddToInboxAsync(ea.BasicProperties.MessageId, eventName, eventType, eventBytes)) if (await AddToInboxAsync(ea.BasicProperties.MessageId, eventName, eventType, eventData))
{ {
return; return;
} }
var eventData = Serializer.Deserialize(eventBytes, eventType); await TriggerHandlersDirectAsync(eventType, eventData);
await TriggerHandlersAsync(eventType, eventData);
} }
public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory) public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory)
@ -193,11 +194,18 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
unitOfWork.AddOrReplaceDistributedEvent(eventRecord); unitOfWork.AddOrReplaceDistributedEvent(eventRecord);
} }
public override Task PublishFromOutboxAsync( public override async Task PublishFromOutboxAsync(
OutgoingEventInfo outgoingEvent, OutgoingEventInfo outgoingEvent,
OutboxConfig outboxConfig) OutboxConfig outboxConfig)
{ {
return PublishAsync(outgoingEvent.EventName, outgoingEvent.EventData, null, eventId: outgoingEvent.Id); await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
await PublishAsync(outgoingEvent.EventName, outgoingEvent.EventData, null, eventId: outgoingEvent.Id);
} }
public async override Task PublishManyFromOutboxAsync( public async override Task PublishManyFromOutboxAsync(
@ -211,10 +219,17 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
foreach (var outgoingEvent in outgoingEventArray) foreach (var outgoingEvent in outgoingEventArray)
{ {
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
await PublishAsync( await PublishAsync(
channel, channel,
outgoingEvent.EventName, outgoingEvent.EventName,
outgoingEvent.EventData, outgoingEvent.EventData,
properties: null, properties: null,
eventId: outgoingEvent.Id); eventId: outgoingEvent.Id);
} }
@ -235,7 +250,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType); var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
var exceptions = new List<Exception>(); var exceptions = new List<Exception>();
await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig); await TriggerHandlersFromInboxAsync(eventType, eventData, exceptions, inboxConfig);
if (exceptions.Any()) if (exceptions.Any())
{ {
ThrowOriginalExceptions(eventType, exceptions); ThrowOriginalExceptions(eventType, exceptions);
@ -249,7 +264,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
public Task PublishAsync( public Task PublishAsync(
Type eventType, Type eventType,
object eventData, object eventData,
IBasicProperties properties, IBasicProperties properties,
Dictionary<string, object> headersArguments = null) Dictionary<string, object> headersArguments = null)
{ {
@ -343,6 +358,12 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
} }
} }
protected override Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
EventTypes.GetOrAdd(eventName, eventType);
return base.OnAddToOutboxAsync(eventName, eventType, eventData);
}
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType) private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType)
{ {
return HandlerFactories.GetOrAdd( return HandlerFactories.GetOrAdd(
@ -350,7 +371,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe
type => type =>
{ {
var eventName = EventNameAttribute.GetNameOrDefault(type); var eventName = EventNameAttribute.GetNameOrDefault(type);
EventTypes[eventName] = type; EventTypes.GetOrAdd(eventName, eventType);
return new List<IEventHandlerFactory>(); return new List<IEventHandlerFactory>();
} }
); );

41
framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs

@ -11,6 +11,7 @@ using Rebus.Pipeline;
using Rebus.Transport; using Rebus.Transport;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
@ -41,7 +42,8 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
IRebusSerializer serializer, IRebusSerializer serializer,
IGuidGenerator guidGenerator, IGuidGenerator guidGenerator,
IClock clock, IClock clock,
IEventHandlerInvoker eventHandlerInvoker) : IEventHandlerInvoker eventHandlerInvoker,
ILocalEventBus localEventBus) :
base( base(
serviceScopeFactory, serviceScopeFactory,
currentTenant, currentTenant,
@ -49,7 +51,8 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
abpDistributedEventBusOptions, abpDistributedEventBusOptions,
guidGenerator, guidGenerator,
clock, clock,
eventHandlerInvoker) eventHandlerInvoker,
localEventBus)
{ {
Rebus = rebus; Rebus = rebus;
Serializer = serializer; Serializer = serializer;
@ -142,12 +145,12 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
var messageId = MessageContext.Current.TransportMessage.GetMessageId(); var messageId = MessageContext.Current.TransportMessage.GetMessageId();
var eventName = EventNameAttribute.GetNameOrDefault(eventType); var eventName = EventNameAttribute.GetNameOrDefault(eventType);
if (await AddToInboxAsync(messageId, eventName, eventType, MessageContext.Current.TransportMessage.Body)) if (await AddToInboxAsync(messageId, eventName, eventType, eventData))
{ {
return; return;
} }
await TriggerHandlersAsync(eventType, eventData); await TriggerHandlersDirectAsync(eventType, eventData);
} }
protected async override Task PublishToEventBusAsync(Type eventType, object eventData) protected async override Task PublishToEventBusAsync(Type eventType, object eventData)
@ -181,6 +184,12 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
unitOfWork.AddOrReplaceDistributedEvent(eventRecord); unitOfWork.AddOrReplaceDistributedEvent(eventRecord);
} }
protected override Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
EventTypes.GetOrAdd(eventName, eventType);
return base.OnAddToOutboxAsync(eventName, eventType, eventData);
}
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType) private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType)
{ {
return HandlerFactories.GetOrAdd( return HandlerFactories.GetOrAdd(
@ -188,7 +197,7 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
type => type =>
{ {
var eventName = EventNameAttribute.GetNameOrDefault(type); var eventName = EventNameAttribute.GetNameOrDefault(type);
EventTypes[eventName] = type; EventTypes.GetOrAdd(eventName, eventType);
return new List<IEventHandlerFactory>(); return new List<IEventHandlerFactory>();
} }
); );
@ -225,14 +234,21 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
return false; return false;
} }
public override Task PublishFromOutboxAsync( public override async Task PublishFromOutboxAsync(
OutgoingEventInfo outgoingEvent, OutgoingEventInfo outgoingEvent,
OutboxConfig outboxConfig) OutboxConfig outboxConfig)
{ {
var eventType = EventTypes.GetOrDefault(outgoingEvent.EventName); var eventType = EventTypes.GetOrDefault(outgoingEvent.EventName);
var eventData = Serializer.Deserialize(outgoingEvent.EventData, eventType); var eventData = Serializer.Deserialize(outgoingEvent.EventData, eventType);
return PublishAsync(eventType, eventData, eventId: outgoingEvent.Id); await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
await PublishAsync(eventType, eventData, eventId: outgoingEvent.Id);
} }
public async override Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig) public async override Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig)
@ -243,9 +259,16 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
{ {
foreach (var outgoingEvent in outgoingEventArray) foreach (var outgoingEvent in outgoingEventArray)
{ {
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
await PublishFromOutboxAsync(outgoingEvent, outboxConfig); await PublishFromOutboxAsync(outgoingEvent, outboxConfig);
} }
await scope.CompleteAsync(); await scope.CompleteAsync();
} }
} }
@ -262,7 +285,7 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType); var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
var exceptions = new List<Exception>(); var exceptions = new List<Exception>();
await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig); await TriggerHandlersFromInboxAsync(eventType, eventData, exceptions, inboxConfig);
if (exceptions.Any()) if (exceptions.Any())
{ {
ThrowOriginalExceptions(eventType, exceptions); ThrowOriginalExceptions(eventType, exceptions);

93
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Timing; using Volo.Abp.Timing;
@ -16,6 +17,7 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
protected IGuidGenerator GuidGenerator { get; } protected IGuidGenerator GuidGenerator { get; }
protected IClock Clock { get; } protected IClock Clock { get; }
protected AbpDistributedEventBusOptions AbpDistributedEventBusOptions { get; } protected AbpDistributedEventBusOptions AbpDistributedEventBusOptions { get; }
protected ILocalEventBus LocalEventBus { get; }
protected DistributedEventBusBase( protected DistributedEventBusBase(
IServiceScopeFactory serviceScopeFactory, IServiceScopeFactory serviceScopeFactory,
@ -24,8 +26,8 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
IOptions<AbpDistributedEventBusOptions> abpDistributedEventBusOptions, IOptions<AbpDistributedEventBusOptions> abpDistributedEventBusOptions,
IGuidGenerator guidGenerator, IGuidGenerator guidGenerator,
IClock clock, IClock clock,
IEventHandlerInvoker eventHandlerInvoker IEventHandlerInvoker eventHandlerInvoker,
) : base( ILocalEventBus localEventBus) : base(
serviceScopeFactory, serviceScopeFactory,
currentTenant, currentTenant,
unitOfWorkManager, unitOfWorkManager,
@ -34,6 +36,7 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
GuidGenerator = guidGenerator; GuidGenerator = guidGenerator;
Clock = clock; Clock = clock;
AbpDistributedEventBusOptions = abpDistributedEventBusOptions.Value; AbpDistributedEventBusOptions = abpDistributedEventBusOptions.Value;
LocalEventBus = localEventBus;
} }
public IDisposable Subscribe<TEvent>(IDistributedEventHandler<TEvent> handler) where TEvent : class public IDisposable Subscribe<TEvent>(IDistributedEventHandler<TEvent> handler) where TEvent : class
@ -78,6 +81,13 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
} }
} }
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Direct,
EventName = EventNameAttribute.GetNameOrDefault(eventType),
EventData = eventData
});
await PublishToEventBusAsync(eventType, eventData); await PublishToEventBusAsync(eventType, eventData);
} }
@ -95,7 +105,7 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
IncomingEventInfo incomingEvent, IncomingEventInfo incomingEvent,
InboxConfig inboxConfig); InboxConfig inboxConfig);
private async Task<bool> AddToOutboxAsync(Type eventType, object eventData) protected virtual async Task<bool> AddToOutboxAsync(Type eventType, object eventData)
{ {
var unitOfWork = UnitOfWorkManager.Current; var unitOfWork = UnitOfWorkManager.Current;
if (unitOfWork == null) if (unitOfWork == null)
@ -107,9 +117,18 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
{ {
if (outboxConfig.Selector == null || outboxConfig.Selector(eventType)) if (outboxConfig.Selector == null || outboxConfig.Selector(eventType))
{ {
var eventOutbox = var eventOutbox = (IEventOutbox)unitOfWork.ServiceProvider.GetRequiredService(outboxConfig.ImplementationType);
(IEventOutbox)unitOfWork.ServiceProvider.GetRequiredService(outboxConfig.ImplementationType);
var eventName = EventNameAttribute.GetNameOrDefault(eventType); var eventName = EventNameAttribute.GetNameOrDefault(eventType);
await OnAddToOutboxAsync(eventName, eventType, eventData);
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Direct,
EventName = eventName,
EventData = eventData
});
await eventOutbox.EnqueueAsync( await eventOutbox.EnqueueAsync(
new OutgoingEventInfo( new OutgoingEventInfo(
GuidGenerator.Create(), GuidGenerator.Create(),
@ -125,11 +144,16 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
return false; return false;
} }
protected virtual Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
return Task.CompletedTask;
}
protected async Task<bool> AddToInboxAsync( protected async Task<bool> AddToInboxAsync(
string messageId, string messageId,
string eventName, string eventName,
Type eventType, Type eventType,
byte[] eventBytes) object eventData)
{ {
if (AbpDistributedEventBusOptions.Inboxes.Count <= 0) if (AbpDistributedEventBusOptions.Inboxes.Count <= 0)
{ {
@ -153,12 +177,19 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
} }
} }
await TriggerDistributedEventReceivedAsync(new DistributedEventReceived
{
Source = DistributedEventSource.Direct,
EventName = EventNameAttribute.GetNameOrDefault(eventType),
EventData = eventData
});
await eventInbox.EnqueueAsync( await eventInbox.EnqueueAsync(
new IncomingEventInfo( new IncomingEventInfo(
GuidGenerator.Create(), GuidGenerator.Create(),
messageId, messageId,
eventName, eventName,
eventBytes, Serialize(eventData),
Clock.Now Clock.Now
) )
); );
@ -170,4 +201,52 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
} }
protected abstract byte[] Serialize(object eventData); protected abstract byte[] Serialize(object eventData);
protected virtual async Task TriggerHandlersDirectAsync(Type eventType, object eventData)
{
await TriggerDistributedEventReceivedAsync(new DistributedEventReceived
{
Source = DistributedEventSource.Direct,
EventName = EventNameAttribute.GetNameOrDefault(eventType),
EventData = eventData
});
await TriggerHandlersAsync(eventType, eventData);
}
protected virtual async Task TriggerHandlersFromInboxAsync(Type eventType, object eventData, List<Exception> exceptions, InboxConfig inboxConfig = null)
{
await TriggerDistributedEventReceivedAsync(new DistributedEventReceived
{
Source = DistributedEventSource.Inbox,
EventName = EventNameAttribute.GetNameOrDefault(eventType),
EventData = eventData
});
await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig);
}
public virtual async Task TriggerDistributedEventSentAsync(DistributedEventSent distributedEvent)
{
try
{
await LocalEventBus.PublishAsync(distributedEvent);
}
catch (Exception _)
{
// ignored
}
}
public virtual async Task TriggerDistributedEventReceivedAsync(DistributedEventReceived distributedEvent)
{
try
{
await LocalEventBus.PublishAsync(distributedEvent);
}
catch (Exception _)
{
// ignored
}
}
} }

28
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus.cs

@ -28,6 +28,30 @@ public class LocalDistributedEventBus : IDistributedEventBus, ISingletonDependen
ServiceScopeFactory = serviceScopeFactory; ServiceScopeFactory = serviceScopeFactory;
AbpDistributedEventBusOptions = distributedEventBusOptions.Value; AbpDistributedEventBusOptions = distributedEventBusOptions.Value;
Subscribe(distributedEventBusOptions.Value.Handlers); Subscribe(distributedEventBusOptions.Value.Handlers);
// For unit testing
if (localEventBus is LocalEventBus eventBus)
{
eventBus.OnEventHandleInvoking = async (eventType, eventData) =>
{
await localEventBus.PublishAsync(new DistributedEventReceived()
{
Source = DistributedEventSource.Direct,
EventName = EventNameAttribute.GetNameOrDefault(eventType),
EventData = eventData
}, onUnitOfWorkComplete: false);
};
eventBus.OnPublishing = async (eventType, eventData) =>
{
await localEventBus.PublishAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Direct,
EventName = EventNameAttribute.GetNameOrDefault(eventType),
EventData = eventData
}, onUnitOfWorkComplete: false);
};
}
} }
public virtual void Subscribe(ITypeList<IEventHandler> handlers) public virtual void Subscribe(ITypeList<IEventHandler> handlers)
@ -132,7 +156,7 @@ public class LocalDistributedEventBus : IDistributedEventBus, ISingletonDependen
{ {
return _localEventBus.PublishAsync(eventType, eventData, onUnitOfWorkComplete); return _localEventBus.PublishAsync(eventType, eventData, onUnitOfWorkComplete);
} }
public Task PublishAsync<TEvent>(TEvent eventData, bool onUnitOfWorkComplete = true, bool useOutbox = true) where TEvent : class public Task PublishAsync<TEvent>(TEvent eventData, bool onUnitOfWorkComplete = true, bool useOutbox = true) where TEvent : class
{ {
return _localEventBus.PublishAsync(eventData, onUnitOfWorkComplete); return _localEventBus.PublishAsync(eventData, onUnitOfWorkComplete);
@ -142,4 +166,4 @@ public class LocalDistributedEventBus : IDistributedEventBus, ISingletonDependen
{ {
return _localEventBus.PublishAsync(eventType, eventData, onUnitOfWorkComplete); return _localEventBus.PublishAsync(eventType, eventData, onUnitOfWorkComplete);
} }
} }

8
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs

@ -9,7 +9,6 @@ using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Collections; using Volo.Abp.Collections;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace Volo.Abp.EventBus; namespace Volo.Abp.EventBus;
@ -214,7 +213,7 @@ public abstract class EventBusBase : IEventBus
using (CurrentTenant.Change(GetEventDataTenantId(eventData))) using (CurrentTenant.Change(GetEventDataTenantId(eventData)))
{ {
await EventHandlerInvoker.InvokeAsync(eventHandlerWrapper.EventHandler, eventData, eventType); await InvokeEventHandlerAsync(eventHandlerWrapper.EventHandler, eventData, eventType);
} }
} }
catch (TargetInvocationException ex) catch (TargetInvocationException ex)
@ -228,6 +227,11 @@ public abstract class EventBusBase : IEventBus
} }
} }
protected virtual Task InvokeEventHandlerAsync(IEventHandler eventHandler, object eventData, Type eventType)
{
return EventHandlerInvoker.InvokeAsync(eventHandler, eventData, eventType);
}
protected virtual Guid? GetEventDataTenantId(object eventData) protected virtual Guid? GetEventDataTenantId(object eventData)
{ {
return eventData switch return eventData switch

42
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs

@ -8,6 +8,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
using Volo.Abp.Uow; using Volo.Abp.Uow;
@ -168,4 +169,45 @@ public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency
return false; return false;
} }
// Internal for unit testing
internal Func<Type, object, Task> OnEventHandleInvoking { get; set; }
// Internal for unit testing
protected async override Task InvokeEventHandlerAsync(IEventHandler eventHandler, object eventData, Type eventType)
{
if (OnEventHandleInvoking != null && eventType != typeof(DistributedEventSent) && eventType != typeof(DistributedEventReceived))
{
await OnEventHandleInvoking(eventType, eventData);
}
await base.InvokeEventHandlerAsync(eventHandler, eventData, eventType);
}
// Internal for unit testing
internal Func<Type, object, Task> OnPublishing { get; set; }
// For unit testing
public async override Task PublishAsync(
Type eventType,
object eventData,
bool onUnitOfWorkComplete = true)
{
if (onUnitOfWorkComplete && UnitOfWorkManager.Current != null)
{
AddToUnitOfWork(
UnitOfWorkManager.Current,
new UnitOfWorkEventRecord(eventType, eventData, EventOrderGenerator.GetNext())
);
return;
}
// For unit testing
if (OnPublishing != null && eventType != typeof(DistributedEventSent) && eventType != typeof(DistributedEventReceived))
{
await OnPublishing(eventType, eventData);
}
await PublishToEventBusAsync(eventType, eventData);
}
} }

2
framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbDateTimeSerializer.cs

@ -34,7 +34,7 @@ public class AbpMongoDbDateTimeSerializer : DateTimeSerializer
return (dateTime - BsonConstants.UnixEpoch).Ticks / 10000L; return (dateTime - BsonConstants.UnixEpoch).Ticks / 10000L;
} }
// For unit testing. // For unit testing
internal void SetDateTimeKind(DateTimeKind dateTimeKind) internal void SetDateTimeKind(DateTimeKind dateTimeKind)
{ {
DateTimeKind = dateTimeKind; DateTimeKind = dateTimeKind;

22
framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/DistributedEventHandles.cs

@ -0,0 +1,22 @@
using System.Threading.Tasks;
namespace Volo.Abp.EventBus.Distributed;
public class DistributedEventHandles : ILocalEventHandler<DistributedEventSent>, ILocalEventHandler<DistributedEventReceived>
{
public static int SentCount { get; set; }
public static int ReceivedCount { get; set; }
public Task HandleEventAsync(DistributedEventSent eventData)
{
SentCount++;
return Task.CompletedTask;
}
public Task HandleEventAsync(DistributedEventReceived eventData)
{
ReceivedCount++;
return Task.CompletedTask;
}
}

44
framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs

@ -1,7 +1,8 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.MultiTenancy; using Volo.Abp.EventBus.Local;
using Volo.Abp.Uow;
using Xunit; using Xunit;
namespace Volo.Abp.EventBus.Distributed; namespace Volo.Abp.EventBus.Distributed;
@ -49,7 +50,7 @@ public class LocalDistributedEventBus_Test : LocalDistributedEventBusTestBase
public async Task Should_Get_TenantId_From_EventEto_Extra_Property() public async Task Should_Get_TenantId_From_EventEto_Extra_Property()
{ {
var tenantId = Guid.NewGuid(); var tenantId = Guid.NewGuid();
DistributedEventBus.Subscribe<MySimpleEto>(GetRequiredService<MySimpleDistributedSingleInstanceEventHandler>()); DistributedEventBus.Subscribe<MySimpleEto>(GetRequiredService<MySimpleDistributedSingleInstanceEventHandler>());
await DistributedEventBus.PublishAsync(new MySimpleEto await DistributedEventBus.PublishAsync(new MySimpleEto
@ -59,7 +60,44 @@ public class LocalDistributedEventBus_Test : LocalDistributedEventBusTestBase
{"TenantId", tenantId.ToString()} {"TenantId", tenantId.ToString()}
} }
}); });
Assert.Equal(tenantId, MySimpleDistributedSingleInstanceEventHandler.TenantId); Assert.Equal(tenantId, MySimpleDistributedSingleInstanceEventHandler.TenantId);
} }
[Fact]
public async Task DistributedEventSentAndReceived_Test()
{
GetRequiredService<ILocalEventBus>().Subscribe<DistributedEventSent, DistributedEventHandles>();
GetRequiredService<ILocalEventBus>().Subscribe<DistributedEventReceived, DistributedEventHandles>();
DistributedEventBus.Subscribe<MyEventDate, MyEventHandle>();
using (var uow = GetRequiredService<IUnitOfWorkManager>().Begin())
{
await DistributedEventBus.PublishAsync(new MyEventDate(), onUnitOfWorkComplete: false);
Assert.Equal(1, DistributedEventHandles.SentCount);
Assert.Equal(1, DistributedEventHandles.ReceivedCount);
await DistributedEventBus.PublishAsync(new MyEventDate(), onUnitOfWorkComplete: true);
await uow.CompleteAsync();
Assert.Equal(2, DistributedEventHandles.SentCount);
Assert.Equal(2, DistributedEventHandles.ReceivedCount);
}
}
class MyEventDate
{
}
class MyEventHandle : IDistributedEventHandler<MyEventDate>
{
public Task HandleEventAsync(MyEventDate eventData)
{
return Task.CompletedTask;
}
}
} }

Loading…
Cancel
Save