mirror of
https://github.com/bitwarden/server
synced 2025-12-21 18:53:41 +00:00
[PM-17562] Refactor event integration methods / declarations in ServiceCollectionExtensions (#6118)
* [PM-17562] Refactor event integration methods / declarations in ServiceCollectionExtensions * Refactored ServiceCollectionExtensions to use TryAdd and still launch unique listeneer services * Updated unit tests to match new generic format for Listeners * Fix method spacing * Update README to reflect new integration setup in ServiceCollectionExtensions * Move interfaces to I prefix; fix typo in subscription * Fix reference to IIntegrationListenerConfiguration
This commit is contained in:
@@ -2,27 +2,26 @@
|
||||
|
||||
using System.Text;
|
||||
using Azure.Messaging.ServiceBus;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
public class AzureServiceBusEventListenerService : EventLoggingListenerService
|
||||
public class AzureServiceBusEventListenerService<TConfiguration> : EventLoggingListenerService
|
||||
where TConfiguration : IEventListenerConfiguration
|
||||
{
|
||||
private readonly ServiceBusProcessor _processor;
|
||||
|
||||
public AzureServiceBusEventListenerService(
|
||||
TConfiguration configuration,
|
||||
IEventMessageHandler handler,
|
||||
IAzureServiceBusService serviceBusService,
|
||||
string subscriptionName,
|
||||
GlobalSettings globalSettings,
|
||||
ILogger<AzureServiceBusEventListenerService> logger) : base(handler, logger)
|
||||
ILogger<AzureServiceBusEventListenerService<TConfiguration>> logger) : base(handler, logger)
|
||||
{
|
||||
_processor = serviceBusService.CreateProcessor(
|
||||
globalSettings.EventLogging.AzureServiceBus.EventTopicName,
|
||||
subscriptionName,
|
||||
topicName: configuration.EventTopicName,
|
||||
subscriptionName: configuration.EventSubscriptionName,
|
||||
new ServiceBusProcessorOptions());
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
|
||||
@@ -1,32 +1,36 @@
|
||||
#nullable enable
|
||||
|
||||
using Azure.Messaging.ServiceBus;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
public class AzureServiceBusIntegrationListenerService : BackgroundService
|
||||
public class AzureServiceBusIntegrationListenerService<TConfiguration> : BackgroundService
|
||||
where TConfiguration : IIntegrationListenerConfiguration
|
||||
{
|
||||
private readonly int _maxRetries;
|
||||
private readonly IAzureServiceBusService _serviceBusService;
|
||||
private readonly IIntegrationHandler _handler;
|
||||
private readonly ServiceBusProcessor _processor;
|
||||
private readonly ILogger<AzureServiceBusIntegrationListenerService> _logger;
|
||||
private readonly ILogger<AzureServiceBusIntegrationListenerService<TConfiguration>> _logger;
|
||||
|
||||
public AzureServiceBusIntegrationListenerService(IIntegrationHandler handler,
|
||||
string topicName,
|
||||
string subscriptionName,
|
||||
int maxRetries,
|
||||
public AzureServiceBusIntegrationListenerService(
|
||||
TConfiguration configuration,
|
||||
IIntegrationHandler handler,
|
||||
IAzureServiceBusService serviceBusService,
|
||||
ILogger<AzureServiceBusIntegrationListenerService> logger)
|
||||
ILogger<AzureServiceBusIntegrationListenerService<TConfiguration>> logger)
|
||||
{
|
||||
_handler = handler;
|
||||
_logger = logger;
|
||||
_maxRetries = maxRetries;
|
||||
_maxRetries = configuration.MaxRetries;
|
||||
_serviceBusService = serviceBusService;
|
||||
|
||||
_processor = _serviceBusService.CreateProcessor(topicName, subscriptionName, new ServiceBusProcessorOptions());
|
||||
_processor = _serviceBusService.CreateProcessor(
|
||||
topicName: configuration.IntegrationTopicName,
|
||||
subscriptionName: configuration.IntegrationSubscriptionName,
|
||||
options: new ServiceBusProcessorOptions());
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
|
||||
@@ -399,35 +399,44 @@ These names added here are what must match the values provided in the secrets or
|
||||
in Global Settings. This must be in place (and the local ASB emulator restarted) before you can use any
|
||||
code locally that accesses ASB resources.
|
||||
|
||||
## ListenerConfiguration
|
||||
|
||||
New integrations will need their own subclass of `ListenerConfiguration` which also conforms to
|
||||
`IIntegrationListenerConfiguration`. This class provides a way of accessing the previously configured
|
||||
RabbitMQ queues and ASB subscriptions by referring to the values created in `GlobalSettings`. This new
|
||||
listener configuration will be used to type the listener and provide the means to access the necessary
|
||||
configurations for the integration.
|
||||
|
||||
## ServiceCollectionExtensions
|
||||
|
||||
In our `ServiceCollectionExtensions`, we pull all the above pieces together to start listeners on each message
|
||||
tier with handlers to process the integration. There are a number of helper methods in here to make this simple
|
||||
to add a new integration - one call per platform.
|
||||
tier with handlers to process the integration.
|
||||
|
||||
Also note that if an integration needs a custom singleton / service defined, the add listeners method is a
|
||||
good place to set that up. For instance, `SlackIntegrationHandler` needs a `SlackService`, so the singleton
|
||||
declaration is right above the add integration method for slack. Same thing for webhooks when it comes to
|
||||
defining a custom HttpClient by name.
|
||||
The core method for all event integration setup is `AddEventIntegrationServices`. This method is called by
|
||||
both of the add listeners methods, which ensures that we have one common place to set up cross-messaging-platform
|
||||
dependencies and integrations. For instance, `SlackIntegrationHandler` needs a `SlackService`, so
|
||||
`AddEventIntegrationServices` has a call to `AddSlackService`. Same thing for webhooks when it
|
||||
comes to defining a custom HttpClient by name.
|
||||
|
||||
1. In `AddEventIntegrationServices` create the listener configuration:
|
||||
|
||||
1. In `AddRabbitMqListeners` add the integration:
|
||||
``` csharp
|
||||
services.AddRabbitMqIntegration<ExampleIntegrationConfigurationDetails, ExampleIntegrationHandler>(
|
||||
globalSettings.EventLogging.RabbitMq.ExampleEventsQueueName,
|
||||
globalSettings.EventLogging.RabbitMq.ExampleIntegrationQueueName,
|
||||
globalSettings.EventLogging.RabbitMq.ExampleIntegrationRetryQueueName,
|
||||
globalSettings.EventLogging.RabbitMq.MaxRetries,
|
||||
IntegrationType.Example);
|
||||
var exampleConfiguration = new ExampleListenerConfiguration(globalSettings);
|
||||
```
|
||||
|
||||
2. In `AddAzureServiceBusListeners` add the integration:
|
||||
2. Add the integration to both the RabbitMQ and ASB specific declarations:
|
||||
|
||||
``` csharp
|
||||
services.AddAzureServiceBusIntegration<ExampleIntegrationConfigurationDetails, ExampleIntegrationHandler>(
|
||||
eventSubscriptionName: globalSettings.EventLogging.AzureServiceBus.ExampleEventSubscriptionName,
|
||||
integrationSubscriptionName: globalSettings.EventLogging.AzureServiceBus.ExampleIntegrationSubscriptionName,
|
||||
integrationType: IntegrationType.Example,
|
||||
globalSettings: globalSettings);
|
||||
services.AddRabbitMqIntegration<ExampleIntegrationConfigurationDetails, ExampleListenerConfiguration>(exampleConfiguration);
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
``` csharp
|
||||
services.AddAzureServiceBusIntegration<ExampleIntegrationConfigurationDetails, ExampleListenerConfiguration>(exampleConfiguration);
|
||||
```
|
||||
|
||||
|
||||
# Deploying a new integration
|
||||
|
||||
## RabbitMQ
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Text;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using RabbitMQ.Client;
|
||||
using RabbitMQ.Client.Events;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
public class RabbitMqEventListenerService : EventLoggingListenerService
|
||||
public class RabbitMqEventListenerService<TConfiguration> : EventLoggingListenerService
|
||||
where TConfiguration : IEventListenerConfiguration
|
||||
{
|
||||
private readonly Lazy<Task<IChannel>> _lazyChannel;
|
||||
private readonly string _queueName;
|
||||
@@ -15,12 +17,11 @@ public class RabbitMqEventListenerService : EventLoggingListenerService
|
||||
|
||||
public RabbitMqEventListenerService(
|
||||
IEventMessageHandler handler,
|
||||
string queueName,
|
||||
TConfiguration configuration,
|
||||
IRabbitMqService rabbitMqService,
|
||||
ILogger<RabbitMqEventListenerService> logger) : base(handler, logger)
|
||||
ILogger<RabbitMqEventListenerService<TConfiguration>> logger) : base(handler, logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_queueName = queueName;
|
||||
_queueName = configuration.EventQueueName;
|
||||
_rabbitMqService = rabbitMqService;
|
||||
_lazyChannel = new Lazy<Task<IChannel>>(() => _rabbitMqService.CreateChannelAsync());
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ using RabbitMQ.Client.Events;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
public class RabbitMqIntegrationListenerService : BackgroundService
|
||||
public class RabbitMqIntegrationListenerService<TConfiguration> : BackgroundService
|
||||
where TConfiguration : IIntegrationListenerConfiguration
|
||||
{
|
||||
private readonly int _maxRetries;
|
||||
private readonly string _queueName;
|
||||
@@ -19,26 +20,24 @@ public class RabbitMqIntegrationListenerService : BackgroundService
|
||||
private readonly IIntegrationHandler _handler;
|
||||
private readonly Lazy<Task<IChannel>> _lazyChannel;
|
||||
private readonly IRabbitMqService _rabbitMqService;
|
||||
private readonly ILogger<RabbitMqIntegrationListenerService> _logger;
|
||||
private readonly ILogger<RabbitMqIntegrationListenerService<TConfiguration>> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public RabbitMqIntegrationListenerService(IIntegrationHandler handler,
|
||||
string routingKey,
|
||||
string queueName,
|
||||
string retryQueueName,
|
||||
int maxRetries,
|
||||
public RabbitMqIntegrationListenerService(
|
||||
IIntegrationHandler handler,
|
||||
TConfiguration configuration,
|
||||
IRabbitMqService rabbitMqService,
|
||||
ILogger<RabbitMqIntegrationListenerService> logger,
|
||||
ILogger<RabbitMqIntegrationListenerService<TConfiguration>> logger,
|
||||
TimeProvider timeProvider)
|
||||
{
|
||||
_handler = handler;
|
||||
_routingKey = routingKey;
|
||||
_retryQueueName = retryQueueName;
|
||||
_queueName = queueName;
|
||||
_maxRetries = configuration.MaxRetries;
|
||||
_routingKey = configuration.RoutingKey;
|
||||
_retryQueueName = configuration.IntegrationRetryQueueName;
|
||||
_queueName = configuration.IntegrationQueueName;
|
||||
_rabbitMqService = rabbitMqService;
|
||||
_logger = logger;
|
||||
_timeProvider = timeProvider;
|
||||
_maxRetries = maxRetries;
|
||||
_lazyChannel = new Lazy<Task<IChannel>>(() => _rabbitMqService.CreateChannelAsync());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user