Skip to content

Commit 7b817ef

Browse files
committed
chore: implement transactional dual-write
1 parent e722c08 commit 7b817ef

File tree

1 file changed

+26
-2
lines changed
  • controlplane/src/core/blobstorage

1 file changed

+26
-2
lines changed

controlplane/src/core/blobstorage/dual.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,35 @@ export class DualBlobStorage implements BlobStorage {
1919
contentType: string;
2020
metadata?: Metadata;
2121
}): Promise<void> {
22-
await Promise.all([this.primary.putObject(data), this.secondary.putObject(data)]);
22+
const results = await Promise.allSettled([this.primary.putObject(data), this.secondary.putObject(data)]);
23+
const [primaryResult, secondaryResult] = results;
24+
25+
if (primaryResult.status === 'fulfilled' && secondaryResult.status === 'fulfilled') {
26+
return;
27+
}
28+
29+
// Roll back successful writes before throwing
30+
if (primaryResult.status === 'fulfilled') {
31+
await this.primary.deleteObject({ key: data.key, abortSignal: data.abortSignal });
32+
}
33+
if (secondaryResult.status === 'fulfilled') {
34+
await this.secondary.deleteObject({ key: data.key, abortSignal: data.abortSignal });
35+
}
36+
37+
const errors = results.filter((r): r is PromiseRejectedResult => r.status === 'rejected').map((r) => r.reason);
38+
throw new AggregateError(errors, 'Failed to put object into storage');
2339
}
2440

2541
async getObject(data: { key: string; abortSignal?: AbortSignal }): Promise<BlobObject> {
26-
return await Promise.any([this.primary.getObject(data), this.secondary.getObject(data)]);
42+
try {
43+
return await this.primary.getObject(data);
44+
} catch (primaryError) {
45+
try {
46+
return await this.secondary.getObject(data);
47+
} catch (secondaryError) {
48+
throw new AggregateError([primaryError, secondaryError], 'Both primary and secondary storage failed to get object');
49+
}
50+
}
2751
}
2852

2953
async removeDirectory(data: { key: string; abortSignal?: AbortSignal }): Promise<number> {

0 commit comments

Comments
 (0)