@frockbot/workspace-store 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/store.test.ts +13 -5
- package/src/store.ts +18 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frockbot/workspace-store",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@frockbot/kernel-contracts": "0.3.
|
|
18
|
+
"@frockbot/kernel-contracts": "0.3.7"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/bun": "1.4.0",
|
package/src/store.test.ts
CHANGED
|
@@ -680,11 +680,14 @@ describe("an unrecorded file is still overwritable by the writer that read it",
|
|
|
680
680
|
// The `record` that follows a `put` fails once: the bytes land, and the
|
|
681
681
|
// only place their generation exists is beside them in the object store.
|
|
682
682
|
const record = generations.record;
|
|
683
|
-
let
|
|
683
|
+
let attempts = 0;
|
|
684
684
|
generations.record = (entry) => {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
685
|
+
attempts += 1;
|
|
686
|
+
// Both attempts fail: the retry is not what is under test here.
|
|
687
|
+
if (attempts <= 2) {
|
|
688
|
+
return Promise.reject(new Error("the ledger is unreachable"));
|
|
689
|
+
}
|
|
690
|
+
return record(entry);
|
|
688
691
|
};
|
|
689
692
|
|
|
690
693
|
const first = await files.write({
|
|
@@ -693,7 +696,12 @@ describe("an unrecorded file is still overwritable by the writer that read it",
|
|
|
693
696
|
writer: user,
|
|
694
697
|
expectedGenerationId: null,
|
|
695
698
|
});
|
|
696
|
-
|
|
699
|
+
// The bytes are durable, so the write is `ok`. Reporting a failure here
|
|
700
|
+
// told the model nothing was written while object storage held it, and
|
|
701
|
+
// the write then turned up in the next injection anyway.
|
|
702
|
+
expect(first).toMatchObject({ status: "ok", ledgerPending: true });
|
|
703
|
+
// It is tried twice before it is called pending.
|
|
704
|
+
expect(attempts).toBe(2);
|
|
697
705
|
expect(await generations.current(INSTRUCTIONS, "notes.md")).toBeUndefined();
|
|
698
706
|
|
|
699
707
|
// The file reads back with the generation its writer minted…
|
package/src/store.ts
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
// and `gcTombstoneMarkersV1` collects markers old enough that no create can
|
|
45
45
|
// still be conditioned on one.
|
|
46
46
|
import {
|
|
47
|
+
retryOnceV1,
|
|
47
48
|
WORKSPACE_MAX_FILE_BYTES,
|
|
48
49
|
WORKSPACE_MAX_LIST_ENTRIES,
|
|
49
50
|
isWorkspaceComputerReadOnlyRootV1,
|
|
@@ -613,19 +614,25 @@ class ObjectWorkspaceFiles implements WorkspaceFilesV1 {
|
|
|
613
614
|
);
|
|
614
615
|
}
|
|
615
616
|
if (written) {
|
|
617
|
+
// The bytes are durable. The ledger is the index of that fact, not
|
|
618
|
+
// the fact: reporting a failure here told the model nothing was
|
|
619
|
+
// written while object storage held it, and the write then turned up
|
|
620
|
+
// in the next injection anyway — exactly the intent/outcome
|
|
621
|
+
// divergence the record exists to prevent. So the ledger call is
|
|
622
|
+
// retried, and a still-failing ledger is `ok` with `ledgerPending`:
|
|
623
|
+
// the metadata beside the bytes lets `reconcile` repair the entry.
|
|
616
624
|
try {
|
|
617
|
-
await
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
return failure(
|
|
626
|
-
"unavailable",
|
|
627
|
-
error instanceof Error ? error.message : String(error),
|
|
625
|
+
await retryOnceV1(() =>
|
|
626
|
+
this.generations.record({
|
|
627
|
+
schemaVersion: 1,
|
|
628
|
+
root,
|
|
629
|
+
path: relative,
|
|
630
|
+
generation,
|
|
631
|
+
etag: written.etag,
|
|
632
|
+
}),
|
|
628
633
|
);
|
|
634
|
+
} catch {
|
|
635
|
+
return { status: "ok", generation, ledgerPending: true };
|
|
629
636
|
}
|
|
630
637
|
return { status: "ok", generation };
|
|
631
638
|
}
|