public void RunAndBlock(CancellationToken cancellationToken = default(CancellationToken))
        {
            _consecutiveErrorCount = 0;
            do
            {
                ScriptHost newInstance = null;

                try
                {
                    // if we were in an error state retain that,
                    // otherwise move to default
                    if (State != ScriptHostState.Error)
                    {
                        State = ScriptHostState.Default;
                    }

                    // Create a new host config, but keep the host id from existing one
                    _config.HostConfig = new JobHostConfiguration(_settingsManager.Configuration)
                    {
                        HostId = _config.HostConfig.HostId
                    };
                    OnInitializeConfig(_config);
                    newInstance = _scriptHostFactory.Create(_environment, EventManager, _settingsManager, _config, _loggerProviderFactory);

                    _currentInstance = newInstance;
                    lock (_liveInstances)
                    {
                        _liveInstances.Add(newInstance);
                        _hostStartCount++;
                    }

                    newInstance.HostInitializing += OnHostInitializing;
                    newInstance.HostInitialized  += OnHostInitialized;
                    newInstance.HostStarted      += OnHostStarted;
                    newInstance.Initialize();

                    newInstance.StartAsync(cancellationToken).GetAwaiter().GetResult();

                    // log any function initialization errors
                    LogErrors(newInstance);

                    LastError = null;
                    _consecutiveErrorCount   = 0;
                    _restartDelayTokenSource = null;

                    // Wait for a restart signal. This event will automatically reset.
                    // While we're restarting, it is possible for another restart to be
                    // signaled. That is fine - the restart will be processed immediately
                    // once we get to this line again. The important thing is that these
                    // restarts are only happening on a single thread.
                    var waitHandles = new WaitHandle[] { cancellationToken.WaitHandle, _restartHostEvent, _stopEvent };
                    if (!waitHandles.Any(p => p.SafeWaitHandle.IsClosed))
                    {
                        WaitHandle.WaitAny(waitHandles);
                    }

                    // Orphan the current host instance. We're stopping it, so it won't listen for any new functions
                    // it will finish any currently executing functions and then clean itself up.
                    // Spin around and create a new host instance.
                    Task.Run(() => Orphan(newInstance)
                             .ContinueWith(t =>
                    {
                        if (t.IsFaulted)
                        {
                            t.Exception.Handle(e => true);
                        }
                    }, TaskContinuationOptions.ExecuteSynchronously));
                }
                catch (Exception ex)
                {
                    if (_disposed)
                    {
                        // In some cases during shutdown we'll be disposed and get
                        // some terminating exceptions. We want to just ignore these
                        // and stop immediately.
                        break;
                    }

                    State     = ScriptHostState.Error;
                    LastError = ex;
                    _consecutiveErrorCount++;

                    // We need to keep the host running, so we catch and log any errors
                    // then restart the host
                    string message = "A ScriptHost error has occurred";
                    Instance?.Logger.LogError(0, ex, message);

                    if (ShutdownHostIfUnhealthy())
                    {
                        break;
                    }

                    // If a ScriptHost instance was created before the exception was thrown
                    // Orphan and cleanup that instance.
                    if (newInstance != null)
                    {
                        Task.Run(() => Orphan(newInstance, forceStop: true)
                                 .ContinueWith(t =>
                        {
                            if (t.IsFaulted)
                            {
                                t.Exception.Handle(e => true);
                            }
                        }, TaskContinuationOptions.ExecuteSynchronously));
                    }

                    // attempt restarts using an exponential backoff strategy
                    CreateRestartBackoffDelay(_consecutiveErrorCount).GetAwaiter().GetResult();
                }
            }while (!_stopped && !_disposed && !cancellationToken.IsCancellationRequested);
        }