# Buggy code
def _run_on_schedule(
    self, parameters: Dict[str, Any], runner_cls: type, **kwargs: Any
) -> "prefect.engine.state.State":
    base_parameters = parameters or dict()

    ## determine time of first run
    try:
        if self.schedule is not None:
            next_run_event = self.schedule.next(1, return_events=True)[0]
            next_run_time = next_run_event.start_time  # type: ignore
            parameters = base_parameters.copy()
            parameters.update(next_run_event.parameter_defaults)  # type: ignore
        else:
            next_run_time = pendulum.now("utc")
    except IndexError:
        raise ValueError("Flow has no more scheduled runs.") from None

    ## setup initial states
    flow_state = prefect.engine.state.Scheduled(start_time=next_run_time, result={})
    flow_state = kwargs.pop("state", flow_state)
    if not isinstance(flow_state.result, dict):
        flow_state.result = {}
    task_states = kwargs.pop("task_states", {})
    flow_state.result.update(task_states)

    # set context for this flow run
    flow_run_context = kwargs.pop("context", {}).copy()  # copy to avoid modification

    ## run this flow indefinitely, so long as its schedule has future dates
    while True:
        flow_run_context.update(scheduled_start_time=next_run_time)

        if flow_state.is_scheduled():
            next_run_time = flow_state.start_time
            now = pendulum.now("utc")
            naptime = max((next_run_time - now).total_seconds(), 0)
            if naptime > 0:
                self.logger.info(
                    "Waiting for next scheduled run at {}".format(next_run_time)
                )
            time.sleep(naptime)

        ## begin a single flow run
        while not flow_state.is_finished():
            runner = runner_cls(flow=self)
            flow_state = runner.run(
                parameters=parameters,
                return_tasks=self.tasks,
                state=flow_state,
                task_states=flow_state.result,
                context=flow_run_context,
                **kwargs,
            )
            if not isinstance(flow_state.result, dict):
                return flow_state  # something went wrong

            task_states = list(flow_state.result.values())
            for s in filter(lambda x: x.is_mapped(), task_states):
                task_states.extend(s.map_states)
            earliest_start = min(
                [s.start_time for s in task_states if s.is_scheduled()],
                default=pendulum.now("utc"),
            )

            ## wait until first task is ready for retry
            now = pendulum.now("utc")
            naptime = max((earliest_start - now).total_seconds(), 0)
            if naptime > 0:
                self.logger.info(
                    "Waiting for next available Task run at {}".format(earliest_start)
                )
            time.sleep(naptime)

        ## create next scheduled run
        try:
            # update context cache
            for t, s in flow_state.result.items():
                if s.is_cached():
                    cached_sub_states = [s]
                elif s.is_mapped() and any(
                    sub_state.is_cached() for sub_state in s.map_states
                ):
                    cached_sub_states = [
                        sub_state for sub_state in s.map_states if sub_state.is_cached()
                    ]
                else:
                    cached_sub_states = []

                fresh_states = [
                    s
                    for s in prefect.context.caches.get(t.cache_key or t.name, [])
                    + cached_sub_states
                    if s.cached_result_expiration > now
                ]
                prefect.context.caches[t.cache_key or t.name] = fresh_states
            if self.schedule is not None:
                next_run_event = self.schedule.next(1, return_events=True)[0]
                next_run_time = next_run_event.start_time  # type: ignore
                parameters = base_parameters.copy()
                parameters.update(next_run_event.parameter_defaults)  # type: ignore
            else:
                break
        except IndexError:
            break
        flow_state = prefect.engine.state.Scheduled(start_time=next_run_time, result={})
    return flow_state


# Traceback (tornado.util.TimeoutError)
[2020-03-09 12:48:50,310] ERROR - prefect.FlowRunner | Unexpected error: OSError("Timed out trying to connect to 'tcp://localhost:8786' after 10 s: in <distributed.comm.tcp.TCPConnector object at 0x0000017EBAD57208>: ConnectionRefusedError: [Errno 10061] Unknown error")
Traceback (most recent call last):
File "\Anaconda\lib\site-packages\distributed\comm\core.py", line 218, in connect
quiet_exceptions=EnvironmentError,
File "\Anaconda\lib\site-packages\tornado\gen.py", line 735, in run
value = future.result()
tornado.util.TimeoutError: Timeout

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "\Anaconda\lib\site-packages\prefect\engine\runner.py", line 48, in inner
new_state = method(self, state, *args, **kwargs)
File "\Anaconda\lib\site-packages\prefect\engine\flow_runner.py", line 398, in get_flow_run_state
with executor.start():
File "\Anaconda\lib\contextlib.py", line 112, in __enter__
return next(self.gen)
File "\Anaconda\lib\site-packages\prefect\engine\executors\dask.py", line 78, in start
with Client(self.address, **self.kwargs) as client:
File "\Anaconda\lib\site-packages\distributed\client.py", line 712, in __init__
self.start(timeout=timeout)
File "\Anaconda\lib\site-packages\distributed\client.py", line 858, in start
sync(self.loop, self._start, **kwargs)
File "\Anaconda\lib\site-packages\distributed\utils.py", line 331, in sync
six.reraise(*error[0])
File "\Anaconda\lib\site-packages\six.py", line 703, in reraise
raise value
File "\Anaconda\lib\site-packages\distributed\utils.py", line 316, in f
result[0] = yield future
File "\Anaconda\lib\site-packages\tornado\gen.py", line 735, in run
value = future.result()
File "\Anaconda\lib\site-packages\tornado\gen.py", line 742, in run
yielded = self.gen.throw(*exc_info)  # type: ignore
File "\Anaconda\lib\site-packages\distributed\client.py", line 954, in _start
yield self._ensure_connected(timeout=timeout)
File "\Anaconda\lib\site-packages\tornado\gen.py", line 735, in run
value = future.result()
File "\Anaconda\lib\site-packages\tornado\gen.py", line 742, in run
yielded = self.gen.throw(*exc_info)  # type: ignore
File "\Anaconda\lib\site-packages\distributed\client.py", line 1010, in _ensure_connected
connection_args=self.connection_args,
File "\Anaconda\lib\site-packages\tornado\gen.py", line 735, in run
value = future.result()
File "\Anaconda\lib\site-packages\tornado\gen.py", line 742, in run
yielded = self.gen.throw(*exc_info)  # type: ignore
File "\Anaconda\lib\site-packages\distributed\comm\core.py", line 230, in connect
_raise(error)
File "\Anaconda\lib\site-packages\distributed\comm\core.py", line 207, in _raise
raise IOError(msg)
OSError: Timed out trying to connect to 'tcp://localhost:8786' after 10 s: in <distributed.comm.tcp.TCPConnector object at 0x0000017EBAD57208>: ConnectionRefusedError: [Errno 10061] Unknown error
[2020-03-09 12:48:50,360] ERROR - prefect.Flow: Hello | Unexpected error occured in FlowRunner: OSError("Timed out trying to connect to 'tcp://localhost:8786' after 10 s: in <distributed.comm.tcp.TCPConnector object at 0x0000017EBAD57208>: ConnectionRefusedError: [Errno 10061] Unknown error")

# Fixed code
def _run_on_schedule(
    self, parameters: Dict[str, Any], runner_cls: type, **kwargs: Any
) -> "prefect.engine.state.State":
    base_parameters = parameters or dict()

    ## determine time of first run
    try:
        if self.schedule is not None:
            next_run_event = self.schedule.next(1, return_events=True)[0]
            next_run_time = next_run_event.start_time  # type: ignore
            parameters = base_parameters.copy()
            parameters.update(next_run_event.parameter_defaults)  # type: ignore
        else:
            next_run_time = pendulum.now("utc")
    except IndexError:
        raise ValueError("Flow has no more scheduled runs.") from None

    ## setup initial states
    flow_state = prefect.engine.state.Scheduled(start_time=next_run_time, result={})
    flow_state = kwargs.pop("state", flow_state)
    if not isinstance(flow_state.result, dict):
        flow_state.result = {}
    task_states = kwargs.pop("task_states", {})
    flow_state.result.update(task_states)

    # set context for this flow run
    flow_run_context = kwargs.pop("context", {}).copy()  # copy to avoid modification

    ## run this flow indefinitely, so long as its schedule has future dates
    while True:
        flow_run_context.update(scheduled_start_time=next_run_time)

        if flow_state.is_scheduled():
            next_run_time = flow_state.start_time
            now = pendulum.now("utc")
            naptime = max((next_run_time - now).total_seconds(), 0)
            if naptime > 0:
                self.logger.info(
                    "Waiting for next scheduled run at {}".format(next_run_time)
                )
            time.sleep(naptime)

        error = False

        ## begin a single flow run
        while not flow_state.is_finished():
            runner = runner_cls(flow=self)
            flow_state = runner.run(
                parameters=parameters,
                return_tasks=self.tasks,
                state=flow_state,
                task_states=flow_state.result,
                context=flow_run_context,
                **kwargs,
            )
            if not isinstance(flow_state.result, dict):
                error = True
                break

            task_states = list(flow_state.result.values())
            for s in filter(lambda x: x.is_mapped(), task_states):
                task_states.extend(s.map_states)
            earliest_start = min(
                [s.start_time for s in task_states if s.is_scheduled()],
                default=pendulum.now("utc"),
            )

            ## wait until first task is ready for retry
            now = pendulum.now("utc")
            naptime = max((earliest_start - now).total_seconds(), 0)
            if naptime > 0:
                self.logger.info(
                    "Waiting for next available Task run at {}".format(earliest_start)
                )
            time.sleep(naptime)

        ## create next scheduled run
        if not error:
            # update context cache
            for t, s in flow_state.result.items():
                if s.is_cached():
                    cached_sub_states = [s]
                elif s.is_mapped() and any(
                    sub_state.is_cached() for sub_state in s.map_states
                ):
                    cached_sub_states = [
                        sub_state for sub_state in s.map_states if sub_state.is_cached()
                    ]
                else:
                    cached_sub_states = []

                fresh_states = [
                    s
                    for s in prefect.context.caches.get(t.cache_key or t.name, [])
                    + cached_sub_states
                    if s.cached_result_expiration > now
                ]
                prefect.context.caches[t.cache_key or t.name] = fresh_states

        try:
            if self.schedule is not None:
                next_run_event = self.schedule.next(1, return_events=True)[0]
                next_run_time = next_run_event.start_time  # type: ignore
                parameters = base_parameters.copy()
                parameters.update(next_run_event.parameter_defaults)  # type: ignore
            else:
                break
        except IndexError:
            # Handle when there are no more events on schedule
            break

        flow_state = prefect.engine.state.Scheduled(start_time=next_run_time, result={})
    return flow_state