@c3-oss/prosa 0.8.0 → 0.8.1
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/dist/bin/prosa.js +233 -68
- package/dist/bin/prosa.js.map +1 -1
- package/dist/cli/main.js +233 -68
- package/dist/cli/main.js.map +1 -1
- package/package.json +2 -2
package/dist/bin/prosa.js
CHANGED
|
@@ -28398,8 +28398,9 @@ import path2 from "path";
|
|
|
28398
28398
|
import { request as httpRequest } from "http";
|
|
28399
28399
|
import { request as httpsRequest } from "https";
|
|
28400
28400
|
import { OBJECT_PACK_BINARY_CONTENT_TYPE, encodeBinaryObjectPack } from "@c3-oss/prosa-sync";
|
|
28401
|
-
var OBJECT_UPLOAD_MAX_ATTEMPTS =
|
|
28402
|
-
var OBJECT_UPLOAD_BASE_BACKOFF_MS =
|
|
28401
|
+
var OBJECT_UPLOAD_MAX_ATTEMPTS = 6;
|
|
28402
|
+
var OBJECT_UPLOAD_BASE_BACKOFF_MS = 500;
|
|
28403
|
+
var OBJECT_UPLOAD_MAX_BACKOFF_MS = 15e3;
|
|
28403
28404
|
function trimTrailingSlash(url) {
|
|
28404
28405
|
return url.endsWith("/") ? url.slice(0, -1) : url;
|
|
28405
28406
|
}
|
|
@@ -28424,7 +28425,8 @@ __name(retryAfterMs, "retryAfterMs");
|
|
|
28424
28425
|
function objectUploadBackoffMs(attempt, headers) {
|
|
28425
28426
|
const retryAfter = headers ? retryAfterMs(headers) : void 0;
|
|
28426
28427
|
if (retryAfter !== void 0) return retryAfter;
|
|
28427
|
-
|
|
28428
|
+
const exponential = Math.min(OBJECT_UPLOAD_MAX_BACKOFF_MS, OBJECT_UPLOAD_BASE_BACKOFF_MS * 2 ** attempt);
|
|
28429
|
+
return Math.floor(exponential + Math.random() * Math.min(250, exponential));
|
|
28428
28430
|
}
|
|
28429
28431
|
__name(objectUploadBackoffMs, "objectUploadBackoffMs");
|
|
28430
28432
|
function isRetryableObjectUploadStatus(status) {
|
|
@@ -28438,10 +28440,21 @@ function isRetryableNetworkError(err) {
|
|
|
28438
28440
|
return code != null && [
|
|
28439
28441
|
"ECONNRESET",
|
|
28440
28442
|
"ETIMEDOUT",
|
|
28441
|
-
"EPIPE"
|
|
28443
|
+
"EPIPE",
|
|
28444
|
+
"ECONNREFUSED",
|
|
28445
|
+
"UND_ERR_SOCKET",
|
|
28446
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
28442
28447
|
].includes(code);
|
|
28443
28448
|
}
|
|
28444
28449
|
__name(isRetryableNetworkError, "isRetryableNetworkError");
|
|
28450
|
+
function networkErrorReason(err) {
|
|
28451
|
+
if (err instanceof Error) {
|
|
28452
|
+
const code = err.code ?? err.cause?.code;
|
|
28453
|
+
return code ? `${err.message} (${code})` : err.message;
|
|
28454
|
+
}
|
|
28455
|
+
return String(err);
|
|
28456
|
+
}
|
|
28457
|
+
__name(networkErrorReason, "networkErrorReason");
|
|
28445
28458
|
function isUnsupportedBinaryObjectPackResponse(status, text) {
|
|
28446
28459
|
return status === 415 || status === 400 && /Unsupported Media Type|JSON body required/i.test(text);
|
|
28447
28460
|
}
|
|
@@ -28539,12 +28552,16 @@ var ProsaApiClient = class {
|
|
|
28539
28552
|
baseUrl;
|
|
28540
28553
|
fetchFn;
|
|
28541
28554
|
hasInjectedFetch;
|
|
28555
|
+
onRetry;
|
|
28556
|
+
onRequestSuccess;
|
|
28542
28557
|
token;
|
|
28543
28558
|
tenantId;
|
|
28544
28559
|
constructor(opts) {
|
|
28545
28560
|
this.baseUrl = trimTrailingSlash(opts.baseUrl);
|
|
28546
28561
|
this.fetchFn = opts.fetch ?? globalThis.fetch;
|
|
28547
28562
|
this.hasInjectedFetch = Boolean(opts.fetch);
|
|
28563
|
+
this.onRetry = opts.onRetry;
|
|
28564
|
+
this.onRequestSuccess = opts.onRequestSuccess;
|
|
28548
28565
|
this.token = opts.token;
|
|
28549
28566
|
this.tenantId = opts.tenantId;
|
|
28550
28567
|
}
|
|
@@ -28575,6 +28592,90 @@ var ProsaApiClient = class {
|
|
|
28575
28592
|
});
|
|
28576
28593
|
return this.parseTrpc(path14, response);
|
|
28577
28594
|
}
|
|
28595
|
+
async trpcMutationRetriable(path14, input, opts) {
|
|
28596
|
+
return this.retriableFetch({
|
|
28597
|
+
operation: opts.operation,
|
|
28598
|
+
retryHttpStatusBeforeParse: false,
|
|
28599
|
+
retryParseErrorsOnRetryableStatus: true,
|
|
28600
|
+
retryStructuredErrorsOnRetryableStatus: opts.retryStructuredErrorsOnRetryableStatus,
|
|
28601
|
+
request: /* @__PURE__ */ __name(() => this.fetchFn(`${this.baseUrl}/trpc/${path14}`, {
|
|
28602
|
+
method: "POST",
|
|
28603
|
+
headers: this.headers({
|
|
28604
|
+
"content-type": "application/json",
|
|
28605
|
+
...opts.headers
|
|
28606
|
+
}),
|
|
28607
|
+
body: JSON.stringify(input ?? {})
|
|
28608
|
+
}), "request"),
|
|
28609
|
+
parse: /* @__PURE__ */ __name((response) => this.parseTrpc(path14, response), "parse")
|
|
28610
|
+
});
|
|
28611
|
+
}
|
|
28612
|
+
async retriableFetch(opts) {
|
|
28613
|
+
const { operation: operation2, request: request2, parse: parse3 } = opts;
|
|
28614
|
+
let lastError;
|
|
28615
|
+
for (let attempt = 0; attempt < OBJECT_UPLOAD_MAX_ATTEMPTS; attempt += 1) {
|
|
28616
|
+
let response;
|
|
28617
|
+
try {
|
|
28618
|
+
response = await request2();
|
|
28619
|
+
} catch (err) {
|
|
28620
|
+
lastError = err;
|
|
28621
|
+
if (!isRetryableNetworkError(err) || attempt >= OBJECT_UPLOAD_MAX_ATTEMPTS - 1) {
|
|
28622
|
+
throw this.wrapRetriedError(operation2, attempt + 1, err);
|
|
28623
|
+
}
|
|
28624
|
+
const delayMs = objectUploadBackoffMs(attempt);
|
|
28625
|
+
this.onRetry?.({
|
|
28626
|
+
operation: operation2,
|
|
28627
|
+
attempt: attempt + 1,
|
|
28628
|
+
maxAttempts: OBJECT_UPLOAD_MAX_ATTEMPTS,
|
|
28629
|
+
delayMs,
|
|
28630
|
+
reason: networkErrorReason(err)
|
|
28631
|
+
});
|
|
28632
|
+
await sleep(delayMs);
|
|
28633
|
+
continue;
|
|
28634
|
+
}
|
|
28635
|
+
if (opts.retryHttpStatusBeforeParse !== false && isRetryableObjectUploadStatus(response.status) && attempt < OBJECT_UPLOAD_MAX_ATTEMPTS - 1) {
|
|
28636
|
+
const delayMs = objectUploadBackoffMs(attempt, response.headers);
|
|
28637
|
+
this.onRetry?.({
|
|
28638
|
+
operation: operation2,
|
|
28639
|
+
attempt: attempt + 1,
|
|
28640
|
+
maxAttempts: OBJECT_UPLOAD_MAX_ATTEMPTS,
|
|
28641
|
+
delayMs,
|
|
28642
|
+
reason: `HTTP ${response.status}`
|
|
28643
|
+
});
|
|
28644
|
+
await response.arrayBuffer().catch(() => void 0);
|
|
28645
|
+
await sleep(delayMs);
|
|
28646
|
+
continue;
|
|
28647
|
+
}
|
|
28648
|
+
try {
|
|
28649
|
+
const parsed = await parse3(response);
|
|
28650
|
+
this.onRequestSuccess?.({
|
|
28651
|
+
operation: operation2,
|
|
28652
|
+
attempts: attempt + 1
|
|
28653
|
+
});
|
|
28654
|
+
return parsed;
|
|
28655
|
+
} catch (err) {
|
|
28656
|
+
if (opts.retryParseErrorsOnRetryableStatus && (opts.retryStructuredErrorsOnRetryableStatus !== false || !(err instanceof ProsaApiError)) && isRetryableObjectUploadStatus(response.status) && attempt < OBJECT_UPLOAD_MAX_ATTEMPTS - 1) {
|
|
28657
|
+
const delayMs = objectUploadBackoffMs(attempt, response.headers);
|
|
28658
|
+
this.onRetry?.({
|
|
28659
|
+
operation: operation2,
|
|
28660
|
+
attempt: attempt + 1,
|
|
28661
|
+
maxAttempts: OBJECT_UPLOAD_MAX_ATTEMPTS,
|
|
28662
|
+
delayMs,
|
|
28663
|
+
reason: `HTTP ${response.status}: ${networkErrorReason(err)}`
|
|
28664
|
+
});
|
|
28665
|
+
await sleep(delayMs);
|
|
28666
|
+
continue;
|
|
28667
|
+
}
|
|
28668
|
+
throw this.wrapRetriedError(operation2, attempt + 1, err);
|
|
28669
|
+
}
|
|
28670
|
+
}
|
|
28671
|
+
throw this.wrapRetriedError(operation2, OBJECT_UPLOAD_MAX_ATTEMPTS, lastError);
|
|
28672
|
+
}
|
|
28673
|
+
wrapRetriedError(operation2, attempts, err) {
|
|
28674
|
+
if (err instanceof ProsaApiError) return err;
|
|
28675
|
+
if (attempts <= 1) return err instanceof Error ? err : new Error(String(err));
|
|
28676
|
+
const reason = networkErrorReason(err);
|
|
28677
|
+
return new CliUserError(`${operation2} failed after ${attempts} attempts: ${reason}`);
|
|
28678
|
+
}
|
|
28578
28679
|
async parseTrpc(path14, response) {
|
|
28579
28680
|
const text = await response.text();
|
|
28580
28681
|
if (!text) throw new CliUserError(`${path14}: empty response (status ${response.status})`);
|
|
@@ -28684,14 +28785,18 @@ var ProsaApiClient = class {
|
|
|
28684
28785
|
return this.trpcMutation("sync.planUpload", input);
|
|
28685
28786
|
}
|
|
28686
28787
|
async syncCommitUpload(input, opts = {}) {
|
|
28687
|
-
return this.
|
|
28788
|
+
return this.trpcMutationRetriable("sync.commitUpload", input, {
|
|
28789
|
+
operation: "sync.commitUpload",
|
|
28688
28790
|
headers: opts.idempotencyKey ? {
|
|
28689
28791
|
"idempotency-key": opts.idempotencyKey
|
|
28690
|
-
} : void 0
|
|
28792
|
+
} : void 0,
|
|
28793
|
+
retryStructuredErrorsOnRetryableStatus: false
|
|
28691
28794
|
});
|
|
28692
28795
|
}
|
|
28693
28796
|
async syncVerifyPromotion(input) {
|
|
28694
|
-
return this.
|
|
28797
|
+
return this.trpcMutationRetriable("sync.verifyPromotion", input, {
|
|
28798
|
+
operation: "sync.verifyPromotion"
|
|
28799
|
+
});
|
|
28695
28800
|
}
|
|
28696
28801
|
async syncAckCleanup(input) {
|
|
28697
28802
|
return this.trpcMutation("sync.ackCleanup", input);
|
|
@@ -28702,21 +28807,9 @@ var ProsaApiClient = class {
|
|
|
28702
28807
|
} : void 0);
|
|
28703
28808
|
}
|
|
28704
28809
|
async uploadObjectBytes(input) {
|
|
28705
|
-
|
|
28706
|
-
for (let attempt = 0; attempt < OBJECT_UPLOAD_MAX_ATTEMPTS; attempt += 1) {
|
|
28707
|
-
try {
|
|
28708
|
-
return await this.uploadObjectBytesOnce(input, attempt);
|
|
28709
|
-
} catch (err) {
|
|
28710
|
-
lastError = err;
|
|
28711
|
-
if (!isRetryableNetworkError(err) || attempt >= OBJECT_UPLOAD_MAX_ATTEMPTS - 1) {
|
|
28712
|
-
throw err;
|
|
28713
|
-
}
|
|
28714
|
-
await sleep(objectUploadBackoffMs(attempt));
|
|
28715
|
-
}
|
|
28716
|
-
}
|
|
28717
|
-
throw lastError instanceof Error ? lastError : new CliUserError("object upload failed");
|
|
28810
|
+
return this.uploadObjectBytesOnce(input);
|
|
28718
28811
|
}
|
|
28719
|
-
async uploadObjectBytesOnce(input
|
|
28812
|
+
async uploadObjectBytesOnce(input) {
|
|
28720
28813
|
const url = new URL(`${this.baseUrl}/objects/${input.objectId}`);
|
|
28721
28814
|
url.searchParams.set("batchId", input.batchId);
|
|
28722
28815
|
url.searchParams.set("hash", input.hash);
|
|
@@ -28724,55 +28817,65 @@ var ProsaApiClient = class {
|
|
|
28724
28817
|
url.searchParams.set("uncompressed", String(input.uncompressedSize));
|
|
28725
28818
|
url.searchParams.set("compression", input.compression ?? "zstd");
|
|
28726
28819
|
if (input.transportHash) url.searchParams.set("transportHash", input.transportHash);
|
|
28727
|
-
|
|
28728
|
-
|
|
28729
|
-
|
|
28730
|
-
|
|
28731
|
-
|
|
28732
|
-
|
|
28820
|
+
return this.retriableFetch({
|
|
28821
|
+
operation: "object PUT upload",
|
|
28822
|
+
request: /* @__PURE__ */ __name(() => this.fetchFn(url.toString(), {
|
|
28823
|
+
method: "PUT",
|
|
28824
|
+
headers: this.headers({
|
|
28825
|
+
"content-type": "application/octet-stream"
|
|
28826
|
+
}),
|
|
28827
|
+
body: input.bytes
|
|
28828
|
+
}), "request"),
|
|
28829
|
+
parse: /* @__PURE__ */ __name(async (response) => {
|
|
28830
|
+
const text = await response.text();
|
|
28831
|
+
if (response.status >= 400) {
|
|
28832
|
+
throw new CliUserError(`object upload failed: ${response.status} ${text}`);
|
|
28833
|
+
}
|
|
28834
|
+
const parsed = JSON.parse(text);
|
|
28835
|
+
return {
|
|
28836
|
+
alreadyExisted: Boolean(parsed.alreadyExisted)
|
|
28837
|
+
};
|
|
28838
|
+
}, "parse")
|
|
28733
28839
|
});
|
|
28734
|
-
const text = await response.text();
|
|
28735
|
-
if (response.status >= 400) {
|
|
28736
|
-
if (isRetryableObjectUploadStatus(response.status) && attempt < OBJECT_UPLOAD_MAX_ATTEMPTS - 1) {
|
|
28737
|
-
await sleep(objectUploadBackoffMs(attempt, response.headers));
|
|
28738
|
-
return this.uploadObjectBytesOnce(input, attempt + 1);
|
|
28739
|
-
}
|
|
28740
|
-
throw new CliUserError(`object upload failed: ${response.status} ${text}`);
|
|
28741
|
-
}
|
|
28742
|
-
const parsed = JSON.parse(text);
|
|
28743
|
-
return {
|
|
28744
|
-
alreadyExisted: Boolean(parsed.alreadyExisted)
|
|
28745
|
-
};
|
|
28746
28840
|
}
|
|
28747
28841
|
async uploadObjectPack(input) {
|
|
28748
28842
|
const url = new URL(`${this.baseUrl}/object-packs`);
|
|
28749
28843
|
url.searchParams.set("batchId", input.batchId);
|
|
28750
28844
|
const prepared = this.prepareObjectPackUpload(input.objects);
|
|
28751
|
-
const
|
|
28752
|
-
|
|
28753
|
-
|
|
28754
|
-
"
|
|
28755
|
-
|
|
28756
|
-
|
|
28757
|
-
|
|
28758
|
-
|
|
28759
|
-
|
|
28845
|
+
const binary = await this.retriableFetch({
|
|
28846
|
+
operation: "object pack binary upload",
|
|
28847
|
+
request: /* @__PURE__ */ __name(() => this.fetchFn(url.toString(), {
|
|
28848
|
+
method: "POST",
|
|
28849
|
+
headers: this.headers({
|
|
28850
|
+
"content-type": OBJECT_PACK_BINARY_CONTENT_TYPE
|
|
28851
|
+
}),
|
|
28852
|
+
body: encodeBinaryObjectPack({
|
|
28853
|
+
entries: prepared.entries,
|
|
28854
|
+
payload: prepared.payload
|
|
28855
|
+
})
|
|
28856
|
+
}), "request"),
|
|
28857
|
+
parse: /* @__PURE__ */ __name(async (response) => ({
|
|
28858
|
+
status: response.status,
|
|
28859
|
+
text: await response.text()
|
|
28860
|
+
}), "parse")
|
|
28760
28861
|
});
|
|
28761
|
-
|
|
28762
|
-
|
|
28763
|
-
|
|
28764
|
-
|
|
28765
|
-
|
|
28766
|
-
|
|
28767
|
-
|
|
28768
|
-
|
|
28769
|
-
|
|
28770
|
-
|
|
28771
|
-
|
|
28772
|
-
|
|
28773
|
-
|
|
28862
|
+
if (!isUnsupportedBinaryObjectPackResponse(binary.status, binary.text)) {
|
|
28863
|
+
return this.parseObjectPackUploadResponse(binary.status, binary.text);
|
|
28864
|
+
}
|
|
28865
|
+
return this.retriableFetch({
|
|
28866
|
+
operation: "object pack JSON upload",
|
|
28867
|
+
request: /* @__PURE__ */ __name(() => this.fetchFn(url.toString(), {
|
|
28868
|
+
method: "POST",
|
|
28869
|
+
headers: this.headers({
|
|
28870
|
+
"content-type": "application/json"
|
|
28871
|
+
}),
|
|
28872
|
+
body: JSON.stringify({
|
|
28873
|
+
bytesBase64: prepared.payload.toString("base64"),
|
|
28874
|
+
entries: prepared.entries
|
|
28875
|
+
})
|
|
28876
|
+
}), "request"),
|
|
28877
|
+
parse: /* @__PURE__ */ __name(async (response) => this.parseObjectPackUploadResponse(response.status, await response.text()), "parse")
|
|
28774
28878
|
});
|
|
28775
|
-
return this.parseObjectPackUploadResponse(fallbackResponse.status, await fallbackResponse.text());
|
|
28776
28879
|
}
|
|
28777
28880
|
prepareObjectPackUpload(objects) {
|
|
28778
28881
|
let offset = 0;
|
|
@@ -53671,6 +53774,46 @@ __name(runReadUploadPipeline, "runReadUploadPipeline");
|
|
|
53671
53774
|
// src/cli/sync/promotion.ts
|
|
53672
53775
|
import { rm as rm4 } from "fs/promises";
|
|
53673
53776
|
import path11 from "path";
|
|
53777
|
+
var AdaptiveUploadConcurrencyController = class {
|
|
53778
|
+
static {
|
|
53779
|
+
__name(this, "AdaptiveUploadConcurrencyController");
|
|
53780
|
+
}
|
|
53781
|
+
ceiling;
|
|
53782
|
+
onChange;
|
|
53783
|
+
value;
|
|
53784
|
+
successStreak = 0;
|
|
53785
|
+
constructor(ceiling, onChange) {
|
|
53786
|
+
this.ceiling = ceiling;
|
|
53787
|
+
this.onChange = onChange;
|
|
53788
|
+
this.value = Math.max(1, ceiling);
|
|
53789
|
+
}
|
|
53790
|
+
current() {
|
|
53791
|
+
return this.value;
|
|
53792
|
+
}
|
|
53793
|
+
recordRetry() {
|
|
53794
|
+
const previous = this.value;
|
|
53795
|
+
this.value = Math.max(1, Math.floor(this.value / 2));
|
|
53796
|
+
this.successStreak = 0;
|
|
53797
|
+
if (this.value !== previous) this.onChange?.({
|
|
53798
|
+
previous,
|
|
53799
|
+
current: this.value,
|
|
53800
|
+
reason: "retry"
|
|
53801
|
+
});
|
|
53802
|
+
}
|
|
53803
|
+
recordSuccess() {
|
|
53804
|
+
if (this.value >= this.ceiling) return;
|
|
53805
|
+
this.successStreak += 1;
|
|
53806
|
+
if (this.successStreak < 10) return;
|
|
53807
|
+
this.successStreak = 0;
|
|
53808
|
+
const previous = this.value;
|
|
53809
|
+
this.value = Math.min(this.ceiling, this.value + 1);
|
|
53810
|
+
if (this.value !== previous) this.onChange?.({
|
|
53811
|
+
previous,
|
|
53812
|
+
current: this.value,
|
|
53813
|
+
reason: "success"
|
|
53814
|
+
});
|
|
53815
|
+
}
|
|
53816
|
+
};
|
|
53674
53817
|
var BLAKE3_HEX_RE = /^[0-9a-f]{64}$/i;
|
|
53675
53818
|
var OBJECT_PACK_ENTRY_LIMIT = 1024;
|
|
53676
53819
|
var DEFAULT_OBJECT_PACK_MAX_BYTES = 8 * 1024 * 1024;
|
|
@@ -53733,9 +53876,10 @@ async function uploadObjectPut(client, batchId, object) {
|
|
|
53733
53876
|
});
|
|
53734
53877
|
}
|
|
53735
53878
|
__name(uploadObjectPut, "uploadObjectPut");
|
|
53736
|
-
async function uploadMissingCasObjects({ client, batchId, missingObjects, objectConcurrency, maxObjectPackBytes = DEFAULT_OBJECT_PACK_MAX_BYTES }) {
|
|
53879
|
+
async function uploadMissingCasObjects({ client, batchId, missingObjects, objectConcurrency, uploadConcurrency, maxObjectPackBytes = DEFAULT_OBJECT_PACK_MAX_BYTES }) {
|
|
53737
53880
|
const { packs, putObjects } = splitMissingObjectUploads(missingObjects, maxObjectPackBytes);
|
|
53738
|
-
|
|
53881
|
+
const concurrency = /* @__PURE__ */ __name(() => uploadConcurrency?.current() ?? objectConcurrency, "concurrency");
|
|
53882
|
+
await mapConcurrent(packs, concurrency(), async (pack) => {
|
|
53739
53883
|
await client.uploadObjectPack({
|
|
53740
53884
|
batchId,
|
|
53741
53885
|
objects: pack.map(({ entry, bytes }) => ({
|
|
@@ -53744,7 +53888,7 @@ async function uploadMissingCasObjects({ client, batchId, missingObjects, object
|
|
|
53744
53888
|
}))
|
|
53745
53889
|
});
|
|
53746
53890
|
});
|
|
53747
|
-
await mapConcurrent(putObjects,
|
|
53891
|
+
await mapConcurrent(putObjects, concurrency(), async (object) => {
|
|
53748
53892
|
await uploadObjectPut(client, batchId, object);
|
|
53749
53893
|
});
|
|
53750
53894
|
return {
|
|
@@ -54016,6 +54160,7 @@ async function uploadMissingCasObjectsWithReadPipeline(opts) {
|
|
|
54016
54160
|
batchId: opts.batchId,
|
|
54017
54161
|
missingObjects: batch,
|
|
54018
54162
|
objectConcurrency: opts.objectConcurrency,
|
|
54163
|
+
uploadConcurrency: opts.uploadConcurrency,
|
|
54019
54164
|
...opts.maxObjectPackBytes ? {
|
|
54020
54165
|
maxObjectPackBytes: opts.maxObjectPackBytes
|
|
54021
54166
|
} : {}
|
|
@@ -54725,7 +54870,7 @@ function readArtifactChunk(bundle, afterId, limit) {
|
|
|
54725
54870
|
};
|
|
54726
54871
|
}
|
|
54727
54872
|
__name(readArtifactChunk, "readArtifactChunk");
|
|
54728
|
-
async function promoteChunk({ client, deviceId, storePath, casObjects, projection, label, metrics, objectConcurrency, maxObjectPackBytes, verbose }) {
|
|
54873
|
+
async function promoteChunk({ client, deviceId, storePath, casObjects, projection, label, metrics, objectConcurrency, uploadConcurrency, maxObjectPackBytes, verbose }) {
|
|
54729
54874
|
const objectEntries = casObjects.map((c6) => c6.entry);
|
|
54730
54875
|
const totalStart = Date.now();
|
|
54731
54876
|
const planStart = Date.now();
|
|
@@ -54751,6 +54896,7 @@ async function promoteChunk({ client, deviceId, storePath, casObjects, projectio
|
|
|
54751
54896
|
storePath,
|
|
54752
54897
|
missingObjects,
|
|
54753
54898
|
objectConcurrency,
|
|
54899
|
+
uploadConcurrency,
|
|
54754
54900
|
...maxObjectPackBytes ? {
|
|
54755
54901
|
maxObjectPackBytes
|
|
54756
54902
|
} : {},
|
|
@@ -54862,7 +55008,7 @@ async function promotePhase(tasks, concurrency, worker) {
|
|
|
54862
55008
|
return results;
|
|
54863
55009
|
}
|
|
54864
55010
|
__name(promotePhase, "promotePhase");
|
|
54865
|
-
async function promoteChunkedUpload({ client, deviceId, storePath, bundle, maxObjectsPerPlan, maxRowsPerCommit, maxObjectPackBytes, objectConcurrency, batchConcurrency, verbose, progress, totalBatches, checkpoint }) {
|
|
55011
|
+
async function promoteChunkedUpload({ client, deviceId, storePath, bundle, maxObjectsPerPlan, maxRowsPerCommit, maxObjectPackBytes, objectConcurrency, uploadConcurrency, batchConcurrency, verbose, progress, totalBatches, checkpoint }) {
|
|
54866
55012
|
let batchCount = 0;
|
|
54867
55013
|
let lastReceipt = null;
|
|
54868
55014
|
let metrics = emptySyncMetrics(objectConcurrency);
|
|
@@ -54887,6 +55033,7 @@ async function promoteChunkedUpload({ client, deviceId, storePath, bundle, maxOb
|
|
|
54887
55033
|
projection: toProjection(chunk.rows),
|
|
54888
55034
|
label: `${label} batch ${phaseStart + cursor.sequence}`,
|
|
54889
55035
|
objectConcurrency,
|
|
55036
|
+
uploadConcurrency,
|
|
54890
55037
|
...maxObjectPackBytes ? {
|
|
54891
55038
|
maxObjectPackBytes
|
|
54892
55039
|
} : {},
|
|
@@ -54978,6 +55125,7 @@ async function promoteChunkedUpload({ client, deviceId, storePath, bundle, maxOb
|
|
|
54978
55125
|
label: `chunk ${batchCount}`,
|
|
54979
55126
|
metrics,
|
|
54980
55127
|
objectConcurrency,
|
|
55128
|
+
uploadConcurrency,
|
|
54981
55129
|
...maxObjectPackBytes ? {
|
|
54982
55130
|
maxObjectPackBytes
|
|
54983
55131
|
} : {},
|
|
@@ -55020,10 +55168,26 @@ function syncCommand() {
|
|
|
55020
55168
|
if (!tenantHint) {
|
|
55021
55169
|
throw new CliUserError("no active tenant. Run `prosa auth use <tenant>` first.");
|
|
55022
55170
|
}
|
|
55171
|
+
const uploadConcurrency = new AdaptiveUploadConcurrencyController(options.objectConcurrency, (change) => {
|
|
55172
|
+
if (!options.verbose) return;
|
|
55173
|
+
const direction = change.reason === "retry" ? "reduced" : "increased";
|
|
55174
|
+
process.stderr.write(`adaptive object concurrency ${direction} ${change.previous}->${change.current} after ${change.reason}
|
|
55175
|
+
`);
|
|
55176
|
+
});
|
|
55023
55177
|
const client = new ProsaApiClient({
|
|
55024
55178
|
baseUrl: server,
|
|
55025
55179
|
token: entry.token,
|
|
55026
|
-
tenantId: tenantHint
|
|
55180
|
+
tenantId: tenantHint,
|
|
55181
|
+
onRetry: /* @__PURE__ */ __name((event) => {
|
|
55182
|
+
if (event.operation.startsWith("object ")) uploadConcurrency.recordRetry();
|
|
55183
|
+
if (options.verbose) {
|
|
55184
|
+
process.stderr.write(`retry ${event.operation} attempt=${event.attempt}/${event.maxAttempts} delayMs=${event.delayMs} reason=${event.reason}
|
|
55185
|
+
`);
|
|
55186
|
+
}
|
|
55187
|
+
}, "onRetry"),
|
|
55188
|
+
onRequestSuccess: /* @__PURE__ */ __name((event) => {
|
|
55189
|
+
if (event.operation.startsWith("object ")) uploadConcurrency.recordSuccess();
|
|
55190
|
+
}, "onRequestSuccess")
|
|
55027
55191
|
});
|
|
55028
55192
|
const storePath = path12.resolve(options.store ?? defaultBundlePath13());
|
|
55029
55193
|
const exists = await bundleManifestExists(storePath);
|
|
@@ -55115,6 +55279,7 @@ function syncCommand() {
|
|
|
55115
55279
|
maxRowsPerCommit: handshake.limits.maxRowsPerCommit,
|
|
55116
55280
|
maxObjectPackBytes: handshake.limits.maxObjectBytes,
|
|
55117
55281
|
objectConcurrency: options.objectConcurrency,
|
|
55282
|
+
uploadConcurrency,
|
|
55118
55283
|
batchConcurrency: options.batchConcurrency,
|
|
55119
55284
|
verbose: options.verbose,
|
|
55120
55285
|
progress,
|