def get_via_cycle(job_state_map, job):
    """
    Find a possible cycle including via_job.

    :param job_state_map:
        A dictionary mapping job.id to a JobState object.
    :param via_job:
        Any job, start of a hypothetical via job cycle.
    :raises KeyError:
        If any of the encountered jobs are not present in job_state_map.
    :return:
        A list of jobs that represent the cycle or an empty tuple if no cycle
        is present. The list has the property that item[0] is item[-1]

    A via cycle occurs if *job* is reachable through the *via_job* by
    recursively following via_job connection until via_job becomes None.
    """
    cycle = []
    seen = set()
    while job is not None:
        cycle.append(job)
        seen.add(job)
        next_job = job_state_map[job.id].via_job
        if next_job in seen:
            break
        job = next_job
    else:
        return ()
    cycle.append(next_job)
    return cycle
