예제 #1
0
        /// <summary>
        /// Reload this instance.
        /// </summary>
        public async Task ReloadAsync(bool http, bool https)
        {
            Program.DebugConsoleOutput("Reloading instance");
            var cfg    = ConfigParser.ParseTextFile(m_path);
            var config = ConfigParser.CreateServerConfig(cfg);

            config.Storage = m_storage;

            ((MemoryStorageCreator)m_storage).ExpireCheckInterval = cfg.StorageExpirationCheckIntervalSeconds;

            var prevhttp  = m_http_runner?.Wrapper;
            var prevhttps = m_https_runner?.Wrapper;

            IWrappedRunner new_http_runner  = null;
            IWrappedRunner new_https_runner = null;

            Program.DebugConsoleOutput("Creating runners");

            try
            {
                if (http)
                {
                    new_http_runner = CreateRunner(m_path, false, m_storage, default(System.Threading.CancellationToken));
                }
                if (https)
                {
                    new_https_runner = CreateRunner(m_path, true, m_storage, default(System.Threading.CancellationToken));
                }
            }
            catch (Exception ex)
            {
                Program.DebugConsoleOutput("Failed to create runners: {0}", ex);

                // If we fail to start, just kill any of the instances we just started
                if (new_http_runner != null)
                {
                    try { new_http_runner.Kill(); }
                    catch { }
                }

                if (new_https_runner != null)
                {
                    try { new_https_runner.Kill(); }
                    catch { }
                }

                throw;
            }

            Program.DebugConsoleOutput("Created runners, replacing existing runners");

            // Set up the new instances
            m_http_runner = await ReplaceOrRestartAsync(m_http_runner, prevhttp, new_http_runner, cfg.HttpAddress, cfg.HttpPort, false, config);

            m_https_runner = await ReplaceOrRestartAsync(m_https_runner, prevhttps, new_https_runner, cfg.HttpsAddress, cfg.HttpsPort, true, config);


            Program.DebugConsoleOutput("Stopping old runners");

            if (new_https_runner == null)
            {
                if (m_https_runner != null)
                {
                    m_https_runner.StopAsync();
                }
            }
            else
            {
                if (m_https_runner == null)
                {
                    m_https_runner = new InstanceRunner();
                }

                m_https_runner.Wrapper = new_https_runner;
            }

            // TODO: If the runner is reconfigured, then restart it

            Program.DebugConsoleOutput("Setting up crash handlers.");

            // Bind variables
            var self_http  = m_http_runner;
            var self_https = m_https_runner;

            // Set up a crash handler to capture crash in log
            var dummy = self_http?.RunnerTask.ContinueWith(x =>
            {
                if (!self_http.ShouldStop && InstanceCrashed != null)
                {
                    InstanceCrashed(cfg.HttpAddress, false, x.IsFaulted ? x.Exception : new Exception("Unexpected stop"));
                }
            });

            // Set up a crash handler to capture crash in log
            dummy = self_https?.RunnerTask.ContinueWith(x =>
            {
                if (!self_https.ShouldStop && InstanceCrashed != null)
                {
                    InstanceCrashed(cfg.HttpsAddress, true, x.IsFaulted ? x.Exception : new Exception("Unexpected stop"));
                }
            });

            Program.DebugConsoleOutput("Ensuring that old runners are stopped");

            if (prevhttp != null || prevhttps != null)
            {
                await Task.Run(async() =>
                {
                    // We need both to stop
                    var t = Task.WhenAll(new[] { prevhttp?.StopAsync(), prevhttps?.StopAsync() }.Where(x => x != null));

                    // Give old processes time to terminate (if they are handling requests)
                    var maxtries = cfg.MaxUnloadWaitSeconds;
                    while (maxtries-- > 0 && !t.IsCompleted)
                    {
                        await Task.WhenAny(t, Task.Delay(1000));
                    }

                    // If we failed to stop, request a kill
                    if (!t.IsCompleted)
                    {
                        Program.DebugConsoleOutput("Requesting kill of old runners");
                        if (prevhttp != null)
                        {
                            prevhttp.Kill();
                        }
                        if (prevhttps != null)
                        {
                            prevhttps.Kill();
                        }
                    }
                });
            }

            Program.DebugConsoleOutput("Reloading completed");
        }
예제 #2
0
        private async Task <InstanceRunner> ReplaceOrRestartAsync(InstanceRunner runner, IWrappedRunner prevhandler, IWrappedRunner newhandler, string newaddr, int newport, bool usessl, ServerConfig config)
        {
            if (newhandler == null)
            {
                // We are stopping the handler

                if (runner != null)
                {
                    runner.StopAsync();
                }
                runner = null;
            }
            else
            {
                // We are starting, or restarting the handler
                if (runner == null)
                {
                    // Just
                    runner = new InstanceRunner {
                        Wrapper = newhandler
                    };
                    await runner.RestartAsync(newaddr, newport, usessl, config);
                }
                else
                {
                    // If any of these change, we need to restart the listen socket
                    if (runner.Address != newaddr || runner.Port != newport)
                    {
                        // Start the new instance first
                        var newrunner = new InstanceRunner {
                            Wrapper = newhandler
                        };
                        await newrunner.RestartAsync(newaddr, newport, usessl, config);

                        runner.StopAsync();
                        return(newrunner);
                    }
                    // In this case we must restart the socket, but need to stop first
                    else if (config.SocketBacklog != runner.Config.SocketBacklog)
                    {
                        await runner.StopAsync();

                        runner         = new InstanceRunner();
                        runner.Wrapper = newhandler;
                        await runner.RestartAsync(newaddr, newport, usessl, config);
                    }
                    else
                    {
                        // No changes, just apply the new handler for future requests
                        runner.Wrapper = newhandler;
                    }
                }
            }

            return(runner);
        }