/// <summary>
        ///     Replaces the <see cref="IServiceProvider" /> with the one from the specified scope.
        /// </summary>
        /// <param name="newServiceScope">
        ///     The <see cref="IServiceScope" /> to be used.
        /// </param>
        public void ReplaceServiceScope(IServiceScope newServiceScope)
        {
            _serviceScope?.Dispose();

            _serviceScope   = Check.NotNull(newServiceScope, nameof(newServiceScope));
            ServiceProvider = newServiceScope.ServiceProvider;
        }
예제 #2
0
        /// <summary>
        /// Makes logging
        /// Executes UnhandledExceptionHandler if any
        /// Stops Host based on exitCode passed. If it's null no stop
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="exception"></param>
        /// <param name="exitCode"></param>
        public async Task HandleUnhandledExceptionAsync(IServiceScope?scope, Exception exception, int?exitCode)
        {
            IServiceScope?localScope = null;

            try
            {
                var handler = _workerOptions.UnhandledExceptionHandler;
                if (handler != null)
                {
                    if (scope == null)
                    {
                        scope = localScope = _serviceProvider.CreateScope();
                    }
                    await handler.Invoke(scope.ServiceProvider, exception);
                }
            }
            catch (Exception e)
            {
                _logger.CustomErrorHandlerExceptionOccured(e);
            }
            finally
            {
                localScope?.Dispose();
            }

            if (exitCode.HasValue)
            {
                Environment.ExitCode = exitCode.Value;
                _hostApplicationLifetime.StopApplication();
            }
        }
예제 #3
0
        public async Task StopAsync(CancellationToken ct)
        {
            try
            {
                cancellationTokenSource?.Cancel();

                var task = runningTask;
                if (task != null)
                {
                    logger.LogTrace("Detect Cancel signal, wait for running console app task canceled.");
                    try
                    {
                        if (ct.CanBeCanceled)
                        {
                            var cancelTask    = CreateTimeoutTask(ct);
                            var completedTask = await Task.WhenAny(cancelTask, task);

                            if (completedTask == cancelTask)
                            {
                                logger.LogTrace("ConsoleApp aborted, cancel timeout.");
                            }
                            else
                            {
                                logger.LogTrace("ConsoleApp cancel completed.");
                            }
                        }
                        else
                        {
                            await task;
                            logger.LogTrace("ConsoleApp cancel completed.");
                        }
                    }
                    catch (OperationCanceledException ex)
                    {
                        if (ex.CancellationToken == ct)
                        {
                            logger.LogTrace("ConsoleApp aborted, cancel timeout.");
                        }
                        else
                        {
                            logger.LogTrace("ConsoleApp cancel completed.");
                        }
                    }
                }
            }
            finally
            {
                if (scope is IAsyncDisposable asyncDisposable)
                {
                    await asyncDisposable.DisposeAsync();
                }
                else
                {
                    scope?.Dispose();
                }
            }
        }
예제 #4
0
 void IDisposable.Dispose()
 {
     if (!IsDisposed)
     {
         _scope?.Dispose();
         _scope = null;
         Dispose(disposing: true);
         IsDisposed = true;
     }
 }
예제 #5
0
        public async Task StopAsync(CancellationToken cancellationToken = default)
        {
            await _console.Output.WriteLineAsync("Stopping WebHost background worker...");

            if (_webHost != null)
            {
                await _webHost.StopAsync(cancellationToken);

                await _webHost.WaitForShutdownAsync(cancellationToken);

                _webHost.Dispose();
                _webHost = null;
            }

            _serviceScope?.Dispose();
            _serviceScope = null;

            StartupTime = DateTime.MinValue;
        }
예제 #6
0
 protected virtual void Dispose(bool disposing)
 {
     if (!disposedValue)
     {
         if (disposing)
         {
             _compositionScope.Dispose();
             _fallback?.Dispose();
         }
         disposedValue = true;
     }
 }
예제 #7
0
        private void InvokeCore <TCallback>(
            Action <TCallback> action,
            IServiceProvider?scopedServiceProvider,
            bool invokeDuringShutdown)
        {
            if (!HasAny <TCallback>() || _appStopping && !invokeDuringShutdown)
            {
                return;
            }

            IServiceScope?scope = null;

            try
            {
                if (scopedServiceProvider == null)
                {
                    scope = _serviceScopeFactory.CreateScope();
                    scopedServiceProvider = scope.ServiceProvider;
                }

                var services = GetCallbacks <TCallback>(scopedServiceProvider);

                foreach (var service in services)
                {
                    TryInvoke(service, action);
                }
            }
            catch (BrokerCallbackInvocationException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new BrokerCallbackInvocationException(
                          $"Error occurred invoking the callbacks of type {typeof(TCallback).Name}. " +
                          "See inner exception for details.",
                          ex);
            }
            finally
            {
                scope?.Dispose();
            }
        }
예제 #8
0
    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources asynchronously.
    /// </summary>
    /// <returns>
    /// A task that represents the asynchronous dispose operation.
    /// </returns>
    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (!IsDisposed)
        {
            if (_scope is IAsyncDisposable asyncDisposable)
            {
                await asyncDisposable.DisposeAsync().ConfigureAwait(false);
            }
            else
            {
                _scope?.Dispose();
            }
            _scope = null;
            await DisposeAsync().ConfigureAwait(false);

            IsDisposed = true;
        }
        GC.SuppressFinalize(this);
    }
예제 #9
0
        private async Task InvokeCoreAsync <TCallback>(
            Func <TCallback, Task> action,
            IServiceProvider?scopedServiceProvider)
        {
            if (_appStopping || !HasAny <TCallback>())
            {
                return;
            }

            IServiceScope?scope = null;

            try
            {
                if (scopedServiceProvider == null)
                {
                    scope = _serviceScopeFactory.CreateScope();
                    scopedServiceProvider = scope.ServiceProvider;
                }

                var services = GetCallbacks <TCallback>(scopedServiceProvider);

                foreach (var service in services)
                {
                    await TryInvokeAsync(service, action).ConfigureAwait(false);
                }
            }
            catch (BrokerCallbackInvocationException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new BrokerCallbackInvocationException(
                          $"Error occurred invoking the callbacks of type {typeof(TCallback).Name}. " +
                          "See inner exception for details.",
                          ex);
            }
            finally
            {
                scope?.Dispose();
            }
        }
예제 #10
0
 public void Dispose()
 {
     serviceScope?.Dispose();
 }
        public override async Task OnConnectedAsync(ConnectionContext connection)
        {
            IServiceScope      scope         = null;
            BlazeClientContext clientContext = null;

            try
            {
                //Create connection scope
                scope = _serviceScopeFactory.CreateScope();
                var messageHandler = scope.ServiceProvider.GetRequiredService <IBlazeMessageHandler>();

                clientContext = (BlazeClientContext)scope.ServiceProvider.GetRequiredService <ClientContext>();
                clientContext.ConnectionContext = connection;
                clientContext.Reader            = connection.CreateReader();
                clientContext.Writer            = connection.CreateWriter();

                _clientManager.Add(clientContext);

                while (true)
                {
                    try
                    {
                        var result = await clientContext.Reader.ReadAsync(_protocol);

                        var message = result.Message;

                        if (message != null)
                        {
                            var response = await messageHandler.ProcessMessage(message);

                            if (response != null)
                            {
                                await clientContext.Writer.WriteAsync(_protocol, response);
                            }
                            //Send new notifications
                            while (clientContext.PendingNotifications.TryDequeue(out var notification))
                            {
                                await clientContext.Writer.WriteAsync(_protocol, notification);
                            }
                        }

                        if (result.IsCompleted)
                        {
                            break;
                        }
                    }
                    finally
                    {
                        clientContext.Reader.Advance();
                    }
                }
            }
            finally
            {
                if (clientContext != null)
                {
                    _clientManager.Remove(clientContext);
                }

                scope?.Dispose();
            }
        }
예제 #12
0
 /// <summary>
 ///     Releases the allocated resources for this context.
 /// </summary>
 public virtual void Dispose()
 {
     _disposed = true;
     _serviceScope?.Dispose();
 }
예제 #13
0
 public void Dispose()
 {
     scope?.Dispose();
 }
 public void Dispose()
 {
     _scope?.Dispose();
     _scope = null;
 }
예제 #15
0
 protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
 {
     base.OnNavigatingFrom(e);
     _scope?.Dispose();
 }
예제 #16
0
 /// <summary>
 ///
 /// </summary>
 public void Dispose()
 {
     db?.Dispose();
     scope?.Dispose();
 }
 public void Dispose()
 {
     _scope?.Dispose();
     _scope           = null;
     _requestServices = null;
 }
예제 #18
0
 public void TeardownTest()
 {
     Scope?.Dispose();
 }
예제 #19
0
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            Thread.CurrentThread.CurrentCulture   = new CultureInfo("en-us");
            Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

            Log.LogInformation("Starting bot background service.");

            IServiceScope scope = null;

            try
            {
                // Create a new scope for the session.
                scope = _provider.CreateScope();

                Log.LogTrace("Registering listeners for Discord client events.");

                _client.LatencyUpdated += OnLatencyUpdated;
                _client.Disconnected   += OnDisconnect;

                _client.Log     += _serilogAdapter.HandleLog;
                _restClient.Log += _serilogAdapter.HandleLog;
                _commands.Log   += _serilogAdapter.HandleLog;

                // Register with the cancellation token so we can stop listening to client events if the service is
                // shutting down or being disposed.
                stoppingToken.Register(OnStopping);

                Log.LogInformation("Running database migrations.");
                scope.ServiceProvider.GetRequiredService <ModixContext>()
                .Database.Migrate();

                Log.LogInformation("Starting behaviors.");
                await scope.ServiceProvider.GetRequiredService <IBehaviourConfigurationService>()
                .LoadBehaviourConfiguration();

                foreach (var behavior in scope.ServiceProvider.GetServices <IBehavior>())
                {
                    await behavior.StartAsync();

                    stoppingToken.Register(() => behavior.StopAsync().GetAwaiter().GetResult());
                }

                // The only thing that could go wrong at this point is the client failing to login and start. Promote
                // our local service scope to a field so that it's available to the HandleCommand method once events
                // start firing after we've connected.
                _scope = scope;

                Log.LogInformation("Loading command modules...");

                await _commands.AddModulesAsync(typeof(ModixBot).Assembly, _scope.ServiceProvider);

                Log.LogInformation("{Modules} modules loaded, containing {Commands} commands",
                                   _commands.Modules.Count(), _commands.Modules.SelectMany(d => d.Commands).Count());

                Log.LogInformation("Logging into Discord and starting the client.");

                await StartClient(stoppingToken);

                Log.LogInformation("Discord client started successfully.");

                await Task.Delay(-1);
            }
            catch (Exception ex)
            {
                Log.LogError(ex, "An error occurred while attempting to start the background service.");

                try
                {
                    OnStopping();

                    Log.LogInformation("Logging out of Discord.");
                    await _client.LogoutAsync();
                }
                finally
                {
                    scope?.Dispose();
                    _scope = null;
                }

                throw;
            }

            void OnStopping()
            {
                Log.LogInformation("Stopping background service.");

                _client.Disconnected   -= OnDisconnect;
                _client.LatencyUpdated -= OnLatencyUpdated;

                _client.Log     -= _serilogAdapter.HandleLog;
                _commands.Log   -= _serilogAdapter.HandleLog;
                _restClient.Log -= _serilogAdapter.HandleLog;

                foreach (var context in _commandScopes.Keys)
                {
                    _commandScopes.TryRemove(context, out var commandScope);
                    commandScope?.Dispose();
                }
            }
        }
        /// <inheritdoc/>
        protected override async Task BeforeTestCollectionFinishedAsync()
        {
            await base.BeforeTestCollectionFinishedAsync();

            _serviceScope?.Dispose();
        }
예제 #21
0
 public void Dispose()
 {
     _serviceScope?.Dispose();
     _messageQueueTransaction?.Dispose();
 }
 public void ClearScope()
 {
     _serviceScope?.Dispose();
     _serviceScope = null;
 }
예제 #23
0
 public void Dispose()
 {
     _transaction?.Dispose();
     _serviceScope?.Dispose();
 }
 public void Dispose()
 {
     _scope?.Dispose();
     _benchmarkContext?.Dispose();
 }
예제 #25
0
 public void CleanUp() => _scope?.Dispose();
예제 #26
0
 public override void Dispose()
 {
     _scope?.Dispose();
     base.Dispose();
 }
예제 #27
0
 public virtual void Dispose()
 {
     _serviceScope?.Dispose();
 }
예제 #28
0
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            Log.LogInformation("Starting bot background service.");

            IServiceScope scope = null;
            ModixBotHooks hooks = null;

            try
            {
                // Create a new scope for the session.
                scope = _provider.CreateScope();

                Log.LogTrace("Registering listeners for Discord client events.");
                hooks = new ModixBotHooks(scope.ServiceProvider);

                _client.MessageReceived += HandleCommand;
                _client.ReactionAdded   += hooks.HandleAddReaction;
                _client.ReactionRemoved += hooks.HandleRemoveReaction;
                _client.UserJoined      += hooks.HandleUserJoined;
                _client.UserLeft        += hooks.HandleUserLeft;

                _client.Log   += hooks.HandleLog;
                _commands.Log += hooks.HandleLog;

                // Register with the cancellation token so we can stop listening to client events if the service is
                // shutting down or being disposed.
                stoppingToken.Register(OnStopping);

                Log.LogInformation("Running database migrations.");
                scope.ServiceProvider.GetRequiredService <ModixContext>()
                .Database.Migrate();

                Log.LogInformation("Starting behaviors.");
                await scope.ServiceProvider.GetRequiredService <IBehaviourConfigurationService>()
                .LoadBehaviourConfiguration();

                foreach (var behavior in scope.ServiceProvider.GetServices <IBehavior>())
                {
                    await behavior.StartAsync();

                    stoppingToken.Register(() => behavior.StopAsync().GetAwaiter().GetResult());
                }

                // The only thing that could go wrong at this point is the client failing to login and start. Promote
                // our local service scope to a field so that it's available to the HandleCommand method once events
                // start firing after we've connected.
                _scope = scope;

                Log.LogInformation("Logging into Discord and starting the client.");

                await StartClient(stoppingToken);

                Log.LogInformation("Discord client started successfully.");

                await Task.Delay(-1);
            }
            catch (Exception ex)
            {
                Log.LogError(ex, "An error occurred while attempting to start the background service.");

                try
                {
                    OnStopping();

                    Log.LogInformation("Logging out of Discord.");
                    await _client.LogoutAsync();
                }
                finally
                {
                    scope?.Dispose();
                    _scope = null;
                }

                throw;
            }

            void OnStopping()
            {
                Log.LogInformation("Stopping background service.");

                _client.MessageReceived -= HandleCommand;

                if (hooks is null)
                {
                    return;
                }

                _client.ReactionAdded   -= hooks.HandleAddReaction;
                _client.ReactionRemoved -= hooks.HandleRemoveReaction;
                _client.UserJoined      -= hooks.HandleUserJoined;
                _client.UserLeft        -= hooks.HandleUserLeft;

                _client.Log   -= hooks.HandleLog;
                _commands.Log -= hooks.HandleLog;
            }
        }
 public void Dispose()
 => _serviceScope?.Dispose();
예제 #30
0
        public void Run(ScheduleHistoryItem objScheduleHistoryItem)
        {
            IServiceScope   serviceScope = null;
            SchedulerClient Process      = null;

            try
            {
                // This is called from RunPooledThread()
                ticksElapsed = Environment.TickCount - ticksElapsed;
                serviceScope = Globals.DependencyProvider.CreateScope();
                Process      = this.GetSchedulerClient(serviceScope.ServiceProvider, objScheduleHistoryItem.TypeFullName, objScheduleHistoryItem);
                Process.ScheduleHistoryItem = objScheduleHistoryItem;

                // Set up the handlers for the CoreScheduler
                Process.ProcessStarted     += Scheduler.CoreScheduler.WorkStarted;
                Process.ProcessProgressing += Scheduler.CoreScheduler.WorkProgressing;
                Process.ProcessCompleted   += Scheduler.CoreScheduler.WorkCompleted;
                Process.ProcessErrored     += Scheduler.CoreScheduler.WorkErrored;

                // This kicks off the DoWork method of the class
                // type specified in the configuration.
                Process.Started();
                try
                {
                    Process.ScheduleHistoryItem.Succeeded = false;
                    Process.DoWork();
                }
                catch (Exception exc)
                {
                    // in case the scheduler client
                    // didn't have proper exception handling
                    // make sure we fire the Errored event
                    Logger.Error(exc);

                    if (Process != null)
                    {
                        if (Process.ScheduleHistoryItem != null)
                        {
                            Process.ScheduleHistoryItem.Succeeded = false;
                        }

                        Process.Errored(ref exc);
                    }
                }

                if (Process.ScheduleHistoryItem.Succeeded)
                {
                    Process.Completed();
                }

                // If all processes in this ProcessGroup have
                // completed, set the ticksElapsed and raise
                // the Completed event.
                // I don't think this is necessary with the
                // other events.  I'll leave it for now and
                // will probably take it out later.
                if (processesCompleted == numberOfProcesses)
                {
                    if (processesCompleted == numberOfProcesses)
                    {
                        ticksElapsed = Environment.TickCount - ticksElapsed;
                        if (this.Completed != null)
                        {
                            this.Completed();
                        }
                    }
                }
            }
            catch (Exception exc)
            {
                // in case the scheduler client
                // didn't have proper exception handling
                // make sure we fire the Errored event
                if (Process != null)
                {
                    if (Process.ScheduleHistoryItem != null)
                    {
                        Process.ScheduleHistoryItem.Succeeded = false;
                    }

                    Process.Errored(ref exc);
                }
                else
                {
                    // when the schedule has invalid config and can't initialize the Process,
                    // we need also trigger work errored event so that the schedule can remove from inprogress and inqueue list to prevent endless loop.
                    Scheduler.CoreScheduler.WorkStarted(objScheduleHistoryItem);
                    objScheduleHistoryItem.Succeeded = false;
                    Scheduler.CoreScheduler.WorkErrored(objScheduleHistoryItem, exc);
                }
            }
            finally
            {
                serviceScope?.Dispose();

                // Track how many processes have completed for
                // this instanciation of the ProcessGroup
                numberOfProcessesInQueue -= 1;
                processesCompleted       += 1;
            }
        }