cosullivan / SmtpServer

A SMTP Server component written in C#
MIT License
676 stars 160 forks source link

What is actually needed for gracefully shutting down the server? #152

Closed reponemec closed 3 years ago

reponemec commented 3 years ago

What is actually needed for gracefully shutting down the server? There are two different examples in source code, first as simple console app, second as worker service:

ServerShutdownExample.cs

    Console.WriteLine("Gracefully shutting down the server.");
    server.Shutdown();

    server.ShutdownTask.WaitWithoutException();
    Console.WriteLine("The server is no longer accepting new connections.");

    Console.WriteLine("Waiting for active sessions to complete.");
    serverTask.WaitWithoutException();

    Console.WriteLine("All active sessions are complete.");

Worker.cs:

    public sealed class Worker : BackgroundService
    {
        readonly SmtpServer.SmtpServer _smtpServer;

        public Worker(SmtpServer.SmtpServer smtpServer)
        {
            _smtpServer = smtpServer;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            return _smtpServer.StartAsync(stoppingToken);
        }
    }

It looks server.Shutdown() and server.ShutdownTask.WaitWithoutException() operations are omited in worker service. Does it mean these operation are not neccessary here? In other words, is this worker service waiting for active sessions to complete in the same way as in the previous example?

cosullivan commented 3 years ago

Hi @reponemec ,

You can cancel the server in one of two ways; a) cancelling the CancellationTokenthat is given to the StartAsync() method, b) calling the Shutdown() method on the server.

Both will actually do the same thing and the two different examples above are just cancelling using the two different methods.

The Shutdown process consists of two phases, firstly, shutting down any listeners and therefore stopping any further connections from being accepted. If you care about knowing when this part of the shutdown process has completed then that is what the ShutdownTask is for. You can await that and it will complete once the listeners have completed.

Once the listeners have been stopped, then any active sessions are given the chance to gracefully shutdown or complete and the task returned by the StartAsync() method will complete once those sessions have finished too.

So the bare minimum is what the WorkerService is doing, but the ServerShutdownExample just shows how you can have a bit more control over when things have shutdown.

I hope this makes sense?

Thanks, Cain.

reponemec commented 3 years ago

Thanks, that's exactly what I needed to know.