From c62627427c2a1df12f6a1de7278811e93387d3d7 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Fri, 20 Jun 2025 13:23:34 +0800 Subject: [PATCH] fix(server): save snapshot and delete updates in the same transaction (#12856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close CLOUD-229 #### PR Dependency Tree * **PR #12856** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) ## Summary by CodeRabbit - **Refactor** - Improved the internal handling of document updates and snapshots to enhance reliability and maintainability. No changes to user-facing features or functionality. --- .../server/src/core/doc/storage/doc.ts | 74 +++++++++++-------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/packages/backend/server/src/core/doc/storage/doc.ts b/packages/backend/server/src/core/doc/storage/doc.ts index 5ca396b14..65f7f0a1d 100644 --- a/packages/backend/server/src/core/doc/storage/doc.ts +++ b/packages/backend/server/src/core/doc/storage/doc.ts @@ -1,4 +1,5 @@ import { Logger } from '@nestjs/common'; +import { Transactional } from '@nestjs-cls/transactional'; import { applyUpdate, diffUpdate, @@ -78,42 +79,55 @@ export abstract class DocStorageAdapter extends Connection { const updates = await this.getDocUpdates(spaceId, docId); if (updates.length) { - this.logger.log( - `Squashing updates, spaceId: ${spaceId}, docId: ${docId}, updates: ${updates.length}` - ); - const { timestamp, bin, editor } = await this.squash( - snapshot ? [snapshot, ...updates] : updates - ); - - const newSnapshot = { - spaceId: spaceId, + return await this.squashUpdatesToSnapshot( + spaceId, docId, - bin, - timestamp, - editor, - }; - - const success = await this.setDocSnapshot(newSnapshot); - - // if there is old snapshot, create a new history record - if (success && snapshot) { - await this.createDocHistory(snapshot); - } - - // always mark updates as merged unless throws - const count = await this.markUpdatesMerged(spaceId, docId, updates); - if (count > 0) { - this.logger.log( - `Marked ${count} updates as merged, spaceId: ${spaceId}, docId: ${docId}` - ); - } - - return newSnapshot; + updates, + snapshot + ); } return snapshot; } + @Transactional() + private async squashUpdatesToSnapshot( + spaceId: string, + docId: string, + updates: DocUpdate[], + snapshot: DocRecord | null + ) { + this.logger.log( + `Squashing updates, spaceId: ${spaceId}, docId: ${docId}, updates: ${updates.length}` + ); + const { timestamp, bin, editor } = await this.squash( + snapshot ? [snapshot, ...updates] : updates + ); + + const newSnapshot: DocRecord = { + spaceId, + docId, + bin, + timestamp, + editor, + }; + + const success = await this.setDocSnapshot(newSnapshot); + + // if there is old snapshot, create a new history record + if (success && snapshot) { + await this.createDocHistory(snapshot); + } + + // always mark updates as merged unless throws + const count = await this.markUpdatesMerged(spaceId, docId, updates); + this.logger.log( + `Marked ${count} updates as merged, spaceId: ${spaceId}, docId: ${docId}, timestamp: ${timestamp}` + ); + + return newSnapshot; + } + async getDocDiff( spaceId: string, docId: string,