openvibers/openvibe.host Commits

Host: a data switch stops a socket-activated service's socket too; ov_live gets its own PgBouncer pool (#36)

OP OpenVibers committed 8 Oct 2026 · 903db10090 · 3 files, +12 −3

Live's switch on 2026-10-08: with only openvibe-live.service stopped, the next request through openvibe-live.socket started the old release again, which wrote analytics.db while the import read it (the verify caught it and the switch rolled back). switchEnv now adds the inventory's socketUnit after the service (the first unit still runs the import); the deploy's restart brings the socket back through the service's Requires=. pgbouncer.ini records the ov_live pool set on the host (pool_size 10, max_db_connections 20).


Claude-Session: https://claude.ai/code/session_01K8AYn3FF3HE7CPfM262qdh

Co-authored-by: Claude Opus 5.5 <[email protected]>

Changes

ddiff --git a/lib/commands/data.js b/lib/commands/data.js
iindex 5a172cd..3da5e3f 100644
---- a/lib/commands/data.js
++++ b/lib/commands/data.js
@@@ -44,6 +44,11 @@ function switchEnv(svc) {
const units = [...svc.units, ...svc.workerUnits].map(unitPattern);
// Deploys restart every unit matching unitsMatch (release-ops), so the switch stops them too.
if (svc.unitsMatch && !units.includes(svc.unitsMatch)) units.push(svc.unitsMatch);
++ // A socket-activated service comes straight back on the next request while its socket listens: the old
++ // release would write the database during the import (2026-10-08, Live: analytics rows moved under the verify).
++ // The socket is stopped after the service (the first unit stays the one whose environment runs the import); the
++ // deploy's restart starts it again through the service's Requires=.
++ if (svc.socketUnit && !units.includes(svc.socketUnit)) units.push(svc.socketUnit);
if (units.length) env.SWITCH_UNITS = units.join(' ');
env.SWITCH_DIR = svc.repo;
return env;
ddiff --git a/roles/data/files/pgbouncer.ini b/roles/data/files/pgbouncer.ini
iindex 5a5c3dc..69e5d39 100644
---- a/roles/data/files/pgbouncer.ini
++++ b/roles/data/files/pgbouncer.ini
@@@ -1,6 +1,8 @@
; OpenVibe data role (ADR-035): PgBouncer in transaction-pooling mode (ADR-007 2026-09-24 rule 1).
; Applications use DATABASE_URL (port 6432); migrations use DATABASE_DIRECT_URL (port 5432).
[databases]
++; Live is the busiest service (chat, viewers, analytics): its own pool, above the default 5 (2026-10-08, plan T4).
++ov_live = host=127.0.0.1 port=5432 pool_size=10 max_db_connections=20
* = host=127.0.0.1 port=5432
[pgbouncer]
ddiff --git a/test/data-provision.test.js b/test/data-provision.test.js
iindex 86a2fe5..abd03cb 100644
---- a/test/data-provision.test.js
++++ b/test/data-provision.test.js
@@@ -101,7 +101,9 @@ runTests([
assert.strictEqual(r.code, 0, r.out);
assert.deepStrictEqual(runs[0].args, ['live']);
assert.strictEqual(runs[0].env.SWITCH_DIR, '/opt/openvibe.live');
-- assert.strictEqual(runs[0].env.SWITCH_UNITS, 'openvibe-live.service');
++ // Live is socket-activated: its socket is stopped too (after the service), or the next request starts the old
++ // release again while the import runs.
++ assert.strictEqual(runs[0].env.SWITCH_UNITS, 'openvibe-live.service openvibe-live.socket');
}),
test('switch also stops the units matching unitsMatch', async () => {
@@@ -112,7 +114,7 @@ runTests([
const runs = installScripts(host);
const r = await cli(host, 'data', 'switch', 'live');
assert.strictEqual(r.code, 0, r.out);
-- assert.strictEqual(runs[0].env.SWITCH_UNITS, 'openvibe-live.service openvibe-live*.service');
++ assert.strictEqual(runs[0].env.SWITCH_UNITS, 'openvibe-live.service openvibe-live*.service openvibe-live.socket');
}),
test('without root both are refused and nothing runs (sudo would drop SWITCH_UNITS/SWITCH_DIR)', async () => {
@@@ -139,7 +141,7 @@ runTests([
const s = await cli(host, 'data', 'switch', 'live', '--sqlite', '/var/lib/openvibe-live/live.db', '--dry-run');
assert.strictEqual(s.code, 0, s.out);
-- assert.match(s.out, /would run: SWITCH_UNITS="openvibe-live\.service" SWITCH_DIR="\/opt\/openvibe\.live" \/opt\/ovhost-install\/roles\/data\/switch-service\.sh "live" "\/var\/lib\/openvibe-live\/live\.db"/);
++ assert.match(s.out, /would run: SWITCH_UNITS="openvibe-live\.service openvibe-live\.socket" SWITCH_DIR="\/opt\/openvibe\.live" \/opt\/ovhost-install\/roles\/data\/switch-service\.sh "live" "\/var\/lib\/openvibe-live\/live\.db"/);
assert.deepStrictEqual(runs, []);
}),