From fdfa32055cc578e9a8c00e47e6a0ef77585d5cbd Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Fri, 27 Sep 2024 14:45:31 -0300 Subject: [PATCH] fix: race condition when forwarding livechat by splitting subscription removal (#33381) --- .changeset/dry-taxis-cry.md | 5 +++++ apps/meteor/server/models/raw/BaseRaw.ts | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 .changeset/dry-taxis-cry.md diff --git a/.changeset/dry-taxis-cry.md b/.changeset/dry-taxis-cry.md new file mode 100644 index 000000000000..ae8244087d9e --- /dev/null +++ b/.changeset/dry-taxis-cry.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes a race condition that causes livechat conversations to get stuck in the agent's sidebar panel after being forwarded. diff --git a/apps/meteor/server/models/raw/BaseRaw.ts b/apps/meteor/server/models/raw/BaseRaw.ts index d822038b177e..3e763017bbd3 100644 --- a/apps/meteor/server/models/raw/BaseRaw.ts +++ b/apps/meteor/server/models/raw/BaseRaw.ts @@ -318,33 +318,33 @@ export abstract class BaseRaw< async findOneAndDelete(filter: Filter, options?: FindOneAndDeleteOptions): Promise> { if (!this.trash) { - if (options) { - return this.col.findOneAndDelete(filter, options); - } - return this.col.findOneAndDelete(filter); + return this.col.findOneAndDelete(filter, options || {}); } - const result = await this.col.findOneAndDelete(filter); - - const { value: doc } = result; + const doc = await this.col.findOne(filter); if (!doc) { - return result; + return { ok: 1, value: null }; } const { _id, ...record } = doc; - const trash: TDeleted = { ...record, _deletedAt: new Date(), __collection__: this.name, } as unknown as TDeleted; - // since the operation is not atomic, we need to make sure that the record is not already deleted/inserted await this.trash?.updateOne({ _id } as Filter, { $set: trash } as UpdateFilter, { upsert: true, }); - return result; + try { + await this.col.deleteOne({ _id } as Filter); + } catch (e) { + await this.trash?.deleteOne({ _id } as Filter); + throw e; + } + + return { ok: 1, value: doc }; } async deleteMany(filter: Filter, options?: DeleteOptions & { onTrash?: (record: ResultFields) => void }): Promise {