Skip to content

Commit 96472fe

Browse files
committed
AUT-5433: Add enhanced consistency checks
This code, along with the rest of the dual session store, will be torn down and deleted once the migration is completed.
1 parent 428f87c commit 96472fe

2 files changed

Lines changed: 90 additions & 0 deletions

File tree

src/config/dual-session-store.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,16 @@ export class DualSessionStore extends Store {
189189
if (
190190
!isDeepStrictEqual(primarySession ?? null, secondarySession ?? null)
191191
) {
192+
const mismatchDetails = this.getKeyDiffs(
193+
primarySession,
194+
secondarySession
195+
);
192196
logger.warn(
193197
{
194198
sid,
195199
primaryExists: !!primarySession,
196200
secondaryExists: !!secondarySession,
201+
mismatchDetails,
197202
},
198203
"Session consistency mismatch"
199204
);
@@ -202,4 +207,67 @@ export class DualSessionStore extends Store {
202207
logger.warn({ err }, "Error performing session store consistency checks");
203208
}
204209
}
210+
211+
private getKeyDiffs(
212+
primary: SessionData | null,
213+
secondary: SessionData | null
214+
): {
215+
keysOnlyInPrimary: string[];
216+
keysOnlyInSecondary: string[];
217+
keysDiffering: string[];
218+
} {
219+
const primaryKeys = primary ? Object.keys(primary) : [];
220+
const secondaryKeys = secondary ? Object.keys(secondary) : [];
221+
const allKeys = Array.from(new Set(primaryKeys.concat(secondaryKeys)));
222+
223+
const keysOnlyInPrimary: string[] = [];
224+
const keysOnlyInSecondary: string[] = [];
225+
const keysDiffering: string[] = [];
226+
227+
for (const key of allKeys) {
228+
const inPrimary = primary && key in primary;
229+
const inSecondary = secondary && key in secondary;
230+
231+
if (inPrimary && !inSecondary) {
232+
keysOnlyInPrimary.push(key);
233+
} else if (!inPrimary && inSecondary) {
234+
keysOnlyInSecondary.push(key);
235+
} else if (
236+
!isDeepStrictEqual(
237+
primary[key as keyof SessionData],
238+
secondary[key as keyof SessionData]
239+
)
240+
) {
241+
const subDiffs = this.getDifferingPaths(
242+
primary[key as keyof SessionData],
243+
secondary[key as keyof SessionData],
244+
key
245+
);
246+
keysDiffering.push(...subDiffs);
247+
}
248+
}
249+
250+
return { keysOnlyInPrimary, keysOnlyInSecondary, keysDiffering };
251+
}
252+
253+
private getDifferingPaths(a: unknown, b: unknown, prefix: string): string[] {
254+
if (
255+
a &&
256+
b &&
257+
typeof a === "object" &&
258+
typeof b === "object" &&
259+
!Array.isArray(a) &&
260+
!Array.isArray(b)
261+
) {
262+
const aObj = a as Record<string, unknown>;
263+
const bObj = b as Record<string, unknown>;
264+
const keys = Array.from(
265+
new Set(Object.keys(aObj).concat(Object.keys(bObj)))
266+
);
267+
return keys
268+
.filter((k) => !isDeepStrictEqual(aObj[k], bObj[k]))
269+
.map((k) => `${prefix}.${k}`);
270+
}
271+
return [prefix];
272+
}
205273
}

test/unit/dual-session-store.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,5 +342,27 @@ describe("DualSessionStore", () => {
342342
setTimeout(done, 10);
343343
});
344344
});
345+
346+
it("should safely handle key diffs with missing keys and nested differences", (done) => {
347+
const primarySession = {
348+
cookie: { originalMaxAge: 3600000 },
349+
user: { id: 7777, role: "admin" },
350+
token: "tokenValueOnlyInPrimary",
351+
} as unknown as SessionData;
352+
const secondarySession = {
353+
cookie: { originalMaxAge: 9999 },
354+
user: { id: 7777, role: "user" },
355+
extra: "extraValueOnlyInSecondary",
356+
} as unknown as SessionData;
357+
primary.get = sinon.fake((_sid, cb) => cb(null, primarySession));
358+
secondary.get = sinon.fake((_sid, cb) => cb(null, secondarySession));
359+
store = new DualSessionStore(primary, secondary, "Redis", "DynamoDB");
360+
361+
store.get(sid, (err, sess) => {
362+
expect(err).to.be.null;
363+
expect(sess).to.deep.equal(primarySession);
364+
setTimeout(done, 10);
365+
});
366+
});
345367
});
346368
});

0 commit comments

Comments
 (0)