Repository: matrix-org/synapse

Issue:
MSC2716 batch sending breaks when using event persistence workers 
### Steps to reproduce

- Have a Synapse instance with workers
- Use [MSC2716](https://github.com/matrix-org/matrix-doc/pull/2716) `/batch_send`ing

Expected result: successful batch send

Actual result: internal server error

```
2021-10-30 11:51:57,760 - synapse.http.server - 97 - ERROR - POST-144- Failed handle request via 'ReplicationSendEventRestServlet': <SynapseRequest at 0x7f65c3d460a0 method='POST' uri='/_synapse/replication/send_event/%24163559471743RetmW%3Amaunium.net/wwYpCVkpSn' clientproto='HTTP/1.1' site=8034>
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/twisted/internet/defer.py", line 1661, in _inlineCallbacks
    result = current_context.run(gen.send, result)
  File "/usr/local/lib/python3.9/site-packages/synapse/replication/http/send_event.py", line 129, in _handle_request
    event = await self.event_creation_handler.persist_and_notify_client_event(
  File "/usr/local/lib/python3.9/site-packages/synapse/handlers/message.py", line 1507, in persist_and_notify_client_event
    await self.store.get_insertion_event_by_batch_id(
AttributeError: 'GenericWorkerSlavedStore' object has no attribute 'get_insertion_event_by_batch_id'
2021-10-30 11:51:57,763 - synapse.access.http.8034 - 400 - INFO - POST-144- 172.18.2.50 - 8034 - {@whatsappbot:maunium.net} Processed request: 0.006sec/0.000sec (0.002sec, 0.000sec) (0.000sec/0.001sec/2) 55B 500 "POST /_synapse/replication/send_event/%24163559471743RetmW%3Amaunium.net/wwYpCVkpSn HTTP/1.1" "Synapse/1.46.0rc1" [1 dbevts]
```

### Version information
- **Version**: 1.45.1, 1.46.0rc1
- **Platform**: Docker


Discussion:

Resolving patch:
diff --git a/synapse/app/generic_worker.py b/synapse/app/generic_worker.py
--- a/synapse/app/generic_worker.py
+++ b/synapse/app/generic_worker.py
@@ -113,6 +113,7 @@
 )
 from synapse.storage.databases.main.presence import PresenceStore
 from synapse.storage.databases.main.room import RoomWorkerStore
+from synapse.storage.databases.main.room_batch import RoomBatchStore
 from synapse.storage.databases.main.search import SearchStore
 from synapse.storage.databases.main.session import SessionStore
 from synapse.storage.databases.main.stats import StatsStore
@@ -240,6 +241,7 @@ class GenericWorkerSlavedStore(
     SlavedEventStore,
     SlavedKeyStore,
     RoomWorkerStore,
+    RoomBatchStore,
     DirectoryStore,
     SlavedApplicationServiceStore,
     SlavedRegistrationStore,
diff --git a/synapse/events/snapshot.py b/synapse/events/snapshot.py
--- a/synapse/events/snapshot.py
+++ b/synapse/events/snapshot.py
@@ -322,6 +322,11 @@ async def _fill_out_state(self) -> None:
         attributes by loading from the database.
         """
         if self.state_group is None:
+            # No state group means the event is an outlier. Usually the state_ids dicts are also
+            # pre-set to empty dicts, but they get reset when the context is serialized, so set
+            # them to empty dicts again here.
+            self._current_state_ids = {}
+            self._prev_state_ids = {}
             return
 
         current_state_ids = await self._storage.state.get_state_ids_for_group(


Test patch: