mirror of https://github.com/abpframework/abp.git
22 changed files with 395 additions and 46 deletions
@ -1,29 +1,59 @@ |
|||||
using System.Threading.Tasks; |
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
using Volo.Abp.EventBus.Distributed; |
using Volo.Abp.EventBus.Distributed; |
||||
using Volo.Abp.Guids; |
using Volo.Abp.Uow; |
||||
|
|
||||
namespace Volo.Abp.EntityFrameworkCore.DistributedEvents |
namespace Volo.Abp.EntityFrameworkCore.DistributedEvents |
||||
{ |
{ |
||||
public class DbContextEventOutbox<TDbContext> : IEventOutbox |
public class DbContextEventOutbox<TDbContext> : IDbContextEventOutbox<TDbContext> |
||||
where TDbContext : IHasEventOutbox |
where TDbContext : IHasEventOutbox |
||||
{ |
{ |
||||
protected IDbContextProvider<TDbContext> DbContextProvider { get; } |
protected IDbContextProvider<TDbContext> DbContextProvider { get; } |
||||
protected IGuidGenerator GuidGenerator { get; } |
|
||||
|
|
||||
public DbContextEventOutbox( |
public DbContextEventOutbox( |
||||
IDbContextProvider<TDbContext> dbContextProvider, |
IDbContextProvider<TDbContext> dbContextProvider) |
||||
IGuidGenerator guidGenerator) |
|
||||
{ |
{ |
||||
DbContextProvider = dbContextProvider; |
DbContextProvider = dbContextProvider; |
||||
GuidGenerator = guidGenerator; |
|
||||
} |
} |
||||
|
|
||||
public async Task EnqueueAsync(string eventName, byte[] eventData) |
[UnitOfWork] |
||||
|
public virtual async Task EnqueueAsync(OutgoingEventInfo outgoingEvent) |
||||
{ |
{ |
||||
var dbContext = (IHasEventOutbox) await DbContextProvider.GetDbContextAsync(); |
var dbContext = (IHasEventOutbox) await DbContextProvider.GetDbContextAsync(); |
||||
dbContext.OutgoingEventRecords.Add( |
dbContext.OutgoingEventRecords.Add( |
||||
new OutgoingEventRecord(GuidGenerator.Create(), eventName, eventData) |
new OutgoingEventRecord(outgoingEvent) |
||||
); |
); |
||||
} |
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
public virtual async Task<List<OutgoingEventInfo>> GetWaitingEventsAsync(int maxCount) |
||||
|
{ |
||||
|
var dbContext = (IHasEventOutbox) await DbContextProvider.GetDbContextAsync(); |
||||
|
|
||||
|
var outgoingEventRecords = await dbContext |
||||
|
.OutgoingEventRecords |
||||
|
.AsNoTracking() |
||||
|
.OrderBy(x => x.CreationTime) |
||||
|
.Take(maxCount) |
||||
|
.ToListAsync(); |
||||
|
|
||||
|
return outgoingEventRecords |
||||
|
.Select(x => x.ToOutgoingEventInfo()) |
||||
|
.ToList(); |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
public virtual async Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
var dbContext = (IHasEventOutbox) await DbContextProvider.GetDbContextAsync(); |
||||
|
var outgoingEvent = await dbContext.OutgoingEventRecords.FindAsync(id); |
||||
|
if (outgoingEvent != null) |
||||
|
{ |
||||
|
dbContext.Remove(outgoingEvent); |
||||
|
} |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
|
||||
|
namespace Volo.Abp.EntityFrameworkCore.DistributedEvents |
||||
|
{ |
||||
|
public interface IDbContextEventOutbox<TDbContext> : IEventOutbox |
||||
|
where TDbContext : IHasEventOutbox |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
|
||||
|
namespace Volo.Abp.EventBus.Boxes |
||||
|
{ |
||||
|
public static class AbpDistributedEventBusExtensions |
||||
|
{ |
||||
|
public static IRawEventPublisher AsRawEventPublisher(this IDistributedEventBus eventBus) |
||||
|
{ |
||||
|
var rawPublisher = eventBus as IRawEventPublisher; |
||||
|
if (rawPublisher == null) |
||||
|
{ |
||||
|
throw new AbpException($"Given type ({eventBus.GetType().AssemblyQualifiedName}) should implement {nameof(IRawEventPublisher)}!"); |
||||
|
} |
||||
|
|
||||
|
return rawPublisher; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,12 +1,17 @@ |
|||||
using Volo.Abp.Modularity; |
using Volo.Abp.BackgroundWorkers; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace Volo.Abp.EventBus.Boxes |
namespace Volo.Abp.EventBus.Boxes |
||||
{ |
{ |
||||
[DependsOn( |
[DependsOn( |
||||
typeof(AbpEventBusModule) |
typeof(AbpEventBusModule), |
||||
|
typeof(AbpBackgroundWorkersModule) |
||||
)] |
)] |
||||
public class AbpEventBusBoxesModule : AbpModule |
public class AbpEventBusBoxesModule : AbpModule |
||||
{ |
{ |
||||
|
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
context.AddBackgroundWorker<OutboxSenderManager>(); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
|
||||
|
namespace Volo.Abp.EventBus.Boxes |
||||
|
{ |
||||
|
public interface IOutboxSender |
||||
|
{ |
||||
|
Task StartAsync(OutboxConfig outboxConfig); |
||||
|
Task StopAsync(); |
||||
|
} |
||||
|
} |
||||
@ -1,7 +1,78 @@ |
|||||
namespace Volo.Abp.EventBus.Boxes |
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
using Volo.Abp.Threading; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace Volo.Abp.EventBus.Boxes |
||||
{ |
{ |
||||
public class OutboxSender |
//TODO: use distributed lock!
|
||||
|
public class OutboxSender : IOutboxSender, ITransientDependency |
||||
{ |
{ |
||||
//Background worker & distributed lock
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
protected AbpTimer Timer { get; } |
||||
|
protected IDistributedEventBus DistributedEventBus { get; } |
||||
|
protected IEventOutbox Outbox { get; private set; } |
||||
|
public ILogger<OutboxSender> Logger { get; set; } |
||||
|
|
||||
|
public OutboxSender( |
||||
|
IServiceProvider serviceProvider, |
||||
|
AbpTimer timer, |
||||
|
IDistributedEventBus distributedEventBus) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
Timer = timer; |
||||
|
DistributedEventBus = distributedEventBus; |
||||
|
Timer.Period = 2000; //TODO: Config?
|
||||
|
Timer.Elapsed += TimerOnElapsed; |
||||
|
Logger = NullLogger<OutboxSender>.Instance; |
||||
|
} |
||||
|
|
||||
|
public virtual Task StartAsync(OutboxConfig outboxConfig) |
||||
|
{ |
||||
|
Outbox = (IEventOutbox)ServiceProvider.GetRequiredService(outboxConfig.ImplementationType); |
||||
|
Timer.Start(); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
public virtual Task StopAsync() |
||||
|
{ |
||||
|
Timer.Stop(); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
private void TimerOnElapsed(object sender, EventArgs e) |
||||
|
{ |
||||
|
AsyncHelper.RunSync(RunAsync); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task RunAsync() |
||||
|
{ |
||||
|
while (true) |
||||
|
{ |
||||
|
var waitingEvents = await Outbox.GetWaitingEventsAsync(100); |
||||
|
if (waitingEvents.Count <= 0) |
||||
|
{ |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
Logger.LogInformation($"Found {waitingEvents.Count} events in the outbox."); |
||||
|
|
||||
|
foreach (var waitingEvent in waitingEvents) |
||||
|
{ |
||||
|
await DistributedEventBus |
||||
|
.AsRawEventPublisher() |
||||
|
.PublishRawAsync(waitingEvent.Id, waitingEvent.EventName, waitingEvent.EventData); |
||||
|
|
||||
|
await Outbox.DeleteAsync(waitingEvent.Id); |
||||
|
|
||||
|
Logger.LogInformation($"Sent the event to the message broker with id = {waitingEvent.Id:N}"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.BackgroundWorkers; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
|
||||
|
namespace Volo.Abp.EventBus.Boxes |
||||
|
{ |
||||
|
public class OutboxSenderManager : IBackgroundWorker |
||||
|
{ |
||||
|
protected AbpDistributedEventBusOptions Options { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
protected List<IOutboxSender> Senders { get; } |
||||
|
|
||||
|
public OutboxSenderManager( |
||||
|
IOptions<AbpDistributedEventBusOptions> options, |
||||
|
IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
Options = options.Value; |
||||
|
Senders = new List<IOutboxSender>(); |
||||
|
} |
||||
|
|
||||
|
public async Task StartAsync(CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
foreach (var outboxConfig in Options.Outboxes.Values) |
||||
|
{ |
||||
|
if (outboxConfig.IsSendingEnabled) |
||||
|
{ |
||||
|
var sender = ServiceProvider.GetRequiredService<IOutboxSender>(); |
||||
|
await sender.StartAsync(outboxConfig); |
||||
|
Senders.Add(sender); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public async Task StopAsync(CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
foreach (var sender in Senders) |
||||
|
{ |
||||
|
await sender.StopAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,15 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace Volo.Abp.EventBus.Distributed |
namespace Volo.Abp.EventBus.Distributed |
||||
{ |
{ |
||||
public interface IEventOutbox |
public interface IEventOutbox |
||||
{ |
{ |
||||
Task EnqueueAsync(string eventName, byte[] eventData); |
Task EnqueueAsync(OutgoingEventInfo outgoingEvent); |
||||
|
|
||||
|
Task<List<OutgoingEventInfo>> GetWaitingEventsAsync(int maxCount); |
||||
|
|
||||
|
Task DeleteAsync(Guid id); |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.EventBus.Distributed |
||||
|
{ |
||||
|
public interface IRawEventPublisher |
||||
|
{ |
||||
|
Task PublishRawAsync( |
||||
|
Guid eventId, |
||||
|
string eventName, |
||||
|
byte[] eventData); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace Volo.Abp.EventBus.Distributed |
||||
|
{ |
||||
|
public class OutgoingEventInfo : IHasExtraProperties |
||||
|
{ |
||||
|
public static int MaxEventNameLength { get; set; } = 256; |
||||
|
|
||||
|
public ExtraPropertyDictionary ExtraProperties { get; protected set; } |
||||
|
|
||||
|
public Guid Id { get; } |
||||
|
|
||||
|
public string EventName { get; } |
||||
|
|
||||
|
public byte[] EventData { get; } |
||||
|
|
||||
|
public DateTime CreationTime { get; } |
||||
|
|
||||
|
protected OutgoingEventInfo() |
||||
|
{ |
||||
|
ExtraProperties = new ExtraPropertyDictionary(); |
||||
|
this.SetDefaultsForExtraProperties(); |
||||
|
} |
||||
|
|
||||
|
public OutgoingEventInfo( |
||||
|
Guid id, |
||||
|
string eventName, |
||||
|
byte[] eventData, |
||||
|
DateTime creationTime) |
||||
|
{ |
||||
|
Id = id; |
||||
|
EventName = eventName; |
||||
|
EventData = eventData; |
||||
|
CreationTime = creationTime; |
||||
|
ExtraProperties = new ExtraPropertyDictionary(); |
||||
|
this.SetDefaultsForExtraProperties(); |
||||
|
} |
||||
|
}} |
||||
Loading…
Reference in new issue