@ouro.bot/cli 0.1.0-alpha.480 → 0.1.0-alpha.481
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/changelog.json +8 -0
- package/dist/mailroom/blob-store.js +23 -8
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.481",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Hosted Blob message downloads now retry once on transient timeout or socket-close failures, so rerunning a delegated HEY archive import does not die on the first flaky duplicate-check read.",
|
|
8
|
+
"Azure Blob mail-store coverage now locks the real duplicate-dedupe retry path that failed in production, keeping historical import reruns resilient while preserving bounded timeout behavior for genuinely stalled blobs.",
|
|
9
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper stay version-synced for the hosted mail import retry hardening release."
|
|
10
|
+
]
|
|
11
|
+
},
|
|
4
12
|
{
|
|
5
13
|
"version": "0.1.0-alpha.480",
|
|
6
14
|
"changes": [
|
|
@@ -9,6 +9,7 @@ const MESSAGE_INDEX_SORT_MAX_MS = 9_999_999_999_999;
|
|
|
9
9
|
const MESSAGE_INDEX_SORT_WIDTH = 13;
|
|
10
10
|
const MESSAGE_INDEX_NO_SOURCE = "~";
|
|
11
11
|
const DEFAULT_BLOB_OPERATION_TIMEOUT_MS = 20_000;
|
|
12
|
+
const DEFAULT_BLOB_DOWNLOAD_ATTEMPTS = 2;
|
|
12
13
|
const DEFAULT_MESSAGE_FETCH_CONCURRENCY = 20;
|
|
13
14
|
const DEFAULT_MESSAGE_INDEX_BACKFILL_CONCURRENCY = 8;
|
|
14
15
|
const MESSAGE_LIST_SCAN_CONCURRENCY = 32;
|
|
@@ -64,18 +65,32 @@ function normalizeBlobOperationError(action, blob, timeoutMs, error) {
|
|
|
64
65
|
}
|
|
65
66
|
return new Error(`${action} ${blobClientName(blob)} failed: ${message}`);
|
|
66
67
|
}
|
|
68
|
+
function isRetryableBlobDownloadError(error) {
|
|
69
|
+
const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
|
|
70
|
+
return message.includes("timed out") ||
|
|
71
|
+
message.includes("abort") ||
|
|
72
|
+
message.includes("econnreset") ||
|
|
73
|
+
message.includes("etimedout") ||
|
|
74
|
+
message.includes("socket closed");
|
|
75
|
+
}
|
|
67
76
|
async function downloadJson(blob, timeoutMs) {
|
|
68
77
|
if (!await blob.exists())
|
|
69
78
|
return null;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
let lastError = null;
|
|
80
|
+
for (let attempt = 1; attempt <= DEFAULT_BLOB_DOWNLOAD_ATTEMPTS; attempt += 1) {
|
|
81
|
+
try {
|
|
82
|
+
const buffer = await withBlobOperationTimeout(timeoutMs, (abortSignal) => {
|
|
83
|
+
return blob.downloadToBuffer(undefined, undefined, { abortSignal });
|
|
84
|
+
});
|
|
85
|
+
return JSON.parse(buffer.toString("utf-8"));
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
lastError = error;
|
|
89
|
+
if (attempt >= DEFAULT_BLOB_DOWNLOAD_ATTEMPTS || !isRetryableBlobDownloadError(error))
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
78
92
|
}
|
|
93
|
+
throw normalizeBlobOperationError("download", blob, timeoutMs, lastError);
|
|
79
94
|
}
|
|
80
95
|
async function uploadJson(blob, value, timeoutMs) {
|
|
81
96
|
try {
|