Skip to content

Commit d3fa038

Browse files
fix: ensure CSR works with a capped collection
The findOneAndDelete() operation is not authorized on a capped collection, so the connection state recovery would always fail when fetching the session. > MongoServerError: cannot remove from a capped collection Related: #20
1 parent 0c80f7f commit d3fa038

File tree

2 files changed

+422
-124
lines changed

2 files changed

+422
-124
lines changed

lib/index.ts

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -806,28 +806,22 @@ export class MongoAdapter extends Adapter {
806806
try {
807807
results = await Promise.all([
808808
// could use a sparse index on [data.pid] (only index the documents whose type is EventType.SESSION)
809-
this.mongoCollection.findOneAndDelete({
810-
type: EventType.SESSION,
811-
"data.pid": pid,
812-
}),
809+
this.findSession(pid),
813810
this.mongoCollection.findOne({
814811
type: EventType.BROADCAST,
815812
_id: eventOffset,
816813
}),
817814
]);
818815
} catch (e) {
816+
debug("error while fetching session: %s", (e as Error).message);
819817
return Promise.reject("error while fetching session");
820818
}
821819

822-
const result = (results[0]?.ok
823-
? results[0].value // mongodb@5
824-
: results[0]) as unknown as WithId<Document>; // mongodb@6
825-
826-
if (!result || !results[1]) {
820+
if (!results[0] || !results[1]) {
827821
return Promise.reject("session or offset not found");
828822
}
829823

830-
const session = result.data;
824+
const session = results[0].data;
831825

832826
// could use a sparse index on [_id, nsp, data.opts.rooms, data.opts.except] (only index the documents whose type is EventType.BROADCAST)
833827
const cursor = this.mongoCollection.find({
@@ -889,4 +883,54 @@ export class MongoAdapter extends Adapter {
889883

890884
return session;
891885
}
886+
887+
private findSession(
888+
pid: PrivateSessionId
889+
): Promise<WithId<Document> | undefined> {
890+
const isCollectionCapped = !this.addCreatedAtField;
891+
if (isCollectionCapped) {
892+
return this.mongoCollection
893+
.findOne(
894+
{
895+
type: EventType.SESSION,
896+
"data.pid": pid,
897+
},
898+
{
899+
sort: {
900+
_id: -1,
901+
},
902+
}
903+
)
904+
.then((result) => {
905+
if (!result) {
906+
debug("session not found");
907+
return;
908+
}
909+
910+
if (result.data.sid) {
911+
debug("session found, adding tombstone");
912+
913+
// since the collection is capped, we cannot remove documents from it, so we add a tombstone to prevent recovering the same session twice
914+
// note: we could also have used two distinct collections, one for the events (capped) and the other for the sessions (not capped, with a TTL)
915+
const TOMBSTONE_SESSION = { pid, tombstone: true };
916+
this.persistSession(TOMBSTONE_SESSION);
917+
918+
return result;
919+
} else {
920+
debug("tombstone session found");
921+
}
922+
});
923+
} else {
924+
return this.mongoCollection
925+
.findOneAndDelete({
926+
type: EventType.SESSION,
927+
"data.pid": pid,
928+
})
929+
.then((result) => {
930+
return result?.ok && result.value
931+
? result.value // mongodb@5
932+
: (result as unknown as WithId<Document>); // mongodb@6
933+
});
934+
}
935+
}
892936
}

0 commit comments

Comments
 (0)