@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/cli/main.js
CHANGED
|
@@ -28394,8 +28394,9 @@ var CliUserError = class extends Error {
|
|
|
28394
28394
|
import { request as httpRequest } from "http";
|
|
28395
28395
|
import { request as httpsRequest } from "https";
|
|
28396
28396
|
import { OBJECT_PACK_BINARY_CONTENT_TYPE, encodeBinaryObjectPack } from "@c3-oss/prosa-sync";
|
|
28397
|
-
var OBJECT_UPLOAD_MAX_ATTEMPTS =
|
|
28398
|
-
var OBJECT_UPLOAD_BASE_BACKOFF_MS =
|
|
28397
|
+
var OBJECT_UPLOAD_MAX_ATTEMPTS = 6;
|
|
28398
|
+
var OBJECT_UPLOAD_BASE_BACKOFF_MS = 500;
|
|
28399
|
+
var OBJECT_UPLOAD_MAX_BACKOFF_MS = 15e3;
|
|
28399
28400
|
function trimTrailingSlash(url) {
|
|
28400
28401
|
return url.endsWith("/") ? url.slice(0, -1) : url;
|
|
28401
28402
|
}
|
|
@@ -28420,7 +28421,8 @@ __name(retryAfterMs, "retryAfterMs");
|
|
|
28420
28421
|
function objectUploadBackoffMs(attempt, headers) {
|
|
28421
28422
|
const retryAfter = headers ? retryAfterMs(headers) : void 0;
|
|
28422
28423
|
if (retryAfter !== void 0) return retryAfter;
|
|
28423
|
-
|
|
28424
|
+
const exponential = Math.min(OBJECT_UPLOAD_MAX_BACKOFF_MS, OBJECT_UPLOAD_BASE_BACKOFF_MS * 2 ** attempt);
|
|
28425
|
+
return Math.floor(exponential + Math.random() * Math.min(250, exponential));
|
|
28424
28426
|
}
|
|
28425
28427
|
__name(objectUploadBackoffMs, "objectUploadBackoffMs");
|
|
28426
28428
|
function isRetryableObjectUploadStatus(status) {
|
|
@@ -28434,10 +28436,21 @@ function isRetryableNetworkError(err) {
|
|
|
28434
28436
|
return code != null && [
|
|
28435
28437
|
"ECONNRESET",
|
|
28436
28438
|
"ETIMEDOUT",
|
|
28437
|
-
"EPIPE"
|
|
28439
|
+
"EPIPE",
|
|
28440
|
+
"ECONNREFUSED",
|
|
28441
|
+
"UND_ERR_SOCKET",
|
|
28442
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
28438
28443
|
].includes(code);
|
|
28439
28444
|
}
|
|
28440
28445
|
__name(isRetryableNetworkError, "isRetryableNetworkError");
|
|
28446
|
+
function networkErrorReason(err) {
|
|
28447
|
+
if (err instanceof Error) {
|
|
28448
|
+
const code = err.code ?? err.cause?.code;
|
|
28449
|
+
return code ? `${err.message} (${code})` : err.message;
|
|
28450
|
+
}
|
|
28451
|
+
return String(err);
|
|
28452
|
+
}
|
|
28453
|
+
__name(networkErrorReason, "networkErrorReason");
|
|
28441
28454
|
function isUnsupportedBinaryObjectPackResponse(status, text) {
|
|
28442
28455
|
return status === 415 || status === 400 && /Unsupported Media Type|JSON body required/i.test(text);
|
|
28443
28456
|
}
|
|
@@ -28535,12 +28548,16 @@ var ProsaApiClient = class {
|
|
|
28535
28548
|
baseUrl;
|
|
28536
28549
|
fetchFn;
|
|
28537
28550
|
hasInjectedFetch;
|
|
28551
|
+
onRetry;
|
|
28552
|
+
onRequestSuccess;
|
|
28538
28553
|
token;
|
|
28539
28554
|
tenantId;
|
|
28540
28555
|
constructor(opts) {
|
|
28541
28556
|
this.baseUrl = trimTrailingSlash(opts.baseUrl);
|
|
28542
28557
|
this.fetchFn = opts.fetch ?? globalThis.fetch;
|
|
28543
28558
|
this.hasInjectedFetch = Boolean(opts.fetch);
|
|
28559
|
+
this.onRetry = opts.onRetry;
|
|
28560
|
+
this.onRequestSuccess = opts.onRequestSuccess;
|
|
28544
28561
|
this.token = opts.token;
|
|
28545
28562
|
this.tenantId = opts.tenantId;
|
|
28546
28563
|
}
|
|
@@ -28571,6 +28588,90 @@ var ProsaApiClient = class {
|
|
|
28571
28588
|
});
|
|
28572
28589
|
return this.parseTrpc(path14, response);
|
|
28573
28590
|
}
|
|
28591
|
+
async trpcMutationRetriable(path14, input, opts) {
|
|
28592
|
+
return this.retriableFetch({
|
|
28593
|
+
operation: opts.operation,
|
|
28594
|
+
retryHttpStatusBeforeParse: false,
|
|
28595
|
+
retryParseErrorsOnRetryableStatus: true,
|
|
28596
|
+
retryStructuredErrorsOnRetryableStatus: opts.retryStructuredErrorsOnRetryableStatus,
|
|
28597
|
+
request: /* @__PURE__ */ __name(() => this.fetchFn(`${this.baseUrl}/trpc/${path14}`, {
|
|
28598
|
+
method: "POST",
|
|
28599
|
+
headers: this.headers({
|
|
28600
|
+
"content-type": "application/json",
|
|
28601
|
+
...opts.headers
|
|
28602
|
+
}),
|
|
28603
|
+
body: JSON.stringify(input ?? {})
|
|
28604
|
+
}), "request"),
|
|
28605
|
+
parse: /* @__PURE__ */ __name((response) => this.parseTrpc(path14, response), "parse")
|
|
28606
|
+
});
|
|
28607
|
+
}
|
|
28608
|
+
async retriableFetch(opts) {
|
|
28609
|
+
const { operation: operation2, request: request2, parse: parse3 } = opts;
|
|
28610
|
+
let lastError;
|
|
28611
|
+
for (let attempt = 0; attempt < OBJECT_UPLOAD_MAX_ATTEMPTS; attempt += 1) {
|
|
28612
|
+
let response;
|
|
28613
|
+
try {
|
|
28614
|
+
response = await request2();
|
|
28615
|
+
} catch (err) {
|
|
28616
|
+
lastError = err;
|
|
28617
|
+
if (!isRetryableNetworkError(err) || attempt >= OBJECT_UPLOAD_MAX_ATTEMPTS - 1) {
|
|
28618
|
+
throw this.wrapRetriedError(operation2, attempt + 1, err);
|
|
28619
|
+
}
|
|
28620
|
+
const delayMs = objectUploadBackoffMs(attempt);
|
|
28621
|
+
this.onRetry?.({
|
|
28622
|
+
operation: operation2,
|
|
28623
|
+
attempt: attempt + 1,
|
|
28624
|
+
maxAttempts: OBJECT_UPLOAD_MAX_ATTEMPTS,
|
|
28625
|
+
delayMs,
|
|
28626
|
+
reason: networkErrorReason(err)
|
|
28627
|
+
});
|
|
28628
|
+
await sleep(delayMs);
|
|
28629
|
+
continue;
|
|
28630
|
+
}
|
|
28631
|
+
if (opts.retryHttpStatusBeforeParse !== false && isRetryableObjectUploadStatus(response.status) && attempt < OBJECT_UPLOAD_MAX_ATTEMPTS - 1) {
|
|
28632
|
+
const delayMs = objectUploadBackoffMs(attempt, response.headers);
|
|
28633
|
+
this.onRetry?.({
|
|
28634
|
+
operation: operation2,
|
|
28635
|
+
attempt: attempt + 1,
|
|
28636
|
+
maxAttempts: OBJECT_UPLOAD_MAX_ATTEMPTS,
|
|
28637
|
+
delayMs,
|
|
28638
|
+
reason: `HTTP ${response.status}`
|
|
28639
|
+
});
|
|
28640
|
+
await response.arrayBuffer().catch(() => void 0);
|
|
28641
|
+
await sleep(delayMs);
|
|
28642
|
+
continue;
|
|
28643
|
+
}
|
|
28644
|
+
try {
|
|
28645
|
+
const parsed = await parse3(response);
|
|
28646
|
+
this.onRequestSuccess?.({
|
|
28647
|
+
operation: operation2,
|
|
28648
|
+
attempts: attempt + 1
|
|
28649
|
+
});
|
|
28650
|
+
return parsed;
|
|
28651
|
+
} catch (err) {
|
|
28652
|
+
if (opts.retryParseErrorsOnRetryableStatus && (opts.retryStructuredErrorsOnRetryableStatus !== false || !(err instanceof ProsaApiError)) && isRetryableObjectUploadStatus(response.status) && attempt < OBJECT_UPLOAD_MAX_ATTEMPTS - 1) {
|
|
28653
|
+
const delayMs = objectUploadBackoffMs(attempt, response.headers);
|
|
28654
|
+
this.onRetry?.({
|
|
28655
|
+
operation: operation2,
|
|
28656
|
+
attempt: attempt + 1,
|
|
28657
|
+
maxAttempts: OBJECT_UPLOAD_MAX_ATTEMPTS,
|
|
28658
|
+
delayMs,
|
|
28659
|
+
reason: `HTTP ${response.status}: ${networkErrorReason(err)}`
|
|
28660
|
+
});
|
|
28661
|
+
await sleep(delayMs);
|
|
28662
|
+
continue;
|
|
28663
|
+
}
|
|
28664
|
+
throw this.wrapRetriedError(operation2, attempt + 1, err);
|
|
28665
|
+
}
|
|
28666
|
+
}
|
|
28667
|
+
throw this.wrapRetriedError(operation2, OBJECT_UPLOAD_MAX_ATTEMPTS, lastError);
|
|
28668
|
+
}
|
|
28669
|
+
wrapRetriedError(operation2, attempts, err) {
|
|
28670
|
+
if (err instanceof ProsaApiError) return err;
|
|
28671
|
+
if (attempts <= 1) return err instanceof Error ? err : new Error(String(err));
|
|
28672
|
+
const reason = networkErrorReason(err);
|
|
28673
|
+
return new CliUserError(`${operation2} failed after ${attempts} attempts: ${reason}`);
|
|
28674
|
+
}
|
|
28574
28675
|
async parseTrpc(path14, response) {
|
|
28575
28676
|
const text = await response.text();
|
|
28576
28677
|
if (!text) throw new CliUserError(`${path14}: empty response (status ${response.status})`);
|
|
@@ -28680,14 +28781,18 @@ var ProsaApiClient = class {
|
|
|
28680
28781
|
return this.trpcMutation("sync.planUpload", input);
|
|
28681
28782
|
}
|
|
28682
28783
|
async syncCommitUpload(input, opts = {}) {
|
|
28683
|
-
return this.
|
|
28784
|
+
return this.trpcMutationRetriable("sync.commitUpload", input, {
|
|
28785
|
+
operation: "sync.commitUpload",
|
|
28684
28786
|
headers: opts.idempotencyKey ? {
|
|
28685
28787
|
"idempotency-key": opts.idempotencyKey
|
|
28686
|
-
} : void 0
|
|
28788
|
+
} : void 0,
|
|
28789
|
+
retryStructuredErrorsOnRetryableStatus: false
|
|
28687
28790
|
});
|
|
28688
28791
|
}
|
|
28689
28792
|
async syncVerifyPromotion(input) {
|
|
28690
|
-
return this.
|
|
28793
|
+
return this.trpcMutationRetriable("sync.verifyPromotion", input, {
|
|
28794
|
+
operation: "sync.verifyPromotion"
|
|
28795
|
+
});
|
|
28691
28796
|
}
|
|
28692
28797
|
async syncAckCleanup(input) {
|
|
28693
28798
|
return this.trpcMutation("sync.ackCleanup", input);
|
|
@@ -28698,21 +28803,9 @@ var ProsaApiClient = class {
|
|
|
28698
28803
|
} : void 0);
|
|
28699
28804
|
}
|
|
28700
28805
|
async uploadObjectBytes(input) {
|
|
28701
|
-
|
|
28702
|
-
for (let attempt = 0; attempt < OBJECT_UPLOAD_MAX_ATTEMPTS; attempt += 1) {
|
|
28703
|
-
try {
|
|
28704
|
-
return await this.uploadObjectBytesOnce(input, attempt);
|
|
28705
|
-
} catch (err) {
|
|
28706
|
-
lastError = err;
|
|
28707
|
-
if (!isRetryableNetworkError(err) || attempt >= OBJECT_UPLOAD_MAX_ATTEMPTS - 1) {
|
|
28708
|
-
throw err;
|
|
28709
|
-
}
|
|
28710
|
-
await sleep(objectUploadBackoffMs(attempt));
|
|
28711
|
-
}
|
|
28712
|
-
}
|
|
28713
|
-
throw lastError instanceof Error ? lastError : new CliUserError("object upload failed");
|
|
28806
|
+
return this.uploadObjectBytesOnce(input);
|
|
28714
28807
|
}
|
|
28715
|
-
async uploadObjectBytesOnce(input
|
|
28808
|
+
async uploadObjectBytesOnce(input) {
|
|
28716
28809
|
const url = new URL(`${this.baseUrl}/objects/${input.objectId}`);
|
|
28717
28810
|
url.searchParams.set("batchId", input.batchId);
|
|
28718
28811
|
url.searchParams.set("hash", input.hash);
|
|
@@ -28720,55 +28813,65 @@ var ProsaApiClient = class {
|
|
|
28720
28813
|
url.searchParams.set("uncompressed", String(input.uncompressedSize));
|
|
28721
28814
|
url.searchParams.set("compression", input.compression ?? "zstd");
|
|
28722
28815
|
if (input.transportHash) url.searchParams.set("transportHash", input.transportHash);
|
|
28723
|
-
|
|
28724
|
-
|
|
28725
|
-
|
|
28726
|
-
|
|
28727
|
-
|
|
28728
|
-
|
|
28816
|
+
return this.retriableFetch({
|
|
28817
|
+
operation: "object PUT upload",
|
|
28818
|
+
request: /* @__PURE__ */ __name(() => this.fetchFn(url.toString(), {
|
|
28819
|
+
method: "PUT",
|
|
28820
|
+
headers: this.headers({
|
|
28821
|
+
"content-type": "application/octet-stream"
|
|
28822
|
+
}),
|
|
28823
|
+
body: input.bytes
|
|
28824
|
+
}), "request"),
|
|
28825
|
+
parse: /* @__PURE__ */ __name(async (response) => {
|
|
28826
|
+
const text = await response.text();
|
|
28827
|
+
if (response.status >= 400) {
|
|
28828
|
+
throw new CliUserError(`object upload failed: ${response.status} ${text}`);
|
|
28829
|
+
}
|
|
28830
|
+
const parsed = JSON.parse(text);
|
|
28831
|
+
return {
|
|
28832
|
+
alreadyExisted: Boolean(parsed.alreadyExisted)
|
|
28833
|
+
};
|
|
28834
|
+
}, "parse")
|
|
28729
28835
|
});
|
|
28730
|
-
const text = await response.text();
|
|
28731
|
-
if (response.status >= 400) {
|
|
28732
|
-
if (isRetryableObjectUploadStatus(response.status) && attempt < OBJECT_UPLOAD_MAX_ATTEMPTS - 1) {
|
|
28733
|
-
await sleep(objectUploadBackoffMs(attempt, response.headers));
|
|
28734
|
-
return this.uploadObjectBytesOnce(input, attempt + 1);
|
|
28735
|
-
}
|
|
28736
|
-
throw new CliUserError(`object upload failed: ${response.status} ${text}`);
|
|
28737
|
-
}
|
|
28738
|
-
const parsed = JSON.parse(text);
|
|
28739
|
-
return {
|
|
28740
|
-
alreadyExisted: Boolean(parsed.alreadyExisted)
|
|
28741
|
-
};
|
|
28742
28836
|
}
|
|
28743
28837
|
async uploadObjectPack(input) {
|
|
28744
28838
|
const url = new URL(`${this.baseUrl}/object-packs`);
|
|
28745
28839
|
url.searchParams.set("batchId", input.batchId);
|
|
28746
28840
|
const prepared = this.prepareObjectPackUpload(input.objects);
|
|
28747
|
-
const
|
|
28748
|
-
|
|
28749
|
-
|
|
28750
|
-
"
|
|
28751
|
-
|
|
28752
|
-
|
|
28753
|
-
|
|
28754
|
-
|
|
28755
|
-
|
|
28841
|
+
const binary = await this.retriableFetch({
|
|
28842
|
+
operation: "object pack binary upload",
|
|
28843
|
+
request: /* @__PURE__ */ __name(() => this.fetchFn(url.toString(), {
|
|
28844
|
+
method: "POST",
|
|
28845
|
+
headers: this.headers({
|
|
28846
|
+
"content-type": OBJECT_PACK_BINARY_CONTENT_TYPE
|
|
28847
|
+
}),
|
|
28848
|
+
body: encodeBinaryObjectPack({
|
|
28849
|
+
entries: prepared.entries,
|
|
28850
|
+
payload: prepared.payload
|
|
28851
|
+
})
|
|
28852
|
+
}), "request"),
|
|
28853
|
+
parse: /* @__PURE__ */ __name(async (response) => ({
|
|
28854
|
+
status: response.status,
|
|
28855
|
+
text: await response.text()
|
|
28856
|
+
}), "parse")
|
|
28756
28857
|
});
|
|
28757
|
-
|
|
28758
|
-
|
|
28759
|
-
|
|
28760
|
-
|
|
28761
|
-
|
|
28762
|
-
|
|
28763
|
-
|
|
28764
|
-
|
|
28765
|
-
|
|
28766
|
-
|
|
28767
|
-
|
|
28768
|
-
|
|
28769
|
-
|
|
28858
|
+
if (!isUnsupportedBinaryObjectPackResponse(binary.status, binary.text)) {
|
|
28859
|
+
return this.parseObjectPackUploadResponse(binary.status, binary.text);
|
|
28860
|
+
}
|
|
28861
|
+
return this.retriableFetch({
|
|
28862
|
+
operation: "object pack JSON upload",
|
|
28863
|
+
request: /* @__PURE__ */ __name(() => this.fetchFn(url.toString(), {
|
|
28864
|
+
method: "POST",
|
|
28865
|
+
headers: this.headers({
|
|
28866
|
+
"content-type": "application/json"
|
|
28867
|
+
}),
|
|
28868
|
+
body: JSON.stringify({
|
|
28869
|
+
bytesBase64: prepared.payload.toString("base64"),
|
|
28870
|
+
entries: prepared.entries
|
|
28871
|
+
})
|
|
28872
|
+
}), "request"),
|
|
28873
|
+
parse: /* @__PURE__ */ __name(async (response) => this.parseObjectPackUploadResponse(response.status, await response.text()), "parse")
|
|
28770
28874
|
});
|
|
28771
|
-
return this.parseObjectPackUploadResponse(fallbackResponse.status, await fallbackResponse.text());
|
|
28772
28875
|
}
|
|
28773
28876
|
prepareObjectPackUpload(objects) {
|
|
28774
28877
|
let offset = 0;
|
|
@@ -53667,6 +53770,46 @@ __name(runReadUploadPipeline, "runReadUploadPipeline");
|
|
|
53667
53770
|
// src/cli/sync/promotion.ts
|
|
53668
53771
|
import { rm as rm4 } from "fs/promises";
|
|
53669
53772
|
import path11 from "path";
|
|
53773
|
+
var AdaptiveUploadConcurrencyController = class {
|
|
53774
|
+
static {
|
|
53775
|
+
__name(this, "AdaptiveUploadConcurrencyController");
|
|
53776
|
+
}
|
|
53777
|
+
ceiling;
|
|
53778
|
+
onChange;
|
|
53779
|
+
value;
|
|
53780
|
+
successStreak = 0;
|
|
53781
|
+
constructor(ceiling, onChange) {
|
|
53782
|
+
this.ceiling = ceiling;
|
|
53783
|
+
this.onChange = onChange;
|
|
53784
|
+
this.value = Math.max(1, ceiling);
|
|
53785
|
+
}
|
|
53786
|
+
current() {
|
|
53787
|
+
return this.value;
|
|
53788
|
+
}
|
|
53789
|
+
recordRetry() {
|
|
53790
|
+
const previous = this.value;
|
|
53791
|
+
this.value = Math.max(1, Math.floor(this.value / 2));
|
|
53792
|
+
this.successStreak = 0;
|
|
53793
|
+
if (this.value !== previous) this.onChange?.({
|
|
53794
|
+
previous,
|
|
53795
|
+
current: this.value,
|
|
53796
|
+
reason: "retry"
|
|
53797
|
+
});
|
|
53798
|
+
}
|
|
53799
|
+
recordSuccess() {
|
|
53800
|
+
if (this.value >= this.ceiling) return;
|
|
53801
|
+
this.successStreak += 1;
|
|
53802
|
+
if (this.successStreak < 10) return;
|
|
53803
|
+
this.successStreak = 0;
|
|
53804
|
+
const previous = this.value;
|
|
53805
|
+
this.value = Math.min(this.ceiling, this.value + 1);
|
|
53806
|
+
if (this.value !== previous) this.onChange?.({
|
|
53807
|
+
previous,
|
|
53808
|
+
current: this.value,
|
|
53809
|
+
reason: "success"
|
|
53810
|
+
});
|
|
53811
|
+
}
|
|
53812
|
+
};
|
|
53670
53813
|
var BLAKE3_HEX_RE = /^[0-9a-f]{64}$/i;
|
|
53671
53814
|
var OBJECT_PACK_ENTRY_LIMIT = 1024;
|
|
53672
53815
|
var DEFAULT_OBJECT_PACK_MAX_BYTES = 8 * 1024 * 1024;
|
|
@@ -53729,9 +53872,10 @@ async function uploadObjectPut(client, batchId, object) {
|
|
|
53729
53872
|
});
|
|
53730
53873
|
}
|
|
53731
53874
|
__name(uploadObjectPut, "uploadObjectPut");
|
|
53732
|
-
async function uploadMissingCasObjects({ client, batchId, missingObjects, objectConcurrency, maxObjectPackBytes = DEFAULT_OBJECT_PACK_MAX_BYTES }) {
|
|
53875
|
+
async function uploadMissingCasObjects({ client, batchId, missingObjects, objectConcurrency, uploadConcurrency, maxObjectPackBytes = DEFAULT_OBJECT_PACK_MAX_BYTES }) {
|
|
53733
53876
|
const { packs, putObjects } = splitMissingObjectUploads(missingObjects, maxObjectPackBytes);
|
|
53734
|
-
|
|
53877
|
+
const concurrency = /* @__PURE__ */ __name(() => uploadConcurrency?.current() ?? objectConcurrency, "concurrency");
|
|
53878
|
+
await mapConcurrent(packs, concurrency(), async (pack) => {
|
|
53735
53879
|
await client.uploadObjectPack({
|
|
53736
53880
|
batchId,
|
|
53737
53881
|
objects: pack.map(({ entry, bytes }) => ({
|
|
@@ -53740,7 +53884,7 @@ async function uploadMissingCasObjects({ client, batchId, missingObjects, object
|
|
|
53740
53884
|
}))
|
|
53741
53885
|
});
|
|
53742
53886
|
});
|
|
53743
|
-
await mapConcurrent(putObjects,
|
|
53887
|
+
await mapConcurrent(putObjects, concurrency(), async (object) => {
|
|
53744
53888
|
await uploadObjectPut(client, batchId, object);
|
|
53745
53889
|
});
|
|
53746
53890
|
return {
|
|
@@ -54012,6 +54156,7 @@ async function uploadMissingCasObjectsWithReadPipeline(opts) {
|
|
|
54012
54156
|
batchId: opts.batchId,
|
|
54013
54157
|
missingObjects: batch,
|
|
54014
54158
|
objectConcurrency: opts.objectConcurrency,
|
|
54159
|
+
uploadConcurrency: opts.uploadConcurrency,
|
|
54015
54160
|
...opts.maxObjectPackBytes ? {
|
|
54016
54161
|
maxObjectPackBytes: opts.maxObjectPackBytes
|
|
54017
54162
|
} : {}
|
|
@@ -54721,7 +54866,7 @@ function readArtifactChunk(bundle, afterId, limit) {
|
|
|
54721
54866
|
};
|
|
54722
54867
|
}
|
|
54723
54868
|
__name(readArtifactChunk, "readArtifactChunk");
|
|
54724
|
-
async function promoteChunk({ client, deviceId, storePath, casObjects, projection, label, metrics, objectConcurrency, maxObjectPackBytes, verbose }) {
|
|
54869
|
+
async function promoteChunk({ client, deviceId, storePath, casObjects, projection, label, metrics, objectConcurrency, uploadConcurrency, maxObjectPackBytes, verbose }) {
|
|
54725
54870
|
const objectEntries = casObjects.map((c6) => c6.entry);
|
|
54726
54871
|
const totalStart = Date.now();
|
|
54727
54872
|
const planStart = Date.now();
|
|
@@ -54747,6 +54892,7 @@ async function promoteChunk({ client, deviceId, storePath, casObjects, projectio
|
|
|
54747
54892
|
storePath,
|
|
54748
54893
|
missingObjects,
|
|
54749
54894
|
objectConcurrency,
|
|
54895
|
+
uploadConcurrency,
|
|
54750
54896
|
...maxObjectPackBytes ? {
|
|
54751
54897
|
maxObjectPackBytes
|
|
54752
54898
|
} : {},
|
|
@@ -54858,7 +55004,7 @@ async function promotePhase(tasks, concurrency, worker) {
|
|
|
54858
55004
|
return results;
|
|
54859
55005
|
}
|
|
54860
55006
|
__name(promotePhase, "promotePhase");
|
|
54861
|
-
async function promoteChunkedUpload({ client, deviceId, storePath, bundle, maxObjectsPerPlan, maxRowsPerCommit, maxObjectPackBytes, objectConcurrency, batchConcurrency, verbose, progress, totalBatches, checkpoint }) {
|
|
55007
|
+
async function promoteChunkedUpload({ client, deviceId, storePath, bundle, maxObjectsPerPlan, maxRowsPerCommit, maxObjectPackBytes, objectConcurrency, uploadConcurrency, batchConcurrency, verbose, progress, totalBatches, checkpoint }) {
|
|
54862
55008
|
let batchCount = 0;
|
|
54863
55009
|
let lastReceipt = null;
|
|
54864
55010
|
let metrics = emptySyncMetrics(objectConcurrency);
|
|
@@ -54883,6 +55029,7 @@ async function promoteChunkedUpload({ client, deviceId, storePath, bundle, maxOb
|
|
|
54883
55029
|
projection: toProjection(chunk.rows),
|
|
54884
55030
|
label: `${label} batch ${phaseStart + cursor.sequence}`,
|
|
54885
55031
|
objectConcurrency,
|
|
55032
|
+
uploadConcurrency,
|
|
54886
55033
|
...maxObjectPackBytes ? {
|
|
54887
55034
|
maxObjectPackBytes
|
|
54888
55035
|
} : {},
|
|
@@ -54974,6 +55121,7 @@ async function promoteChunkedUpload({ client, deviceId, storePath, bundle, maxOb
|
|
|
54974
55121
|
label: `chunk ${batchCount}`,
|
|
54975
55122
|
metrics,
|
|
54976
55123
|
objectConcurrency,
|
|
55124
|
+
uploadConcurrency,
|
|
54977
55125
|
...maxObjectPackBytes ? {
|
|
54978
55126
|
maxObjectPackBytes
|
|
54979
55127
|
} : {},
|
|
@@ -55016,10 +55164,26 @@ function syncCommand() {
|
|
|
55016
55164
|
if (!tenantHint) {
|
|
55017
55165
|
throw new CliUserError("no active tenant. Run `prosa auth use <tenant>` first.");
|
|
55018
55166
|
}
|
|
55167
|
+
const uploadConcurrency = new AdaptiveUploadConcurrencyController(options.objectConcurrency, (change) => {
|
|
55168
|
+
if (!options.verbose) return;
|
|
55169
|
+
const direction = change.reason === "retry" ? "reduced" : "increased";
|
|
55170
|
+
process.stderr.write(`adaptive object concurrency ${direction} ${change.previous}->${change.current} after ${change.reason}
|
|
55171
|
+
`);
|
|
55172
|
+
});
|
|
55019
55173
|
const client = new ProsaApiClient({
|
|
55020
55174
|
baseUrl: server,
|
|
55021
55175
|
token: entry.token,
|
|
55022
|
-
tenantId: tenantHint
|
|
55176
|
+
tenantId: tenantHint,
|
|
55177
|
+
onRetry: /* @__PURE__ */ __name((event) => {
|
|
55178
|
+
if (event.operation.startsWith("object ")) uploadConcurrency.recordRetry();
|
|
55179
|
+
if (options.verbose) {
|
|
55180
|
+
process.stderr.write(`retry ${event.operation} attempt=${event.attempt}/${event.maxAttempts} delayMs=${event.delayMs} reason=${event.reason}
|
|
55181
|
+
`);
|
|
55182
|
+
}
|
|
55183
|
+
}, "onRetry"),
|
|
55184
|
+
onRequestSuccess: /* @__PURE__ */ __name((event) => {
|
|
55185
|
+
if (event.operation.startsWith("object ")) uploadConcurrency.recordSuccess();
|
|
55186
|
+
}, "onRequestSuccess")
|
|
55023
55187
|
});
|
|
55024
55188
|
const storePath = path12.resolve(options.store ?? defaultBundlePath13());
|
|
55025
55189
|
const exists = await bundleManifestExists(storePath);
|
|
@@ -55111,6 +55275,7 @@ function syncCommand() {
|
|
|
55111
55275
|
maxRowsPerCommit: handshake.limits.maxRowsPerCommit,
|
|
55112
55276
|
maxObjectPackBytes: handshake.limits.maxObjectBytes,
|
|
55113
55277
|
objectConcurrency: options.objectConcurrency,
|
|
55278
|
+
uploadConcurrency,
|
|
55114
55279
|
batchConcurrency: options.batchConcurrency,
|
|
55115
55280
|
verbose: options.verbose,
|
|
55116
55281
|
progress,
|