fix(test): wait for swarm convergence before idempotency re-check

setupMonitoring's "is idempotent" test calls it twice back to back.
Swarm keeps converging a freshly created service (scheduling tasks,
resolving endpoints), which bumps Version.Index on its own shortly
after creation. If that bump lands between the second call's inspect()
and update(), Docker rejects it with "update out of sequence" even
though nothing else touched the service.

This never happens in production — setupMonitoring is only triggered
by a UI button click or once during server setup, both far enough
apart in wall-clock time for Swarm to settle. So the fix stays in the
test: wait for two consecutive Version.Index reads to agree before
making the second call.
This commit is contained in:
Narciso 2026-08-31 16:38:16 -04:00
parent 1ff9294009
commit cee950b6c8

View File

@ -64,6 +64,21 @@ const serviceExists = async (name: string) => {
}
};
// Swarm keeps converging a service for a bit after it's created (scheduling
// tasks, resolving endpoints), which bumps Version.Index on its own. Calling
// setupMonitoring again before that settles races that internal bump, so wait
// for two consecutive reads to agree before treating the service as stable.
const waitForServiceConvergence = async (name: string, timeoutMs = 5000) => {
const deadline = Date.now() + timeoutMs;
let lastIndex: string | null = null;
while (Date.now() < deadline) {
const inspect = await docker.getService(name).inspect();
if (inspect.Version.Index === lastIndex) return;
lastIndex = inspect.Version.Index;
await new Promise((resolve) => setTimeout(resolve, 50));
}
};
const swarmTaskNames = async () => {
const list = await docker.listContainers({ all: true });
return list
@ -193,6 +208,7 @@ describe.skipIf(hasRealMonitoring())(
expect(await containerExists(SERVICE_NAME)).toBe(false);
await expect(setupMonitoring("test-server")).resolves.not.toThrow();
await waitForServiceConvergence(SERVICE_NAME);
await expect(setupMonitoring("test-server")).resolves.not.toThrow();
expect(await serviceExists(SERVICE_NAME)).toBe(true);