Previously, diagram saves (for example, during realtime collaboration) would follow these steps:
The server would receive a change from a client
The server would load the diagram
The server would apply the changes
The server would save the diagram and broadcast the changes
Since updating diagrams was not atomic, there was a potential for clashes while updating a diagram: for example an update could be initiated by another client while the server is between steps 2 and 4, resulting in corrupted stored data.
This PR changes the process to enable atomic updates, resolving this issue:
The server will receive a change from a client
The server atomically updates the diagram
The server broadcasts the change
The DiagramStorageService interface is updated with two additional methods:
export interface DiagramStorageService {
saveDiagram(diagramDTO: DiagramDTO, token: string): Promise<string>;
getDiagramByLink(token: string): Promise<DiagramDTO | undefined>;
// 👇 these methods are added via this PR
patchDiagram(token: string, patch: Operation[]): Promise<void>;
diagramExists(token: string): Promise<boolean>;
}
DiagramFileStorageService provides implementations for both of these methods. It will rate limit calls to saveDiagram() and calls to patchDiagram() in a single queue, as the purpose of the rate limiting is to avoid frequently modifying the diagram files on the filesystem regardless of the nature of the change (i.e. a patch will be overwritten by a following save and vice-versa, so they should be debounced w.r.t. each other).
Previously, diagram saves (for example, during realtime collaboration) would follow these steps:
Since updating diagrams was not atomic, there was a potential for clashes while updating a diagram: for example an update could be initiated by another client while the server is between steps 2 and 4, resulting in corrupted stored data.
This PR changes the process to enable atomic updates, resolving this issue:
The
DiagramStorageService
interface is updated with two additional methods:DiagramFileStorageService
provides implementations for both of these methods. It will rate limit calls tosaveDiagram()
and calls topatchDiagram()
in a single queue, as the purpose of the rate limiting is to avoid frequently modifying the diagram files on the filesystem regardless of the nature of the change (i.e. a patch will be overwritten by a following save and vice-versa, so they should be debounced w.r.t. each other).