Skip to content

Commit a6e11db

Browse files
tmmampagent
andauthored
fix(zbugs-swift): start Postgres again when it stops in a kept backend (#124)
zero-cache retries while Postgres refuses connections and catches up once it answers, so the restart from #120 never fires when Postgres is stopped, and Docker's restart: always leaves a container that docker stop stopped alone. With ZBUGS_PG_START, a kept backend runs that command once Postgres has missed three checks 10 seconds apart. Amp-Thread-ID: https://ampcode.com/threads/T-c513a037-a257-45e0-b9a9-15c15edfe859 Co-authored-by: Amp <amp@ampcode.com>
1 parent a0df53f commit a6e11db

2 files changed

Lines changed: 50 additions & 1 deletion

File tree

‎apps/zbugs-swift/README.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ without `ZBUGS_KEEP`, to start over. A kept backend also restarts zero-cache
4343
when zero-cache exits, once Postgres answers again: zero-cache exits when it
4444
loses Postgres, as when the Mac sleeps with Postgres in Docker.
4545

46+
When Postgres stops instead, zero-cache keeps retrying and catches up once
47+
Postgres is back, but nothing brings Postgres back: Docker's `restart: always`
48+
leaves a container that `docker stop` stopped alone. Set `ZBUGS_PG_START` to a
49+
command that starts it, and a kept backend runs it once Postgres has missed
50+
three checks 10 seconds apart:
51+
52+
```sh
53+
ZBUGS_PG_START='docker compose -f apps/zbugs/docker/docker-compose.yml start' \
54+
ZBUGS_KEEP=1 ZBUGS_DIR=~/.zbugs-swift ZBUGS_PG=... \
55+
node apps/zbugs-swift/server/server.ts
56+
```
57+
4658
Then generate the Xcode project and run the `ZBugsApp` scheme on a Mac or an
4759
iOS simulator:
4860

‎apps/zbugs-swift/server/server.ts‎

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
* replica, and its signing keys from the last run instead, so an app keeps
77
* its local data and its token across restarts, and it outlives zero-cache:
88
* when zero-cache exits, as when Postgres is unreachable after this machine
9-
* sleeps, it restarts zero-cache once Postgres answers again.
9+
* sleeps, it restarts zero-cache once Postgres answers again. With
10+
* `ZBUGS_PG_START` it also starts Postgres again when Postgres stops.
1011
*
1112
* node apps/zbugs-swift/server/server.ts
1213
*
@@ -29,6 +30,10 @@
2930
* ZBUGS_KEEP 1 to keep the last run's database, and the replica and
3031
* keys in ZBUGS_DIR, which it needs, and to restart
3132
* zero-cache when it exits
33+
* ZBUGS_PG_START with ZBUGS_KEEP, a shell command that starts Postgres,
34+
* run once Postgres has missed three checks 10 seconds
35+
* apart (for example `docker compose -f
36+
* apps/zbugs/docker/docker-compose.yml start`)
3237
*/
3338
import {execFile, execFileSync, spawn} from 'node:child_process';
3439
import {
@@ -250,6 +255,35 @@ async function postgresAnswers() {
250255
}
251256
}
252257

258+
/**
259+
* zero-cache keeps retrying while Postgres refuses connections and catches
260+
* up once it answers, but nothing starts a stopped Postgres again: Docker's
261+
* `restart: always` leaves a container that `docker stop` stopped alone
262+
* until Docker itself restarts. So a kept backend runs `start` once
263+
* Postgres has missed three checks 10 seconds apart, longer than a Docker
264+
* restart takes, and again after three more.
265+
*/
266+
function watchPostgres(start: string) {
267+
let misses = 0;
268+
const check = async () => {
269+
if (await postgresAnswers()) {
270+
misses = 0;
271+
} else if (++misses === 3) {
272+
misses = 0;
273+
process.stderr.write(
274+
'Postgres is not answering; running ZBUGS_PG_START\n',
275+
);
276+
try {
277+
await promisify(execFile)('/bin/sh', ['-c', start], {timeout: 60_000});
278+
} catch (e) {
279+
process.stderr.write(`ZBUGS_PG_START failed: ${String(e)}\n`);
280+
}
281+
}
282+
setTimeout(check, 10_000);
283+
};
284+
setTimeout(check, 10_000);
285+
}
286+
253287
let ready = false;
254288
let zeroCache = startZeroCache();
255289

@@ -292,3 +326,6 @@ ready = true;
292326
process.stdout.write(
293327
`ready ws://${localHost}:${port} http://${localHost}:${apiPort}\n`,
294328
);
329+
if (keep && env['ZBUGS_PG_START']) {
330+
watchPostgres(env['ZBUGS_PG_START']);
331+
}

0 commit comments

Comments
 (0)