docs: drop the replica-lag testing runbook from the open-source tree

It describes our local two-server MySQL replication setup, which is
internal tooling rather than anything a self-hoster or contributor
needs. It now lives in the heyputer repo alongside the other internal
docs.

The suite it documented stays: the header comment now states the
env-var gate directly instead of pointing at a file this repo no
longer carries.
This commit is contained in:
Juan Castro committed 2026-09-30 17:42:04 -04:00
1 parent 79e496e79d
commit d6b7c8ff52
2 files changed
+2 -109

No files matched your search

-107
View File
@@ -1,107 +0,0 @@
# Testing against a lagging read replica
Some bugs only exist between a primary and a replica that has not caught up:
a row is deleted on the primary, a reader is served the old copy by the
replica, and writes referencing it then fail their foreign keys.
Local development runs on sqlite, which has neither a replica nor foreign-key
enforcement, so neither half of that can happen. Unit tests inject the driver
error instead. This setup runs the real thing: two MySQL servers in actual
replication, where `STOP REPLICA` freezes the follower on demand.
## Setup
Assumes the usual local `puter-mysql` container (mysql:8, port 3306,
`root`/`puter`). Start a follower on 3307:
```bash
docker run -d --name puter-mysql-replica \
-e MYSQL_ROOT_PASSWORD=puter -e MYSQL_DATABASE=puter \
-p 3307:3306 mysql:8 \
--server-id=2 --log-bin=mysql-bin --relay-log=relay-bin
until docker exec puter-mysql-replica mysqladmin -uroot -pputer ping >/dev/null 2>&1
do sleep 2; done
```
Give the primary a replication user:
```bash
docker exec puter-mysql mysql -uroot -pputer -e "
CREATE USER IF NOT EXISTS 'repl'@'%' IDENTIFIED BY 'replpass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;"
```
Seed the follower and point it at the primary. `--source-data=2` records the
binlog coordinates the dump was taken at, which is where the follower starts:
```bash
docker exec puter-mysql mysqldump -uroot -pputer \
--source-data=2 --single-transaction --databases puter > /tmp/primary.sql
grep -m1 'CHANGE REPLICATION SOURCE' /tmp/primary.sql
# -- CHANGE REPLICATION SOURCE TO SOURCE_LOG_FILE='binlog.000006', SOURCE_LOG_POS=717382;
docker exec -i puter-mysql-replica mysql -uroot -pputer < /tmp/primary.sql
PRIMARY_IP=$(docker inspect puter-mysql \
--format '{{.NetworkSettings.Networks.bridge.IPAddress}}')
docker exec puter-mysql-replica mysql -uroot -pputer -e "
STOP REPLICA; RESET REPLICA ALL;
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='${PRIMARY_IP}', SOURCE_PORT=3306,
SOURCE_USER='repl', SOURCE_PASSWORD='replpass',
SOURCE_LOG_FILE='<file from above>', SOURCE_LOG_POS=<pos from above>,
GET_SOURCE_PUBLIC_KEY=1;
START REPLICA;"
```
`GET_SOURCE_PUBLIC_KEY=1` is required because MySQL 8 defaults to
`caching_sha2_password` and this link has no TLS. Confirm both threads are up:
```bash
docker exec puter-mysql-replica mysql -uroot -pputer -e "SHOW REPLICA STATUS\G" \
| grep -E 'Replica_IO_Running|Replica_SQL_Running:|Last_Error'
```
## Running
```bash
PUTER_TEST_REPLICA_LAG=1 npx vitest run \
--config src/backend/vitest.config.ts \
src/backend/stores/replicaLag.integration.test.ts
```
Without the env var the suite skips, so it stays inert in CI and for anyone
without the containers. It builds its own throwaway database
(`puter_replica_lag_verify`), runs the MySQL migrations into it, and drops it
afterwards — your dev data is never touched.
Container names are overridable via `PUTER_TEST_REPLICA_PRIMARY` and
`PUTER_TEST_REPLICA_FOLLOWER`.
## Writing a case
`freeze()` stops replication; everything after it exists only on the primary.
An `afterEach` thaws unconditionally, so a failing assertion cannot strand the
follower and starve later cases of their fixture rows.
```ts
const app = await makeApp(server, user.id);
await settle(); // let the follower catch up
await server.stores.app.getByUid(app.uid); // warm the cache
freeze(); // follower is now behind
await server.stores.app.delete(app.id); // primary only
expect(await server.stores.app.getByUid(app.uid)).toBeNull();
```
## Teardown
```bash
docker rm -f puter-mysql-replica
docker exec puter-mysql mysql -uroot -pputer -e "DROP USER IF EXISTS 'repl'@'%';"
```
@@ -25,8 +25,8 @@
* unit tests inject them, since sqlite has neither a replica nor FK
* enforcement.
*
* Needs both containers, so it is opt-in and skipped in CI — setup and usage in
* doc/testing-replica-lag.md.
* Needs both containers, so it is opt-in behind `PUTER_TEST_REPLICA_LAG` and
* skipped everywhere it is unset, CI included.
*/
import { execFileSync } from 'node:child_process';