fix(server): save snapshot and delete updates in the same transaction (#12856)

close CLOUD-229



#### PR Dependency Tree


* **PR #12856** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## 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.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
fengmk2
2025-06-20 13:23:34 +08:00
committed by GitHub
parent eb5a2ffe05
commit c62627427c

View File

@@ -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,