# Buggy code
def sorted_topologically(
    nodes: Iterable[T],
    graph: Mapping[T, Collection[T]],
) -> Generator[T, None, None]:
    """Given a set of nodes and a graph, yield the nodes in toplogical order.

    For example `sorted_topologically([1, 2], {1: [2]})` will yield `2, 1`.
    """

    # This is implemented by Kahn's algorithm.

    degree_map = {node: 0 for node in nodes}
    reverse_graph = {}  # type: Dict[T, Set[T]]

    for node, edges in graph.items():
        if node not in degree_map:
            continue

        for edge in edges:
            if edge in degree_map:
                degree_map[node] += 1

            reverse_graph.setdefault(edge, set()).add(node)
        reverse_graph.setdefault(node, set())

    zero_degree = [node for node, degree in degree_map.items() if degree == 0]
    heapq.heapify(zero_degree)

    while zero_degree:
        node = heapq.heappop(zero_degree)
        yield node

        for edge in reverse_graph.get(node, []):
            if edge in degree_map:
                degree_map[edge] -= 1
                if degree_map[edge] == 0:
                    heapq.heappush(zero_degree, edge)


# Traceback (KeyError)
янв 22 19:05:51 stratofortress.nexus.i.intelfx.name synapse[373164]: synapse.storage.background_updates: [background_updates-0] Starting update batch on background update 'chain_cover'
янв 22 19:05:51 stratofortress.nexus.i.intelfx.name synapse[373164]: synapse.storage.background_updates: [background_updates-0] Error doing update
Traceback (most recent call last):
File "/usr/lib/python3.9/site-packages/synapse/storage/background_updates.py", line 116, in run_background_updates
result = await self.do_next_background_update(
File "/usr/lib/python3.9/site-packages/synapse/storage/background_updates.py", line 227, in do_next_background_update
await self._do_background_update(desired_duration_ms)
File "/usr/lib/python3.9/site-packages/synapse/storage/background_updates.py", line 264, in _do_background_update
items_updated = await update_handler(progress, batch_size)
File "/usr/lib/python3.9/site-packages/synapse/storage/databases/main/events_bg_updates.py", line 748, in _chain_cover_index
result = await self.db_pool.runInteraction(
File "/usr/lib/python3.9/site-packages/synapse/storage/database.py", line 656, in runInteraction
result = await self.runWithConnection(
File "/usr/lib/python3.9/site-packages/synapse/storage/database.py", line 739, in runWithConnection
return await make_deferred_yieldable(
File "/usr/lib/python3.9/site-packages/twisted/python/threadpool.py", line 250, in inContext
result = inContext.theWork()
File "/usr/lib/python3.9/site-packages/twisted/python/threadpool.py", line 266, in <lambda>
inContext.theWork = lambda: context.call(ctx, func, *args, **kw)
File "/usr/lib/python3.9/site-packages/twisted/python/context.py", line 122, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/usr/lib/python3.9/site-packages/twisted/python/context.py", line 85, in callWithContext
return func(*args,**kw)
File "/usr/lib/python3.9/site-packages/twisted/enterprise/adbapi.py", line 306, in _runWithConnection
compat.reraise(excValue, excTraceback)
File "/usr/lib/python3.9/site-packages/twisted/python/compat.py", line 464, in reraise
raise exception.with_traceback(traceback)
File "/usr/lib/python3.9/site-packages/twisted/enterprise/adbapi.py", line 297, in _runWithConnection
result = func(conn, *args, **kw)
File "/usr/lib/python3.9/site-packages/synapse/storage/database.py", line 734, in inner_func
return func(db_conn, *args, **kwargs)
File "/usr/lib/python3.9/site-packages/synapse/storage/database.py", line 534, in new_transaction
r = func(cursor, *args, **kwargs)
File "/usr/lib/python3.9/site-packages/synapse/storage/databases/main/events_bg_updates.py", line 920, in _calculate_chain_cover_txn
PersistEventsStore._add_chain_cover_index(
File "/usr/lib/python3.9/site-packages/synapse/storage/databases/main/events.py", line 634, in _add_chain_cover_index
existing_chain_id = chain_map[auth_id]
KeyError: '$2PBTqUSs6gQtrZ3jZW8xVUSHvDbUYR3TKpFBoDHHwJk'

# Fixed code
def sorted_topologically(
    nodes: Iterable[T],
    graph: Mapping[T, Collection[T]],
) -> Generator[T, None, None]:
    """Given a set of nodes and a graph, yield the nodes in toplogical order.

    For example `sorted_topologically([1, 2], {1: [2]})` will yield `2, 1`.
    """

    # This is implemented by Kahn's algorithm.

    degree_map = {node: 0 for node in nodes}
    reverse_graph = {}  # type: Dict[T, Set[T]]

    for node, edges in graph.items():
        if node not in degree_map:
            continue

        for edge in set(edges):
            if edge in degree_map:
                degree_map[node] += 1

            reverse_graph.setdefault(edge, set()).add(node)
        reverse_graph.setdefault(node, set())

    zero_degree = [node for node, degree in degree_map.items() if degree == 0]
    heapq.heapify(zero_degree)

    while zero_degree:
        node = heapq.heappop(zero_degree)
        yield node

        for edge in reverse_graph.get(node, []):
            if edge in degree_map:
                degree_map[edge] -= 1
                if degree_map[edge] == 0:
                    heapq.heappush(zero_degree, edge)