# Buggy code
def __init__(self, database: DatabasePool, db_conn, hs):
    super().__init__(database, db_conn, hs)

    self.db_pool.updates.register_background_update_handler(
        self.EVENT_ORIGIN_SERVER_TS_NAME, self._background_reindex_origin_server_ts
    )
    self.db_pool.updates.register_background_update_handler(
        self.EVENT_FIELDS_SENDER_URL_UPDATE_NAME,
        self._background_reindex_fields_sender,
    )

    self.db_pool.updates.register_background_index_update(
        "event_contains_url_index",
        index_name="event_contains_url_index",
        table="events",
        columns=["room_id", "topological_ordering", "stream_ordering"],
        where_clause="contains_url = true AND outlier = false",
    )

    # an event_id index on event_search is useful for the purge_history
    # api. Plus it means we get to enforce some integrity with a UNIQUE
    # clause
    self.db_pool.updates.register_background_index_update(
        "event_search_event_id_idx",
        index_name="event_search_event_id_idx",
        table="event_search",
        columns=["event_id"],
        unique=True,
        psql_only=True,
    )

    self.db_pool.updates.register_background_update_handler(
        self.DELETE_SOFT_FAILED_EXTREMITIES, self._cleanup_extremities_bg_update
    )

    self.db_pool.updates.register_background_update_handler(
        "redactions_received_ts", self._redactions_received_ts
    )

    # This index gets deleted in `event_fix_redactions_bytes` update
    self.db_pool.updates.register_background_index_update(
        "event_fix_redactions_bytes_create_index",
        index_name="redactions_censored_redacts",
        table="redactions",
        columns=["redacts"],
        where_clause="have_censored",
    )

    self.db_pool.updates.register_background_update_handler(
        "event_fix_redactions_bytes", self._event_fix_redactions_bytes
    )

    self.db_pool.updates.register_background_update_handler(
        "event_store_labels", self._event_store_labels
    )

    self.db_pool.updates.register_background_index_update(
        "redactions_have_censored_ts_idx",
        index_name="redactions_have_censored_ts",
        table="redactions",
        columns=["received_ts"],
        where_clause="NOT have_censored",
    )

    self.db_pool.updates.register_background_index_update(
        "users_have_local_media",
        index_name="users_have_local_media",
        table="local_media_repository",
        columns=["user_id", "created_ts"],
    )

    self.db_pool.updates.register_background_update_handler(
        "rejected_events_metadata",
        self._rejected_events_metadata,
    )

    self.db_pool.updates.register_background_update_handler(
        "chain_cover",
        self._chain_cover_index,
    )


# Traceback (twisted.internet.defer.FirstError)
synapse.http.server: [POST-10040] Failed handle request via 'JoinRoomAliasServlet': <XForwardedForRequest at 0x7f57646fa970 method='POST' uri='/_matrix/client/r0/join/%23synapse%3Amatrix.org' clientproto='HTTP/1.1' site='8008'>
Traceback (most recent call last):
File "/usr/lib/python3.9/site-packages/synapse/http/server.py", line 252, in _async_render_wrapper
callback_return = await self._async_render(request)
File "/usr/lib/python3.9/site-packages/synapse/http/server.py", line 430, in _async_render
callback_return = await raw_callback_return
File "/usr/lib/python3.9/site-packages/synapse/rest/client/v1/room.py", line 301, in on_POST
await self.room_member_handler.update_membership(
File "/usr/lib/python3.9/site-packages/synapse/handlers/room_member.py", line 333, in update_membership
result = await self.update_membership_locked(
File "/usr/lib/python3.9/site-packages/synapse/handlers/room_member.py", line 549, in update_membership_locked
remote_join_response = await self._remote_join(
File "/usr/lib/python3.9/site-packages/synapse/handlers/room_member.py", line 1091, in _remote_join
event_id, stream_id = await self.federation_handler.do_invite_join(
File "/usr/lib/python3.9/site-packages/synapse/handlers/federation.py", line 1400, in do_invite_join
max_stream_id = await self._persist_auth_tree(
File "/usr/lib/python3.9/site-packages/synapse/handlers/federation.py", line 2050, in _persist_auth_tree
await self.persist_events_and_notify(
File "/usr/lib/python3.9/site-packages/synapse/handlers/federation.py", line 2925, in persist_events_and_notify
events, max_stream_token = await self.storage.persistence.persist_events(
File "/usr/lib/python3.9/site-packages/synapse/storage/persist_events.py", line 262, in persist_events
ret_vals = await make_deferred_yieldable(
twisted.internet.defer.FirstError: FirstError[#0, [Failure instance: Traceback: <class 'psycopg2.errors.UniqueViolation'>: duplicate key value violates unique constraint "event_auth_chains_pkey"
DETAIL:  Key (event_id)=($e9U026auDHIgaZPAqlblvPupACjl7jcZDblP970dJPs) already exists.

/usr/lib/python3.9/site-packages/synapse/metrics/background_process_metrics.py:208:run
--- <exception caught here> ---
/usr/lib/python3.9/site-packages/synapse/storage/persist_events.py:172:handle_queue_loop
/usr/lib/python3.9/site-packages/synapse/storage/persist_events.py:324:persisting_queue
/usr/lib/python3.9/site-packages/synapse/storage/persist_events.py:532:_persist_events
/usr/lib/python3.9/site-packages/synapse/storage/databases/main/events.py:171:_persist_events_and_state_updates
/usr/lib/python3.9/site-packages/synapse/storage/database.py:661:runInteraction
/usr/lib/python3.9/site-packages/synapse/storage/database.py:744:runWithConnection
/usr/lib64/python3.9/site-packages/twisted/python/threadpool.py:250:inContext
/usr/lib64/python3.9/site-packages/twisted/python/threadpool.py:266:<lambda>
/usr/lib64/python3.9/site-packages/twisted/python/context.py:122:callWithContext
/usr/lib64/python3.9/site-packages/twisted/python/context.py:85:callWithContext
/usr/lib64/python3.9/site-packages/twisted/enterprise/adbapi.py:306:_runWithConnection
/usr/lib64/python3.9/site-packages/twisted/python/compat.py:464:reraise
/usr/lib64/python3.9/site-packages/twisted/enterprise/adbapi.py:297:_runWithConnection
/usr/lib/python3.9/site-packages/synapse/storage/database.py:739:inner_func
/usr/lib/python3.9/site-packages/synapse/storage/database.py:539:new_transaction
/usr/lib/python3.9/site-packages/synapse/logging/utils.py:71:wrapped
/usr/lib/python3.9/site-packages/synapse/storage/databases/main/events.py:379:_persist_events_txn
/usr/lib/python3.9/site-packages/synapse/storage/databases/main/events.py:472:_persist_event_auth_chain_txn
/usr/lib/python3.9/site-packages/synapse/storage/databases/main/events.py:630:_add_chain_cover_index
/usr/lib/python3.9/site-packages/synapse/storage/database.py:896:simple_insert_many_txn
/usr/lib/python3.9/site-packages/synapse/storage/database.py:274:execute_batch
/usr/lib/python3.9/site-packages/synapse/storage/database.py:319:_do_execute
/usr/lib/python3.9/site-packages/synapse/storage/database.py:274:<lambda>
/usr/lib64/python3.9/site-packages/psycopg2/extras.py:1209:execute_batch
]]

# Fixed code
def __init__(self, database: DatabasePool, db_conn, hs):
    super().__init__(database, db_conn, hs)

    self.db_pool.updates.register_background_update_handler(
        self.EVENT_ORIGIN_SERVER_TS_NAME, self._background_reindex_origin_server_ts
    )
    self.db_pool.updates.register_background_update_handler(
        self.EVENT_FIELDS_SENDER_URL_UPDATE_NAME,
        self._background_reindex_fields_sender,
    )

    self.db_pool.updates.register_background_index_update(
        "event_contains_url_index",
        index_name="event_contains_url_index",
        table="events",
        columns=["room_id", "topological_ordering", "stream_ordering"],
        where_clause="contains_url = true AND outlier = false",
    )

    # an event_id index on event_search is useful for the purge_history
    # api. Plus it means we get to enforce some integrity with a UNIQUE
    # clause
    self.db_pool.updates.register_background_index_update(
        "event_search_event_id_idx",
        index_name="event_search_event_id_idx",
        table="event_search",
        columns=["event_id"],
        unique=True,
        psql_only=True,
    )

    self.db_pool.updates.register_background_update_handler(
        self.DELETE_SOFT_FAILED_EXTREMITIES, self._cleanup_extremities_bg_update
    )

    self.db_pool.updates.register_background_update_handler(
        "redactions_received_ts", self._redactions_received_ts
    )

    # This index gets deleted in `event_fix_redactions_bytes` update
    self.db_pool.updates.register_background_index_update(
        "event_fix_redactions_bytes_create_index",
        index_name="redactions_censored_redacts",
        table="redactions",
        columns=["redacts"],
        where_clause="have_censored",
    )

    self.db_pool.updates.register_background_update_handler(
        "event_fix_redactions_bytes", self._event_fix_redactions_bytes
    )

    self.db_pool.updates.register_background_update_handler(
        "event_store_labels", self._event_store_labels
    )

    self.db_pool.updates.register_background_index_update(
        "redactions_have_censored_ts_idx",
        index_name="redactions_have_censored_ts",
        table="redactions",
        columns=["received_ts"],
        where_clause="NOT have_censored",
    )

    self.db_pool.updates.register_background_index_update(
        "users_have_local_media",
        index_name="users_have_local_media",
        table="local_media_repository",
        columns=["user_id", "created_ts"],
    )

    self.db_pool.updates.register_background_update_handler(
        "rejected_events_metadata",
        self._rejected_events_metadata,
    )

    self.db_pool.updates.register_background_update_handler(
        "chain_cover",
        self._chain_cover_index,
    )

    self.db_pool.updates.register_background_update_handler(
        "purged_chain_cover",
        self._purged_chain_cover_index,
    )