diff --git a/src/Notifications/ConnectionCounter.cs b/src/Notifications/ConnectionCounter.cs new file mode 100644 index 0000000000..37cf5069d1 --- /dev/null +++ b/src/Notifications/ConnectionCounter.cs @@ -0,0 +1,29 @@ +using System.Threading; + +namespace Bit.Notifications +{ + public class ConnectionCounter + { + private int _count = 0; + + public void Increment() + { + Interlocked.Increment(ref _count); + } + + public void Decrement() + { + Interlocked.Decrement(ref _count); + } + + public void Reset() + { + _count = 0; + } + + public int GetCount() + { + return _count; + } + } +} diff --git a/src/Notifications/Jobs/JobsHostedService.cs b/src/Notifications/Jobs/JobsHostedService.cs new file mode 100644 index 0000000000..3cbcaf4866 --- /dev/null +++ b/src/Notifications/Jobs/JobsHostedService.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Bit.Core.Jobs; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Quartz; + +namespace Bit.Notifications.Jobs +{ + public class JobsHostedService : BaseJobsHostedService + { + public JobsHostedService( + IServiceProvider serviceProvider, + ILogger logger, + ILogger listenerLogger) + : base(serviceProvider, logger, listenerLogger) { } + + public override async Task StartAsync(CancellationToken cancellationToken) + { + var everyFiveMinutesTrigger = TriggerBuilder.Create() + .StartNow() + .WithCronSchedule("0 */5 * * * ?") + .Build(); + + Jobs = new List> + { + new Tuple(typeof(LogConnectionCounterJob), everyFiveMinutesTrigger) + }; + + await base.StartAsync(cancellationToken); + } + + public static void AddJobsServices(IServiceCollection services) + { + services.AddTransient(); + } + } +} diff --git a/src/Notifications/Jobs/LogConnectionCounterJob.cs b/src/Notifications/Jobs/LogConnectionCounterJob.cs new file mode 100644 index 0000000000..0a819d1513 --- /dev/null +++ b/src/Notifications/Jobs/LogConnectionCounterJob.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using Bit.Core; +using Bit.Core.Jobs; +using Microsoft.Extensions.Logging; +using Quartz; + +namespace Bit.Notifications.Jobs +{ + public class LogConnectionCounterJob : BaseJob + { + private readonly ConnectionCounter _connectionCounter; + + public LogConnectionCounterJob( + ILogger logger, + ConnectionCounter connectionCounter) + : base(logger) + { + _connectionCounter = connectionCounter; + } + + protected override Task ExecuteJobAsync(IJobExecutionContext context) + { + _logger.LogInformation(Constants.BypassFiltersEventId, + "Connection count: {0}", _connectionCounter.GetCount()); + return Task.FromResult(0); + } + } +} diff --git a/src/Notifications/NotificationsHub.cs b/src/Notifications/NotificationsHub.cs index 0141fa3245..a3be4e0ee9 100644 --- a/src/Notifications/NotificationsHub.cs +++ b/src/Notifications/NotificationsHub.cs @@ -8,6 +8,13 @@ namespace Bit.Notifications [Authorize("Application")] public class NotificationsHub : Microsoft.AspNetCore.SignalR.Hub { + private readonly ConnectionCounter _connectionCounter; + + public NotificationsHub(ConnectionCounter connectionCounter) + { + _connectionCounter = connectionCounter; + } + public override async Task OnConnectedAsync() { var currentContext = new CurrentContext(); @@ -16,6 +23,7 @@ namespace Bit.Notifications { await Groups.AddToGroupAsync(Context.ConnectionId, $"Organization_{org.Id}"); } + _connectionCounter.Increment(); await base.OnConnectedAsync(); } @@ -27,6 +35,7 @@ namespace Bit.Notifications { await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"Organization_{org.Id}"); } + _connectionCounter.Decrement(); await base.OnDisconnectedAsync(exception); } } diff --git a/src/Notifications/Startup.cs b/src/Notifications/Startup.cs index a5601353db..77c34998d6 100644 --- a/src/Notifications/Startup.cs +++ b/src/Notifications/Startup.cs @@ -31,12 +31,6 @@ namespace Bit.Notifications // Settings var globalSettings = services.AddGlobalSettingsServices(Configuration); - // Repositories - services.AddSqlServerRepositories(globalSettings); - - // Context - services.AddScoped(); - // Identity services.AddIdentityAuthenticationServices(globalSettings, Environment, config => { @@ -63,15 +57,20 @@ namespace Bit.Notifications services.AddSignalR(); } services.AddSingleton(); + services.AddSingleton(); // Mvc services.AddMvc(); - // Hosted Services - if(!globalSettings.SelfHosted && - CoreHelpers.SettingHasValue(globalSettings.Notifications?.ConnectionString)) + if(!globalSettings.SelfHosted) { - services.AddHostedService(); + // Hosted Services + Jobs.JobsHostedService.AddJobsServices(services); + services.AddHostedService(); + if(CoreHelpers.SettingHasValue(globalSettings.Notifications?.ConnectionString)) + { + services.AddHostedService(); + } } } @@ -105,9 +104,6 @@ namespace Bit.Notifications app.UseDeveloperExceptionPage(); } - // Default Middleware - app.UseDefaultMiddleware(env); - // Add Cors app.UseCors(policy => policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials());