@madewithremy/admin 0.1.13 → 0.1.15
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/index.d.ts +232 -44
- package/dist/index.js +116 -22
- package/dist/index.js.map +1 -1
- package/dist/prod.js +268 -93
- package/package.json +1 -1
package/dist/prod.js
CHANGED
|
@@ -342,6 +342,62 @@ function statsForMethod(ctx, methodId, params = {}) {
|
|
|
342
342
|
);
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
+
// src/sleep.ts
|
|
346
|
+
function sleep(ms) {
|
|
347
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/poll.ts
|
|
351
|
+
async function pollUntil(read, isSettled, options) {
|
|
352
|
+
const start2 = Date.now();
|
|
353
|
+
let movedAt = start2;
|
|
354
|
+
let lastKey;
|
|
355
|
+
let transientSince = null;
|
|
356
|
+
while (true) {
|
|
357
|
+
let value;
|
|
358
|
+
try {
|
|
359
|
+
value = await read();
|
|
360
|
+
transientSince = null;
|
|
361
|
+
} catch (err) {
|
|
362
|
+
if (!isTransientError(err)) {
|
|
363
|
+
throw err;
|
|
364
|
+
}
|
|
365
|
+
transientSince ??= Date.now();
|
|
366
|
+
if (Date.now() - transientSince > TRANSIENT_GRACE_MS) {
|
|
367
|
+
throw err;
|
|
368
|
+
}
|
|
369
|
+
options.onProgress?.(
|
|
370
|
+
`retrying after a gateway error\u2026 (${elapsedSeconds(start2)}s)`
|
|
371
|
+
);
|
|
372
|
+
await sleep(options.pollMs);
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
if (isSettled(value)) {
|
|
376
|
+
return { settled: true, value };
|
|
377
|
+
}
|
|
378
|
+
if (options.progressKey) {
|
|
379
|
+
const key = options.progressKey(value);
|
|
380
|
+
if (key !== lastKey) {
|
|
381
|
+
lastKey = key;
|
|
382
|
+
movedAt = Date.now();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (Date.now() - movedAt > options.timeoutMs) {
|
|
386
|
+
return { settled: false, value };
|
|
387
|
+
}
|
|
388
|
+
if (options.describe) {
|
|
389
|
+
options.onProgress?.(options.describe(value, start2));
|
|
390
|
+
}
|
|
391
|
+
await sleep(options.pollMs);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
function elapsedSeconds(start2) {
|
|
395
|
+
return Math.round((Date.now() - start2) / 1e3);
|
|
396
|
+
}
|
|
397
|
+
function timedOut(timeoutMs, still) {
|
|
398
|
+
return `Timed out after ${Math.round(timeoutMs / 1e3)}s ${still}`;
|
|
399
|
+
}
|
|
400
|
+
|
|
345
401
|
// src/output.ts
|
|
346
402
|
var PRETTY = process.stdout.isTTY === true;
|
|
347
403
|
function out(data) {
|
|
@@ -352,6 +408,31 @@ function progress(message) {
|
|
|
352
408
|
process.stderr.write(`${message}
|
|
353
409
|
`);
|
|
354
410
|
}
|
|
411
|
+
function describeEta(eta, now = Date.now()) {
|
|
412
|
+
if (!eta) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
const minutes = Math.max(1, Math.round((Date.parse(eta) - now) / 6e4));
|
|
416
|
+
if (minutes < 90) {
|
|
417
|
+
return `about ${minutes} min left`;
|
|
418
|
+
}
|
|
419
|
+
const hours = Math.round(minutes / 60 * 10) / 10;
|
|
420
|
+
return `about ${hours} h left`;
|
|
421
|
+
}
|
|
422
|
+
function renderProgress(p, start2, extra) {
|
|
423
|
+
const count = p.total !== null ? `${p.done.toLocaleString()}/${p.total.toLocaleString()} ${p.unit}` : p.done > 0 ? `${p.done.toLocaleString()} ${p.unit}` : null;
|
|
424
|
+
const rate = p.ratePerMinute !== null && p.ratePerMinute > 0 ? `${Math.round(p.ratePerMinute).toLocaleString()}/min` : null;
|
|
425
|
+
const parts = [
|
|
426
|
+
`${p.phase}\u2026`,
|
|
427
|
+
count,
|
|
428
|
+
rate,
|
|
429
|
+
describeEta(p.etaAt),
|
|
430
|
+
extra ?? null,
|
|
431
|
+
p.stalled ? "no progress for 30 min" : null
|
|
432
|
+
].filter((part) => Boolean(part));
|
|
433
|
+
const elapsed = start2 !== void 0 ? ` (${elapsedSeconds(start2)}s)` : "";
|
|
434
|
+
return `${parts.join(" \xB7 ")}${elapsed}`;
|
|
435
|
+
}
|
|
355
436
|
|
|
356
437
|
// src/commands/requests.ts
|
|
357
438
|
var requestsSpecs = {
|
|
@@ -866,11 +947,6 @@ import { execFileSync } from "child_process";
|
|
|
866
947
|
// src/config.ts
|
|
867
948
|
var WORKSPACE_DIR = process.env["WORKSPACE_DIR"] || "/home/vercel-sandbox/workspace";
|
|
868
949
|
|
|
869
|
-
// src/sleep.ts
|
|
870
|
-
function sleep(ms) {
|
|
871
|
-
return new Promise((r) => setTimeout(r, ms));
|
|
872
|
-
}
|
|
873
|
-
|
|
874
950
|
// src/ops/releases.ts
|
|
875
951
|
function list3(ctx, params = {}) {
|
|
876
952
|
return call(
|
|
@@ -2874,50 +2950,6 @@ import path5 from "path";
|
|
|
2874
2950
|
|
|
2875
2951
|
// src/ops/dataSources.ts
|
|
2876
2952
|
import { createHash as createHash2 } from "crypto";
|
|
2877
|
-
|
|
2878
|
-
// src/poll.ts
|
|
2879
|
-
async function pollUntil(read, isSettled, options) {
|
|
2880
|
-
const start2 = Date.now();
|
|
2881
|
-
let transientSince = null;
|
|
2882
|
-
while (true) {
|
|
2883
|
-
let value;
|
|
2884
|
-
try {
|
|
2885
|
-
value = await read();
|
|
2886
|
-
transientSince = null;
|
|
2887
|
-
} catch (err) {
|
|
2888
|
-
if (!isTransientError(err)) {
|
|
2889
|
-
throw err;
|
|
2890
|
-
}
|
|
2891
|
-
transientSince ??= Date.now();
|
|
2892
|
-
if (Date.now() - transientSince > TRANSIENT_GRACE_MS) {
|
|
2893
|
-
throw err;
|
|
2894
|
-
}
|
|
2895
|
-
options.onProgress?.(
|
|
2896
|
-
`retrying after a gateway error\u2026 (${elapsedSeconds(start2)}s)`
|
|
2897
|
-
);
|
|
2898
|
-
await sleep(options.pollMs);
|
|
2899
|
-
continue;
|
|
2900
|
-
}
|
|
2901
|
-
if (isSettled(value)) {
|
|
2902
|
-
return { settled: true, value };
|
|
2903
|
-
}
|
|
2904
|
-
if (Date.now() - start2 > options.timeoutMs) {
|
|
2905
|
-
return { settled: false, value };
|
|
2906
|
-
}
|
|
2907
|
-
if (options.describe) {
|
|
2908
|
-
options.onProgress?.(options.describe(value, start2));
|
|
2909
|
-
}
|
|
2910
|
-
await sleep(options.pollMs);
|
|
2911
|
-
}
|
|
2912
|
-
}
|
|
2913
|
-
function elapsedSeconds(start2) {
|
|
2914
|
-
return Math.round((Date.now() - start2) / 1e3);
|
|
2915
|
-
}
|
|
2916
|
-
function timedOut(timeoutMs, still) {
|
|
2917
|
-
return `Timed out after ${Math.round(timeoutMs / 1e3)}s ${still}`;
|
|
2918
|
-
}
|
|
2919
|
-
|
|
2920
|
-
// src/ops/dataSources.ts
|
|
2921
2953
|
var DEFAULT_WAIT_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
2922
2954
|
var POLL_MS2 = 3e3;
|
|
2923
2955
|
function base(appId) {
|
|
@@ -2998,6 +3030,7 @@ async function waitForIngest(ctx, params) {
|
|
|
2998
3030
|
timeoutMs,
|
|
2999
3031
|
pollMs: POLL_MS2,
|
|
3000
3032
|
describe: (tracked2, start2) => `ingesting\u2026 ${tracked2.length - pendingOf(tracked2).length}/${tracked2.length} done (${elapsedSeconds(start2)}s)`,
|
|
3033
|
+
progressKey: (tracked2) => pendingOf(tracked2).length,
|
|
3001
3034
|
onProgress
|
|
3002
3035
|
}
|
|
3003
3036
|
);
|
|
@@ -3017,33 +3050,49 @@ async function waitForIngest(ctx, params) {
|
|
|
3017
3050
|
documents: tracked.map(summarize)
|
|
3018
3051
|
};
|
|
3019
3052
|
}
|
|
3053
|
+
var FAILURES_PAGE = 50;
|
|
3020
3054
|
async function waitForCandidate(ctx, params) {
|
|
3021
3055
|
const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
3022
|
-
const pendingOf = (docs2) => docs2.filter((d) => d.status === "processing");
|
|
3023
3056
|
const outcome = await pollUntil(
|
|
3024
|
-
() =>
|
|
3025
|
-
|
|
3057
|
+
async () => {
|
|
3058
|
+
const { dataSources } = await list8(ctx);
|
|
3059
|
+
const source = dataSources.find((s) => s.slug === params.slug);
|
|
3060
|
+
if (!source) {
|
|
3061
|
+
throw new Error(`Data source "${params.slug}" not found.`);
|
|
3062
|
+
}
|
|
3063
|
+
return source.candidate?.progress ?? null;
|
|
3064
|
+
},
|
|
3065
|
+
(progress2) => progress2 === null || progress2.processing === 0,
|
|
3026
3066
|
{
|
|
3027
3067
|
timeoutMs,
|
|
3028
3068
|
pollMs: POLL_MS2,
|
|
3029
|
-
describe: (
|
|
3069
|
+
describe: (progress2, start2) => progress2 ? `rebuilding\u2026 ${progress2.done}/${progress2.total} done (${elapsedSeconds(start2)}s)` : `rebuilding\u2026 (${elapsedSeconds(start2)}s)`,
|
|
3070
|
+
progressKey: (progress2) => progress2?.processing ?? null,
|
|
3030
3071
|
onProgress: params.onProgress
|
|
3031
3072
|
}
|
|
3032
3073
|
);
|
|
3033
|
-
const
|
|
3074
|
+
const counts = outcome.value;
|
|
3075
|
+
const failed = counts && counts.error > 0 ? (await documents(ctx, {
|
|
3076
|
+
slug: params.slug,
|
|
3077
|
+
candidate: true,
|
|
3078
|
+
status: "error",
|
|
3079
|
+
limit: FAILURES_PAGE
|
|
3080
|
+
})).documents.map(summarize) : [];
|
|
3034
3081
|
if (!outcome.settled) {
|
|
3035
3082
|
return {
|
|
3036
3083
|
status: "timeout",
|
|
3037
|
-
|
|
3084
|
+
counts,
|
|
3085
|
+
documents: failed,
|
|
3038
3086
|
error: timedOut(
|
|
3039
3087
|
timeoutMs,
|
|
3040
|
-
`with ${
|
|
3088
|
+
`with ${counts?.processing ?? 0} document(s) still building`
|
|
3041
3089
|
)
|
|
3042
3090
|
};
|
|
3043
3091
|
}
|
|
3044
3092
|
return {
|
|
3045
|
-
status:
|
|
3046
|
-
|
|
3093
|
+
status: counts && counts.error > 0 ? "error" : "ready",
|
|
3094
|
+
counts,
|
|
3095
|
+
documents: failed
|
|
3047
3096
|
};
|
|
3048
3097
|
}
|
|
3049
3098
|
var DOCUMENTS_IDS_MAX = 200;
|
|
@@ -3056,7 +3105,10 @@ function documents(ctx, params) {
|
|
|
3056
3105
|
candidate: params.candidate || void 0,
|
|
3057
3106
|
ids: params.ids?.length ? params.ids.join(",") : void 0,
|
|
3058
3107
|
limit: params.limit,
|
|
3059
|
-
cursor: params.cursor
|
|
3108
|
+
cursor: params.cursor,
|
|
3109
|
+
order: params.order,
|
|
3110
|
+
status: params.status,
|
|
3111
|
+
filename: params.filename
|
|
3060
3112
|
})}`
|
|
3061
3113
|
);
|
|
3062
3114
|
}
|
|
@@ -3074,7 +3126,10 @@ async function allDocuments(ctx, params) {
|
|
|
3074
3126
|
candidate: params.candidate,
|
|
3075
3127
|
ids,
|
|
3076
3128
|
limit: 1e3,
|
|
3077
|
-
cursor
|
|
3129
|
+
cursor,
|
|
3130
|
+
order: params.order,
|
|
3131
|
+
status: params.status,
|
|
3132
|
+
filename: params.filename
|
|
3078
3133
|
});
|
|
3079
3134
|
out2.push(...page.documents ?? []);
|
|
3080
3135
|
cursor = page.nextCursor ?? void 0;
|
|
@@ -3165,7 +3220,10 @@ async function waitForMove(ctx, params) {
|
|
|
3165
3220
|
{
|
|
3166
3221
|
timeoutMs,
|
|
3167
3222
|
pollMs: POLL_MS2,
|
|
3168
|
-
describe: (source2, start2) =>
|
|
3223
|
+
describe: (source2, start2) => renderProgress(source2.migration.progress, start2),
|
|
3224
|
+
// A corpus of any size moves as long as it keeps moving; the timeout
|
|
3225
|
+
// bounds silence.
|
|
3226
|
+
progressKey: (source2) => source2.migration?.copied ?? null,
|
|
3169
3227
|
onProgress: params.onProgress
|
|
3170
3228
|
}
|
|
3171
3229
|
);
|
|
@@ -3359,6 +3417,9 @@ async function settle(ctx, params, isSettled) {
|
|
|
3359
3417
|
timeoutMs,
|
|
3360
3418
|
pollMs: POLL_MS3,
|
|
3361
3419
|
describe: describeProgress,
|
|
3420
|
+
// A load of any length is waited out while it moves; the timeout bounds
|
|
3421
|
+
// silence. Planning moves by objects listed, a run by documents.
|
|
3422
|
+
progressKey: (job2) => `${job2.state}:${job2.progress.done}`,
|
|
3362
3423
|
onProgress: params.onProgress
|
|
3363
3424
|
}
|
|
3364
3425
|
);
|
|
@@ -3394,14 +3455,15 @@ async function settle(ctx, params, isSettled) {
|
|
|
3394
3455
|
return { status: "done", job };
|
|
3395
3456
|
}
|
|
3396
3457
|
function describeProgress(job, start2) {
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3458
|
+
if (job.state === "planning" && job.enumerationDone) {
|
|
3459
|
+
return renderProgress(
|
|
3460
|
+
{ ...job.progress, phase: "planning" },
|
|
3461
|
+
start2,
|
|
3462
|
+
`reading a sample of ${job.counts.objectsSeen.toLocaleString()} objects`
|
|
3463
|
+
);
|
|
3400
3464
|
}
|
|
3401
|
-
const
|
|
3402
|
-
|
|
3403
|
-
const spend = `$${job.estimatedDollars.toFixed(2)}${job.budgetDollars !== null ? ` of $${job.budgetDollars.toFixed(2)}` : ""}`;
|
|
3404
|
-
return `${job.state}\u2026 ${processed.toLocaleString()}/${total.toLocaleString()} documents \xB7 ${spend} ${elapsed}`;
|
|
3465
|
+
const spend = job.state === "planning" ? null : `$${job.estimatedDollars.toFixed(2)}${job.budgetDollars !== null ? ` of $${job.budgetDollars.toFixed(2)}` : ""}`;
|
|
3466
|
+
return renderProgress(job.progress, start2, spend);
|
|
3405
3467
|
}
|
|
3406
3468
|
|
|
3407
3469
|
// src/commands/_shared/dataSources.ts
|
|
@@ -3695,7 +3757,10 @@ async function waitForHydration(ctx, params) {
|
|
|
3695
3757
|
{
|
|
3696
3758
|
timeoutMs,
|
|
3697
3759
|
pollMs: POLL_MS4,
|
|
3698
|
-
describe: (source2, start2) =>
|
|
3760
|
+
describe: (source2, start2) => renderProgress(source2.hydration.progress, start2),
|
|
3761
|
+
// A reload of any size is waited out while it moves; the timeout
|
|
3762
|
+
// bounds silence.
|
|
3763
|
+
progressKey: (source2) => source2.hydration?.copied ?? null,
|
|
3699
3764
|
onProgress: params.onProgress
|
|
3700
3765
|
}
|
|
3701
3766
|
);
|
|
@@ -4359,7 +4424,9 @@ Warming and sampling:
|
|
|
4359
4424
|
background; small sources reload inside the search and never show it.
|
|
4360
4425
|
\`hydrate\` starts that reload ahead of time \u2014 before a demo, say \u2014 and
|
|
4361
4426
|
\`--wait\` blocks until the index is back. \`datasources list\` shows the
|
|
4362
|
-
reload's progress under \`hydration\`.
|
|
4427
|
+
reload's progress under \`hydration\`. The same reload is what dedicated
|
|
4428
|
+
capacity runs on its own after a lost node or a resume; \`infra logs\` shows
|
|
4429
|
+
it start, and the source's \`hydration\` shows it land.
|
|
4363
4430
|
|
|
4364
4431
|
\`sample\` draws documents from a source into a new one that shares its
|
|
4365
4432
|
exact pinned config, so what you measure on the sample says something about
|
|
@@ -5074,8 +5141,12 @@ var dataSourcesSpecs = {
|
|
|
5074
5141
|
usage: "Usage: remy-admin datasources list"
|
|
5075
5142
|
},
|
|
5076
5143
|
"datasources status": {
|
|
5077
|
-
usage: "Usage: remy-admin datasources status [--source <slug>]",
|
|
5078
|
-
flags: {
|
|
5144
|
+
usage: "Usage: remy-admin datasources status [--source <slug>] [--status error] [--all]",
|
|
5145
|
+
flags: {
|
|
5146
|
+
source: { type: "string" },
|
|
5147
|
+
status: { type: "string" },
|
|
5148
|
+
all: { type: "boolean" }
|
|
5149
|
+
}
|
|
5079
5150
|
},
|
|
5080
5151
|
"datasources rm": {
|
|
5081
5152
|
usage: "Usage: remy-admin datasources rm [--source <slug>] (--document <id> | --filter <k=v,...|json>)",
|
|
@@ -5216,10 +5287,42 @@ async function dataSourcesList(ctx) {
|
|
|
5216
5287
|
}
|
|
5217
5288
|
async function dataSourcesStatus(ctx, a) {
|
|
5218
5289
|
const slug = sourceOf(a);
|
|
5219
|
-
const
|
|
5290
|
+
const status2 = a.str("status");
|
|
5291
|
+
if (status2 !== void 0 && status2 !== "error") {
|
|
5292
|
+
fatal("--status can only be 'error'.");
|
|
5293
|
+
}
|
|
5294
|
+
if (a.bool("all")) {
|
|
5295
|
+
const documents2 = await allDocuments(ctx, {
|
|
5296
|
+
slug,
|
|
5297
|
+
...status2 ? { status: "error" } : {}
|
|
5298
|
+
});
|
|
5299
|
+
out({
|
|
5300
|
+
dataSource: slug,
|
|
5301
|
+
documents: documents2.map(summarize)
|
|
5302
|
+
});
|
|
5303
|
+
return;
|
|
5304
|
+
}
|
|
5305
|
+
const { dataSources: sources2 } = await list8(ctx);
|
|
5306
|
+
const source = sources2.find((s) => s.slug === slug);
|
|
5307
|
+
if (!source) {
|
|
5308
|
+
out({ dataSource: slug, exists: false });
|
|
5309
|
+
return;
|
|
5310
|
+
}
|
|
5311
|
+
const failures = status2 === "error" || source.counts.error > 0 ? await documents(ctx, {
|
|
5312
|
+
slug,
|
|
5313
|
+
status: "error",
|
|
5314
|
+
limit: FAILURES_PAGE
|
|
5315
|
+
}) : null;
|
|
5220
5316
|
out({
|
|
5221
5317
|
dataSource: slug,
|
|
5222
|
-
|
|
5318
|
+
counts: source.counts,
|
|
5319
|
+
chunkCount: source.chunkCount,
|
|
5320
|
+
lastIngestedAt: source.lastIngestedAt,
|
|
5321
|
+
activeVersion: source.activeVersion,
|
|
5322
|
+
candidate: source.candidate,
|
|
5323
|
+
job: source.job,
|
|
5324
|
+
failures: (failures?.documents ?? []).map(summarize),
|
|
5325
|
+
moreFailures: !!failures?.nextCursor
|
|
5223
5326
|
});
|
|
5224
5327
|
}
|
|
5225
5328
|
async function dataSourcesRm(ctx, a) {
|
|
@@ -5515,7 +5618,8 @@ async function dataSourcesRevectorize(ctx, a) {
|
|
|
5515
5618
|
dataSource: slug,
|
|
5516
5619
|
candidateVersion: started.candidateVersion,
|
|
5517
5620
|
status: result.status,
|
|
5518
|
-
|
|
5621
|
+
counts: result.counts,
|
|
5622
|
+
failures: result.documents,
|
|
5519
5623
|
note: result.status === "error" ? "Some documents failed. Promote with --force to accept, or fix and re-run." : "Run `promote` to make this version live."
|
|
5520
5624
|
});
|
|
5521
5625
|
if (result.status === "error") {
|
|
@@ -5561,7 +5665,7 @@ matching passages with a citation pointing back at the source document.
|
|
|
5561
5665
|
Subcommands:
|
|
5562
5666
|
add Add one or more documents (skips unchanged files)
|
|
5563
5667
|
list List data sources with document counts
|
|
5564
|
-
status Show
|
|
5668
|
+
status Show a source's counts and its failed documents (--all walks every document)
|
|
5565
5669
|
rm Remove a document, or every document matching a filter
|
|
5566
5670
|
search Query a corpus \u2014 useful to sanity-check one you just built
|
|
5567
5671
|
create Create an empty source, optionally on dedicated capacity
|
|
@@ -5588,7 +5692,7 @@ Subcommands:
|
|
|
5588
5692
|
Usage:
|
|
5589
5693
|
remy-admin datasources add [--source <slug>] [--metadata <k=v,...>] [--wait] [--timeout <sec>] <file...>
|
|
5590
5694
|
remy-admin datasources list
|
|
5591
|
-
remy-admin datasources status [--source <slug>]
|
|
5695
|
+
remy-admin datasources status [--source <slug>] [--status error] [--all]
|
|
5592
5696
|
remy-admin datasources rm [--source <slug>] (--document <id> | --filter <k=v,...|json>)
|
|
5593
5697
|
remy-admin datasources search [--source <slug>] [search options] <query>
|
|
5594
5698
|
remy-admin datasources create --source <slug> [--name <name>] [--placement <resource-id|shared>] [rebuild settings...]
|
|
@@ -7501,6 +7605,21 @@ function get10(ctx, params) {
|
|
|
7501
7605
|
`${base6(ctx.appId)}/${encodeURIComponent(params.id)}`
|
|
7502
7606
|
);
|
|
7503
7607
|
}
|
|
7608
|
+
function logs(ctx, params) {
|
|
7609
|
+
const query3 = new URLSearchParams();
|
|
7610
|
+
if (params.after) {
|
|
7611
|
+
query3.set("after", params.after);
|
|
7612
|
+
}
|
|
7613
|
+
if (params.limit) {
|
|
7614
|
+
query3.set("limit", String(params.limit));
|
|
7615
|
+
}
|
|
7616
|
+
const search2 = query3.toString();
|
|
7617
|
+
return call(
|
|
7618
|
+
ctx,
|
|
7619
|
+
"GET",
|
|
7620
|
+
`${base6(ctx.appId)}/${encodeURIComponent(params.id)}/logs${search2 ? `?${search2}` : ""}`
|
|
7621
|
+
);
|
|
7622
|
+
}
|
|
7504
7623
|
function provision(ctx, params) {
|
|
7505
7624
|
return call(ctx, "POST", base6(ctx.appId), {
|
|
7506
7625
|
offeringId: params.offeringId,
|
|
@@ -7554,7 +7673,14 @@ async function waitForPhase(ctx, params) {
|
|
|
7554
7673
|
{
|
|
7555
7674
|
timeoutMs,
|
|
7556
7675
|
pollMs: POLL_MS5,
|
|
7557
|
-
describe: (resource2, start2) =>
|
|
7676
|
+
describe: (resource2, start2) => resource2.progress ? renderProgress(
|
|
7677
|
+
resource2.progress,
|
|
7678
|
+
start2,
|
|
7679
|
+
resource2.resizingTo ? `resizing to ${resource2.resizingTo.label}` : null
|
|
7680
|
+
) : `${resource2.phase}${resource2.detail ? ` \xB7 ${resource2.detail}` : ""}${resource2.resizingTo ? ` \xB7 resizing to ${resource2.resizingTo.label}` : ""}\u2026 (${elapsedSeconds(start2)}s)`,
|
|
7681
|
+
// A rebuild after a resume runs as long as it must; the timeout bounds
|
|
7682
|
+
// silence, and a phase or step change counts as movement.
|
|
7683
|
+
progressKey: (resource2) => `${resource2.phase}:${resource2.progress?.done ?? ""}:${resource2.detail ?? ""}`,
|
|
7558
7684
|
onProgress: params.onProgress
|
|
7559
7685
|
}
|
|
7560
7686
|
);
|
|
@@ -7586,6 +7712,11 @@ var infraSpecs = {
|
|
|
7586
7712
|
usage: "Usage: remy-admin infra get <id>",
|
|
7587
7713
|
positionals: [{ name: "id", required: true }]
|
|
7588
7714
|
},
|
|
7715
|
+
"infra logs": {
|
|
7716
|
+
usage: "Usage: remy-admin infra logs <id> [--follow] [--limit <n>]",
|
|
7717
|
+
positionals: [{ name: "id", required: true }],
|
|
7718
|
+
flags: { follow: { type: "boolean" }, limit: { type: "string" } }
|
|
7719
|
+
},
|
|
7589
7720
|
"infra provision": {
|
|
7590
7721
|
usage: "Usage: remy-admin infra provision --offering <id> [--name <name>] [--wait] [--timeout <sec>]",
|
|
7591
7722
|
flags: {
|
|
@@ -7657,6 +7788,30 @@ async function infraList(ctx, a) {
|
|
|
7657
7788
|
async function infraGet(ctx, a) {
|
|
7658
7789
|
out(await get10(ctx, { id: a.req("id") }));
|
|
7659
7790
|
}
|
|
7791
|
+
var FOLLOW_POLL_MS = 4e3;
|
|
7792
|
+
async function infraLogs(ctx, a) {
|
|
7793
|
+
const id = a.req("id");
|
|
7794
|
+
const limitRaw = a.str("limit");
|
|
7795
|
+
const limit = limitRaw ? Number(limitRaw) : void 0;
|
|
7796
|
+
let { logs: logs2 } = await logs(ctx, { id, ...limit ? { limit } : {} });
|
|
7797
|
+
out({ logs: logs2 });
|
|
7798
|
+
if (!a.bool("follow")) {
|
|
7799
|
+
return;
|
|
7800
|
+
}
|
|
7801
|
+
let after = logs2.length > 0 ? logs2[logs2.length - 1].id : void 0;
|
|
7802
|
+
while (true) {
|
|
7803
|
+
await new Promise((resolve2) => setTimeout(resolve2, FOLLOW_POLL_MS));
|
|
7804
|
+
({ logs: logs2 } = await logs(ctx, {
|
|
7805
|
+
id,
|
|
7806
|
+
...after ? { after } : {},
|
|
7807
|
+
limit: 500
|
|
7808
|
+
}));
|
|
7809
|
+
if (logs2.length > 0) {
|
|
7810
|
+
out({ logs: logs2 });
|
|
7811
|
+
after = logs2[logs2.length - 1].id;
|
|
7812
|
+
}
|
|
7813
|
+
}
|
|
7814
|
+
}
|
|
7660
7815
|
function pricingOf(resource) {
|
|
7661
7816
|
const offering = resource.offering;
|
|
7662
7817
|
if (!offering) {
|
|
@@ -7755,6 +7910,7 @@ async function infraResize(ctx, a) {
|
|
|
7755
7910
|
var infraHandlers = {
|
|
7756
7911
|
"infra list": infraList,
|
|
7757
7912
|
"infra get": infraGet,
|
|
7913
|
+
"infra logs": infraLogs,
|
|
7758
7914
|
"infra provision": infraProvision,
|
|
7759
7915
|
"infra hibernate": infraHibernate,
|
|
7760
7916
|
"infra resume": infraResume,
|
|
@@ -7776,7 +7932,8 @@ the price it committed to. Every action below is audited.
|
|
|
7776
7932
|
|
|
7777
7933
|
Subcommands:
|
|
7778
7934
|
list Resources on this app, plus the offerings you can provision
|
|
7779
|
-
get One resource
|
|
7935
|
+
get One resource: billing to date, state timeline, recent log, attached sources
|
|
7936
|
+
logs The platform's log for a resource (--follow to keep reading)
|
|
7780
7937
|
provision Lease a new resource (needs a month's credits; prints the price)
|
|
7781
7938
|
hibernate Park it: data kept, searches paused, compute charge stops
|
|
7782
7939
|
resume Bring a hibernated resource back
|
|
@@ -7787,6 +7944,7 @@ Subcommands:
|
|
|
7787
7944
|
Usage:
|
|
7788
7945
|
remy-admin infra list [--include-destroyed]
|
|
7789
7946
|
remy-admin infra get <id>
|
|
7947
|
+
remy-admin infra logs <id> [--follow] [--limit <n>]
|
|
7790
7948
|
remy-admin infra provision --offering <id> [--name <name>] [--wait] [--timeout <sec>]
|
|
7791
7949
|
remy-admin infra hibernate <id> [--wait] [--timeout <sec>]
|
|
7792
7950
|
remy-admin infra resume <id> [--wait] [--timeout <sec>]
|
|
@@ -7808,26 +7966,43 @@ Placing a data source on a resource:
|
|
|
7808
7966
|
|
|
7809
7967
|
Searches on a source whose resource is not active fail with
|
|
7810
7968
|
capacity_<phase>: capacity_hibernated once parked, capacity_hibernating /
|
|
7811
|
-
capacity_resuming while it moves.
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
user; the stable code
|
|
7969
|
+
capacity_resuming while it moves. Once active, a source whose index is being
|
|
7970
|
+
rebuilt from durable storage (after a resume, a resize or a lost node)
|
|
7971
|
+
answers index_warming with the rebuild's progress and ETA until it lands;
|
|
7972
|
+
\`datasources list\` shows it under hydration and the resource under
|
|
7973
|
+
progress. The messages are written for the app's end user; the stable code
|
|
7974
|
+
is what to act on.
|
|
7816
7975
|
|
|
7817
7976
|
Resizing:
|
|
7818
|
-
A resize keeps the
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7977
|
+
A resize keeps the documents: the resource is parked, its spec is swapped,
|
|
7978
|
+
and it comes back up with its sources' indexes rebuilt from durable storage
|
|
7979
|
+
in the background (nothing is re-embedded). Searches on those sources answer
|
|
7980
|
+
index_warming until the rebuild lands. A hibernated resource swaps in place
|
|
7981
|
+
and stays parked. Growing needs a month's credits at the new rate; shrinking
|
|
7982
|
+
is refused below what the resource holds (resize_too_small). \`infra get\`
|
|
7983
|
+
shows resizingTo until the swap has happened.
|
|
7824
7984
|
|
|
7825
7985
|
Phases and timing:
|
|
7826
7986
|
requested \u2192 provisioning \u2192 active \u21C4 hibernated \u2192 destroyed, with hibernating /
|
|
7827
7987
|
resuming / decommissioning in between and failed when a change cannot complete
|
|
7828
|
-
(retried automatically; resume or hibernate to retry by hand).
|
|
7829
|
-
takes
|
|
7830
|
-
with
|
|
7988
|
+
(retried automatically; resume or hibernate to retry by hand). A transition
|
|
7989
|
+
takes a minute or two; the rebuild that follows a resume runs under its own
|
|
7990
|
+
progress with a measured ETA. --wait gives up only after --timeout (default
|
|
7991
|
+
600s) WITHOUT movement, so a long rebuild is waited out while it moves.
|
|
7992
|
+
|
|
7993
|
+
Billing and the log:
|
|
7994
|
+
\`infra get\` reports resource.billing: what the resource has actually been
|
|
7995
|
+
charged to date (from the ledger, exact across resizes), the hours at each
|
|
7996
|
+
rate, and when it was last billed. Rates are on resource.offering.
|
|
7997
|
+
|
|
7998
|
+
The log is the platform's narration of the resource, not the instance's
|
|
7999
|
+
stdout: each step a transition went through ("Waiting for capacity",
|
|
8000
|
+
"Rebuilding archive v1 from its artifacts: 14,333,673 document(s)"), each
|
|
8001
|
+
failed attempt, and each failure with the
|
|
8002
|
+
pod's recent Kubernetes events and the warnings-and-errors tail of the
|
|
8003
|
+
instance log at that moment (line.data). \`infra get\` includes the newest
|
|
8004
|
+
200 lines; \`infra logs\` pages the rest and, with --follow, prints new lines
|
|
8005
|
+
every few seconds as their own JSON document until interrupted.
|
|
7831
8006
|
|
|
7832
8007
|
--wait exit codes: 0 reached the target phase \xB7 1 the platform reported failure \xB7
|
|
7833
8008
|
2 still transitioning when --timeout elapsed (default 600s).`;
|