Skip to content

Commit 712d379

Browse files
committed
fix: replace lock-based webhook rejection with timestamp check for chats
Instead of blindly rejecting chat webhooks when the ID is locked, compare updatedAt timestamps and accept the update if the incoming data is more recent than what we have locally.
1 parent 6691ac6 commit 712d379

1 file changed

Lines changed: 52 additions & 18 deletions

File tree

platforms/blabsy/api/src/controllers/WebhookController.ts

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -94,40 +94,47 @@ export class WebhookController {
9494
axios.post(new URL("blabsy", process.env.ANCHR_URL).toString(), req.body)
9595
}
9696

97-
// Early duplicate check
98-
if (adapter.lockedIds.includes(id)) {
97+
const mapping = Object.values(adapter.mapping).find(
98+
(m) => m.schemaId === schemaId,
99+
);
100+
if (!mapping) throw new Error();
101+
const tableName = mapping.tableName + "s";
102+
103+
// For chats, skip the lock check and use timestamp comparison instead
104+
const isChatData = tableName === "chats";
105+
106+
if (!isChatData && adapter.lockedIds.includes(id)) {
99107
console.log(`Webhook skipped - ID ${id} already locked`);
100108
return res.status(200).json({ success: true, skipped: true });
101109
}
102110

103111
console.log(`Processing webhook for ID: ${id}`);
104-
105-
// Lock the global ID immediately to prevent duplicates
106-
adapter.addToLockedIds(id);
107112

108-
const mapping = Object.values(adapter.mapping).find(
109-
(m) => m.schemaId === schemaId,
110-
);
111-
if (!mapping) throw new Error();
112-
const tableName = mapping.tableName + "s";
113+
// Lock the global ID immediately to prevent duplicates (non-chat)
114+
if (!isChatData) {
115+
adapter.addToLockedIds(id);
116+
}
113117

114118
const local = await adapter.fromGlobal({ data, mapping });
115119

116-
console.log("Webhook data received:", {
117-
globalId: id,
118-
tableName,
120+
console.log("Webhook data received:", {
121+
globalId: id,
122+
tableName,
119123
hasEname: !!local.data.ename,
120-
ename: local.data.ename
124+
ename: local.data.ename
121125
});
122-
126+
123127
// Get the local ID from the mapping database
124128
const localId = await adapter.mappingDb.getLocalId(id);
125129

126130
if (localId) {
127131
console.log(`LOCAL, updating - ID: ${id}, LocalID: ${localId}`);
128-
// Lock local ID early to prevent duplicate processing
129-
adapter.addToLockedIds(localId);
130-
await this.updateRecord(tableName, localId, local.data);
132+
if (isChatData) {
133+
await this.updateChatIfNewer(localId, local.data);
134+
} else {
135+
adapter.addToLockedIds(localId);
136+
await this.updateRecord(tableName, localId, local.data);
137+
}
131138
} else {
132139
console.log(`NOT LOCAL, creating - ID: ${id}`);
133140
await this.createRecord(tableName, local.data, req.body.id);
@@ -252,6 +259,33 @@ export class WebhookController {
252259
const mappedData = await this.mapDataToFirebase(tableName, data);
253260
await docRef.update(mappedData);
254261
}
262+
263+
private async updateChatIfNewer(localId: string, data: any) {
264+
const docRef = this.db.collection("chats").doc(localId);
265+
const docSnapshot = await docRef.get();
266+
267+
if (!docSnapshot.exists) {
268+
console.warn(`Chat document '${localId}' does not exist. Skipping update.`);
269+
return;
270+
}
271+
272+
const existing = docSnapshot.data();
273+
const mappedData = this.mapChatData(data, Timestamp.now());
274+
275+
// Compare updatedAt timestamps - accept if incoming is more recent
276+
const existingUpdatedAt = existing?.updatedAt?.toMillis?.() ?? 0;
277+
const incomingUpdatedAt = mappedData.updatedAt?.toMillis?.() ?? 0;
278+
279+
if (incomingUpdatedAt < existingUpdatedAt) {
280+
console.log(`Chat ${localId} webhook skipped - local data is more recent (local: ${existingUpdatedAt}, incoming: ${incomingUpdatedAt})`);
281+
return;
282+
}
283+
284+
adapter.addToLockedIds(localId);
285+
await docRef.update(mappedData);
286+
console.log(`Chat ${localId} updated via webhook (timestamp check passed)`);
287+
}
288+
255289
private mapDataToFirebase(tableName: string, data: any): any {
256290
const now = Timestamp.now();
257291
console.log("MAPPING DATA TO ", tableName);

0 commit comments

Comments
 (0)