Skip to content

Commit abab6cd

Browse files
committed
fix(replication): probe leadership + assert lock keys by slot name
Follow-on to keying the leader lock on slotName: the admin runs-replication status route probed the old name-keyed Redis key (would report leader:false for every source), and the multi-source wiring test asserted the old name-keyed lock keys (CI-red). Both updated to the slot-keyed format.
1 parent cbe81ef commit abab6cd

2 files changed

Lines changed: 16 additions & 11 deletions

File tree

apps/webapp/app/routes/admin.api.v1.runs-replication.status.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ import { getRunsReplicationConfiguredSources } from "~/services/runsReplicationG
77
/**
88
* Probes per-source replication leadership via the redlock leader-lock key, which
99
* is DOUBLE-PREFIXED with `logical-replication-client:` — once from the connection's
10-
* keyPrefix and once from redlock's resource string. So we prefix this connection
11-
* with `runs-replication:logical-replication-client:` and EXISTS on the resource
12-
* `logical-replication-client:runs-replication:<id>`, resolving to:
13-
* runs-replication:logical-replication-client:logical-replication-client:runs-replication:<id>
10+
* keyPrefix and once from redlock's resource string. The lock is keyed on the
11+
* replication slot, so we prefix this connection with
12+
* `runs-replication:logical-replication-client:` and EXISTS on the resource
13+
* `logical-replication-client:<slotName>`, resolving to:
14+
* runs-replication:logical-replication-client:logical-replication-client:<slotName>
1415
*/
15-
async function probeLeadership(sourceIds: string[]): Promise<Map<string, boolean>> {
16+
async function probeLeadership(
17+
sources: { id: string; slotName: string }[]
18+
): Promise<Map<string, boolean>> {
1619
const leaders = new Map<string, boolean>();
1720

1821
const redis = new Redis({
@@ -26,9 +29,9 @@ async function probeLeadership(sourceIds: string[]): Promise<Map<string, boolean
2629
});
2730

2831
try {
29-
for (const id of sourceIds) {
30-
const exists = await redis.exists(`logical-replication-client:runs-replication:${id}`);
31-
leaders.set(id, exists === 1);
32+
for (const source of sources) {
33+
const exists = await redis.exists(`logical-replication-client:${source.slotName}`);
34+
leaders.set(source.id, exists === 1);
3235
}
3336
} finally {
3437
await redis.quit();
@@ -46,7 +49,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
4649
return json({ enabled: false, sources: [] });
4750
}
4851

49-
const leaders = await probeLeadership(sources.map((s) => s.id));
52+
const leaders = await probeLeadership(sources);
5053

5154
return json({
5255
enabled: env.RUN_REPLICATION_ENABLED === "1" && sources.length > 0,

apps/webapp/test/runsReplicationInstance.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,10 +408,12 @@ describe("RunsReplication multi-source wiring (integration)", () => {
408408

409409
probe = new Redis(redisOptions);
410410

411+
// Leader lock is keyed on the slot, so each source holds a distinct
412+
// slot-keyed lock (double-prefixed: connection keyPrefix + redlock resource).
411413
const legacyKey =
412-
"runs-replication:logical-replication-client:logical-replication-client:runs-replication:legacy";
414+
"runs-replication:logical-replication-client:logical-replication-client:tr_legacy_wiring";
413415
const newKey =
414-
"runs-replication:logical-replication-client:logical-replication-client:runs-replication:new";
416+
"runs-replication:logical-replication-client:logical-replication-client:tr_new_wiring";
415417

416418
expect(await probe.exists(legacyKey)).toBe(1);
417419
expect(await probe.exists(newKey)).toBe(1);

0 commit comments

Comments
 (0)