Follow-up to https://github.com/matrix-org/matrix-public-archive/pull/36
Render pipeline separation of concerns:
1. Run in `child_process`
2. Hydrogen render
It's now just a generic `child_process` runner that runs the Hydrogen render in it. This eliminates the windy path of the 1-4 steps that was only held together by the file names themselves.
Follow-up to https://github.com/matrix-org/matrix-public-archive/pull/51
Better `child_process` error handling for a couple scenarios with the finger pointing at it 👉
Also make sure we handle all of these scenarios:
1. Child process fork script throws an `uncaughtException` or `unhandledRejection`
- These are captured and serialized back to the parent and stored in `childErrors` and exposed if we never get a successful rendered HTML response.
2. Child process fails to startup
- Render process is rejected in the `child.on('error', ...` callback
3. 👉 Child process times out and is aborted
- Render process is rejected in the `child.on('error', ...` callback and any `childErrors` encountered are logged
4. 👉 Child process fork script throws an error in scope of in `process.on('message', async (renderOptions) => {`
- Child exits with code 1 and we reject the render process with the error
5. Child process exits with code 1 (error)
- Render process is rejected with any `childError` info
6. Child process exits with code 0 (success) but never sends back any HTML
- We have a `returnedData` data check and any child errors encountered are logged
Add test to make sure the archive doesn't fail when event for event relation is missing and not included in list of provided events. Like if someone is replying to an event that was from long ago out of our range.
In the case of missing relations, Hydrogen does `_loadContextEntryNotInTimeline` because it can't find the event locally which throws an `uncaughtException`. Before https://github.com/matrix-org/matrix-public-archive/pull/51, the `uncaughtException` killed the Hydrogen `child_process` before it could pass back the HTML. Now this PR mainly just adds a test to make sure it works.
```
TypeError: Cannot read properties of undefined (reading 'storeNames')
at TimelineReader.readById (hydrogen-web\target\lib-build\hydrogen.cjs.js:12483:33)
at Timeline._getEventFromStorage (hydrogen-web\target\lib-build\hydrogen.cjs.js:12762:46)
at Timeline._loadContextEntryNotInTimeline (hydrogen-web\target\lib-build\hydrogen.cjs.js:12747:35)
at Timeline._loadContextEntriesWhereNeeded (hydrogen-web\target\lib-build\hydrogen.cjs.js:12741:14)
at Timeline.addEntries (hydrogen-web\target\lib-build\hydrogen.cjs.js:12699:10)
at mountHydrogen (4-hydrogen-vm-render-script.js:204:12)
at 4-hydrogen-vm-render-script.js:353:1
at Script.runInContext (node:vm:139:12)
at _renderHydrogenToStringUnsafe (matrix-public-archive\server\hydrogen-render\3-render-hydrogen-to-string-unsafe.js:102:41)
at async process.<anonymous> (matrix-public-archive\server\hydrogen-render\2-render-hydrogen-to-string-fork-script.js:18:27)
```
Split off from https://github.com/matrix-org/matrix-public-archive/pull/43
Listen to `process.on('uncaughtException', ...)` and handle the async errors ourselves so it no longer fails the child process.
And if the process does exit with status code 1 (error), we have those underlying errors serialized and shown.
We now run the Hydrogen render in a `child_process` so we can exit the whole render process. We still use the `vm` to setup the browser-like globals. With a `vm`, everything continues to run even after it returns and there isn't a way to clean up, stop, kill, terminate the vm script or context so we need this extra `child_process` now to clean up. I don't like the complexity necessary for this though. I wish the `vm` API allowed for this use case. The only way to stop a `vm` is the `timeout` and we want to stop as soon as we return.
Fix https://github.com/matrix-org/matrix-public-archive/issues/34