hobots 2.0.1 → 2.3.0
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/README.md +33 -2
- package/dist/index.cjs +278 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -3
- package/dist/index.d.ts +60 -3
- package/dist/index.js +278 -44
- package/dist/index.js.map +1 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +69 -1
- package/dist/protocol.d.ts +69 -1
- package/docs/api-reference.md +13 -0
- package/docs/protocol.md +25 -1
- package/docs/tasks.md +38 -0
- package/docs/telemetry.md +11 -0
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -103,7 +103,7 @@ function scrubSecrets(text) {
|
|
|
103
103
|
|
|
104
104
|
// src/utils.ts
|
|
105
105
|
var SDK_NAME = "hobots";
|
|
106
|
-
var SDK_VERSION = true ? "2.0
|
|
106
|
+
var SDK_VERSION = true ? "2.3.0" : "0.0.0-dev";
|
|
107
107
|
function isNode() {
|
|
108
108
|
return typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
109
109
|
}
|
|
@@ -396,6 +396,7 @@ var Client = class {
|
|
|
396
396
|
#options;
|
|
397
397
|
#config;
|
|
398
398
|
transport;
|
|
399
|
+
machine;
|
|
399
400
|
constructor(options, config = resolveConfig(options)) {
|
|
400
401
|
this.#options = options;
|
|
401
402
|
this.debug = !!options.debug;
|
|
@@ -415,6 +416,10 @@ var Client = class {
|
|
|
415
416
|
get config() {
|
|
416
417
|
return this.#config;
|
|
417
418
|
}
|
|
419
|
+
/** Sampler de recursos da máquina — cada evento passa a levar `contexts.machine`. */
|
|
420
|
+
attachMachineSampler(sampler) {
|
|
421
|
+
this.machine = sampler;
|
|
422
|
+
}
|
|
418
423
|
/** Serialização explícita nunca inclui o secret. */
|
|
419
424
|
toJSON() {
|
|
420
425
|
return { sdk: SDK_NAME, version: SDK_VERSION, baseUrl: this.#config.baseUrl };
|
|
@@ -446,6 +451,8 @@ var Client = class {
|
|
|
446
451
|
prepareEvent(event, hint, scope2) {
|
|
447
452
|
const tags = { ...this.options.tags, ...scope2.tags, ...event.tags, ...hint?.tags };
|
|
448
453
|
const extra = { ...scope2.extra, ...event.extra, ...hint?.extra };
|
|
454
|
+
const sampled = this.machine?.sample();
|
|
455
|
+
const machine = sampled ? { machine: sampled } : {};
|
|
449
456
|
return {
|
|
450
457
|
...event,
|
|
451
458
|
type: hint?.type ?? event.type ?? scope2.type ?? "error",
|
|
@@ -454,7 +461,7 @@ var Client = class {
|
|
|
454
461
|
tags: Object.keys(tags).length > 0 ? tags : void 0,
|
|
455
462
|
extra: Object.keys(extra).length > 0 ? extra : void 0,
|
|
456
463
|
user: event.user ?? scope2.user,
|
|
457
|
-
contexts: { ...runtimeContexts(), ...scope2.contexts, ...event.contexts },
|
|
464
|
+
contexts: { ...runtimeContexts(), ...machine, ...scope2.contexts, ...event.contexts },
|
|
458
465
|
breadcrumbs: scope2.breadcrumbs.length > 0 ? [...scope2.breadcrumbs] : event.breadcrumbs,
|
|
459
466
|
fingerprint: hint?.fingerprint ?? event.fingerprint ?? scope2.fingerprint
|
|
460
467
|
};
|
|
@@ -489,8 +496,9 @@ var DEFAULT_INTERVAL_MS = 3e4;
|
|
|
489
496
|
var MIN_REPORTED_INTERVAL_MS = 1e3;
|
|
490
497
|
var MAX_REPORTED_INTERVAL_MS = 9e5;
|
|
491
498
|
var Heartbeat = class {
|
|
492
|
-
constructor(client2, options = {}, instanceId) {
|
|
499
|
+
constructor(client2, options = {}, instanceId, sampler) {
|
|
493
500
|
this.client = client2;
|
|
501
|
+
this.sampler = sampler;
|
|
494
502
|
this.intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
495
503
|
this.instanceId = instanceId;
|
|
496
504
|
this.name = options.name ?? instanceId;
|
|
@@ -529,7 +537,9 @@ var Heartbeat = class {
|
|
|
529
537
|
name: this.name,
|
|
530
538
|
interval_ms: Math.min(Math.max(this.intervalMs, MIN_REPORTED_INTERVAL_MS), MAX_REPORTED_INTERVAL_MS),
|
|
531
539
|
timestamp: nowISO(),
|
|
532
|
-
metadata: this.metadata
|
|
540
|
+
metadata: this.metadata,
|
|
541
|
+
// recursos da máquina a cada beat — a série da instância no app
|
|
542
|
+
machine: this.sampler?.sample()
|
|
533
543
|
});
|
|
534
544
|
}
|
|
535
545
|
};
|
|
@@ -560,50 +570,184 @@ function hasInstalledGlobalHandlers() {
|
|
|
560
570
|
return installed;
|
|
561
571
|
}
|
|
562
572
|
function installGlobalHandlers(client2, getScope) {
|
|
563
|
-
if (installed) return;
|
|
573
|
+
if (installed) return () => void 0;
|
|
564
574
|
installed = true;
|
|
565
575
|
if (isNode()) {
|
|
566
|
-
|
|
567
|
-
"uncaughtException",
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
})
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
);
|
|
586
|
-
|
|
587
|
-
"
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
return;
|
|
576
|
+
const onUncaught = markInternal((error) => {
|
|
577
|
+
client2.captureException(error, { type: "fatal", tags: { mechanism: "uncaughtException" } }, getScope());
|
|
578
|
+
void client2.flush(2e3).then(async () => {
|
|
579
|
+
if (externalListenerCount("uncaughtException") === 0) {
|
|
580
|
+
await awaitEmergencyTasks(EMERGENCY_REPORT_CAP_MS);
|
|
581
|
+
console.error(error);
|
|
582
|
+
process.exit(1);
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
const onRejection = markInternal((reason) => {
|
|
587
|
+
client2.captureException(reason, { type: "error", tags: { mechanism: "unhandledRejection" } }, getScope());
|
|
588
|
+
void client2.flush(2e3);
|
|
589
|
+
});
|
|
590
|
+
const onBeforeExit = markInternal(() => {
|
|
591
|
+
void client2.flush(2e3);
|
|
592
|
+
});
|
|
593
|
+
process.on("uncaughtException", onUncaught);
|
|
594
|
+
process.on("unhandledRejection", onRejection);
|
|
595
|
+
process.on("beforeExit", onBeforeExit);
|
|
596
|
+
return () => {
|
|
597
|
+
process.off("uncaughtException", onUncaught);
|
|
598
|
+
process.off("unhandledRejection", onRejection);
|
|
599
|
+
process.off("beforeExit", onBeforeExit);
|
|
600
|
+
installed = false;
|
|
601
|
+
};
|
|
593
602
|
}
|
|
594
603
|
if (typeof window !== "undefined") {
|
|
595
|
-
|
|
604
|
+
const onError = (event) => {
|
|
596
605
|
client2.captureException(event.error ?? event.message, { tags: { mechanism: "onerror" } }, getScope());
|
|
597
|
-
}
|
|
598
|
-
|
|
606
|
+
};
|
|
607
|
+
const onRejection = (event) => {
|
|
599
608
|
client2.captureException(event.reason, { tags: { mechanism: "onunhandledrejection" } }, getScope());
|
|
600
|
-
}
|
|
601
|
-
|
|
609
|
+
};
|
|
610
|
+
const onPageHide = () => {
|
|
602
611
|
void client2.flush(1e3);
|
|
603
|
-
}
|
|
612
|
+
};
|
|
613
|
+
window.addEventListener("error", onError);
|
|
614
|
+
window.addEventListener("unhandledrejection", onRejection);
|
|
615
|
+
window.addEventListener("pagehide", onPageHide);
|
|
616
|
+
return () => {
|
|
617
|
+
window.removeEventListener("error", onError);
|
|
618
|
+
window.removeEventListener("unhandledrejection", onRejection);
|
|
619
|
+
window.removeEventListener("pagehide", onPageHide);
|
|
620
|
+
installed = false;
|
|
621
|
+
};
|
|
604
622
|
}
|
|
623
|
+
return () => {
|
|
624
|
+
installed = false;
|
|
625
|
+
};
|
|
605
626
|
}
|
|
606
627
|
|
|
628
|
+
// src/machine.ts
|
|
629
|
+
var MIN_CPU_WINDOW_MS = 1e3;
|
|
630
|
+
var round1 = (value) => Math.round(value * 10) / 10;
|
|
631
|
+
var clampPercent = (value) => Math.min(100, Math.max(0, value));
|
|
632
|
+
var MachineSampler = class {
|
|
633
|
+
constructor(instanceId, logger) {
|
|
634
|
+
this.instanceId = instanceId;
|
|
635
|
+
this.logger = logger;
|
|
636
|
+
}
|
|
637
|
+
os;
|
|
638
|
+
fs;
|
|
639
|
+
ready = false;
|
|
640
|
+
prevCpu;
|
|
641
|
+
prevProcessCpu;
|
|
642
|
+
prevAt = 0;
|
|
643
|
+
lastCpuPercent = null;
|
|
644
|
+
lastProcessCpuPercent = null;
|
|
645
|
+
/** Carrega os módulos e tira a leitura-base de CPU (a primeira amostra ainda sai com cpu_percent null). */
|
|
646
|
+
async start() {
|
|
647
|
+
if (!isNode()) return;
|
|
648
|
+
try {
|
|
649
|
+
this.os = await import("os");
|
|
650
|
+
this.fs = await import("fs");
|
|
651
|
+
this.prevCpu = this.cpuTotals();
|
|
652
|
+
this.prevProcessCpu = process.cpuUsage();
|
|
653
|
+
this.prevAt = Date.now();
|
|
654
|
+
this.ready = true;
|
|
655
|
+
} catch (error) {
|
|
656
|
+
this.logger.debug("m\xE9tricas de m\xE1quina indispon\xEDveis neste runtime", error);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
sample() {
|
|
660
|
+
if (!this.ready || !this.os) return void 0;
|
|
661
|
+
try {
|
|
662
|
+
const os = this.os;
|
|
663
|
+
const cpuCount = Math.max(1, os.cpus().length);
|
|
664
|
+
this.updateCpu(cpuCount);
|
|
665
|
+
const snapshot = {
|
|
666
|
+
sampled_at: nowISO(),
|
|
667
|
+
instance_id: this.instanceId,
|
|
668
|
+
hostname: os.hostname(),
|
|
669
|
+
os: process.platform,
|
|
670
|
+
arch: process.arch,
|
|
671
|
+
cpu_count: cpuCount,
|
|
672
|
+
cpu_percent: this.lastCpuPercent,
|
|
673
|
+
process: {
|
|
674
|
+
pid: process.pid,
|
|
675
|
+
uptime_s: Math.round(process.uptime()),
|
|
676
|
+
cpu_percent: this.lastProcessCpuPercent
|
|
677
|
+
},
|
|
678
|
+
source: "stdlib"
|
|
679
|
+
};
|
|
680
|
+
if (process.platform !== "win32") {
|
|
681
|
+
const load = os.loadavg()[0];
|
|
682
|
+
if (typeof load === "number" && Number.isFinite(load)) snapshot.load_1 = round1(load);
|
|
683
|
+
}
|
|
684
|
+
const memTotal = os.totalmem();
|
|
685
|
+
const memFree = os.freemem();
|
|
686
|
+
if (memTotal > 0) {
|
|
687
|
+
snapshot.mem_total_bytes = memTotal;
|
|
688
|
+
snapshot.mem_available_bytes = memFree;
|
|
689
|
+
snapshot.mem_percent = round1(clampPercent((memTotal - memFree) / memTotal * 100));
|
|
690
|
+
}
|
|
691
|
+
const disk = this.diskUsage();
|
|
692
|
+
if (disk) Object.assign(snapshot, disk);
|
|
693
|
+
const mem = process.memoryUsage();
|
|
694
|
+
snapshot.process.rss_bytes = mem.rss;
|
|
695
|
+
snapshot.process.heap_used_bytes = mem.heapUsed;
|
|
696
|
+
return snapshot;
|
|
697
|
+
} catch (error) {
|
|
698
|
+
this.logger.debug("falha ao coletar m\xE9tricas de m\xE1quina", error);
|
|
699
|
+
return void 0;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
cpuTotals() {
|
|
703
|
+
let busy = 0;
|
|
704
|
+
let total = 0;
|
|
705
|
+
for (const cpu of this.os.cpus()) {
|
|
706
|
+
const t = cpu.times;
|
|
707
|
+
const cpuBusy = t.user + t.nice + t.sys + t.irq;
|
|
708
|
+
busy += cpuBusy;
|
|
709
|
+
total += cpuBusy + t.idle;
|
|
710
|
+
}
|
|
711
|
+
return { busy, total };
|
|
712
|
+
}
|
|
713
|
+
/** Média desde a leitura anterior; leituras com menos de 1s de janela reutilizam a última média. */
|
|
714
|
+
updateCpu(cpuCount) {
|
|
715
|
+
const now = Date.now();
|
|
716
|
+
const elapsedMs = now - this.prevAt;
|
|
717
|
+
if (elapsedMs < MIN_CPU_WINDOW_MS) return;
|
|
718
|
+
const cpu = this.cpuTotals();
|
|
719
|
+
if (this.prevCpu) {
|
|
720
|
+
const total = cpu.total - this.prevCpu.total;
|
|
721
|
+
if (total > 0) this.lastCpuPercent = round1(clampPercent((cpu.busy - this.prevCpu.busy) / total * 100));
|
|
722
|
+
}
|
|
723
|
+
this.prevCpu = cpu;
|
|
724
|
+
const usage = process.cpuUsage(this.prevProcessCpu);
|
|
725
|
+
const usedMicros = usage.user + usage.system;
|
|
726
|
+
this.lastProcessCpuPercent = round1(clampPercent(usedMicros / (elapsedMs * 1e3 * cpuCount) * 100));
|
|
727
|
+
this.prevProcessCpu = process.cpuUsage();
|
|
728
|
+
this.prevAt = now;
|
|
729
|
+
}
|
|
730
|
+
diskUsage() {
|
|
731
|
+
const statfs = this.fs?.statfsSync;
|
|
732
|
+
if (typeof statfs !== "function") return void 0;
|
|
733
|
+
try {
|
|
734
|
+
const path = process.cwd();
|
|
735
|
+
const stat = statfs(path);
|
|
736
|
+
const total = stat.bsize * stat.blocks;
|
|
737
|
+
const free = stat.bsize * stat.bavail;
|
|
738
|
+
if (total <= 0) return void 0;
|
|
739
|
+
return {
|
|
740
|
+
disk_path: path,
|
|
741
|
+
disk_total_bytes: total,
|
|
742
|
+
disk_free_bytes: free,
|
|
743
|
+
disk_percent: round1(clampPercent((total - free) / total * 100))
|
|
744
|
+
};
|
|
745
|
+
} catch {
|
|
746
|
+
return void 0;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
};
|
|
750
|
+
|
|
607
751
|
// src/scope.ts
|
|
608
752
|
var Scope = class _Scope {
|
|
609
753
|
tags = {};
|
|
@@ -1143,6 +1287,7 @@ var MAX_ITEM_MESSAGE_CHARS = 2e3;
|
|
|
1143
1287
|
var MAX_ITEM_PAYLOAD_BYTES = 16384;
|
|
1144
1288
|
var ITEMS_FLUSH_AT_BUFFERED = 100;
|
|
1145
1289
|
var ITEMS_DRAIN_MS = 15e3;
|
|
1290
|
+
var PROGRESS_FLUSH_MS = 1e3;
|
|
1146
1291
|
function scrubPayloadValue(value, depth) {
|
|
1147
1292
|
if (typeof value === "string") return scrubSecrets(value);
|
|
1148
1293
|
if (depth >= 4 || value === null || typeof value !== "object") return value;
|
|
@@ -1177,12 +1322,28 @@ var RunReporter = class {
|
|
|
1177
1322
|
failed: (message, payload, options) => this.addItem("failed", message, payload, options?.id),
|
|
1178
1323
|
occurrence: (message, payload, options) => this.addItem("occurrence", message, payload, options?.id)
|
|
1179
1324
|
};
|
|
1325
|
+
const progress = Object.defineProperties(
|
|
1326
|
+
{
|
|
1327
|
+
total: (total) => this.setProgress(this.progressCurrent, total),
|
|
1328
|
+
advance: (count = 1) => this.setProgress(this.progressCurrent + count, this.progressTotal),
|
|
1329
|
+
set: (current, total) => this.setProgress(current, total ?? this.progressTotal)
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
current: { enumerable: true, get: () => this.progressCurrent },
|
|
1333
|
+
snapshot: {
|
|
1334
|
+
enumerable: true,
|
|
1335
|
+
get: () => this.progressTotal == null ? null : { current: this.progressCurrent, total: this.progressTotal }
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
// defineProperties não tipa os getters adicionados — a interface é a fonte de verdade
|
|
1339
|
+
);
|
|
1180
1340
|
const signal = this.abortController.signal;
|
|
1181
1341
|
this.context = {
|
|
1182
1342
|
runId,
|
|
1183
1343
|
task,
|
|
1184
1344
|
log,
|
|
1185
1345
|
items,
|
|
1346
|
+
progress,
|
|
1186
1347
|
tx,
|
|
1187
1348
|
signal,
|
|
1188
1349
|
throwIfCanceled: () => {
|
|
@@ -1226,6 +1387,14 @@ var RunReporter = class {
|
|
|
1226
1387
|
uploadQueue = [];
|
|
1227
1388
|
/** Uma vez que a instalação recusa anexos, para de tentar (e de avisar) nesta run. */
|
|
1228
1389
|
attachmentsUnsupported = false;
|
|
1390
|
+
// Progresso (ctx.progress): snapshot absoluto, enviado com throttle via piggyback
|
|
1391
|
+
// em `enqueue()` — nunca gera tráfego próprio enquanto logs/heartbeat já fluem.
|
|
1392
|
+
progressCurrent = 0;
|
|
1393
|
+
progressTotal = null;
|
|
1394
|
+
/** Snapshot ainda não entregue ao servidor. */
|
|
1395
|
+
progressDirty = false;
|
|
1396
|
+
progressTimer;
|
|
1397
|
+
progressWarned = false;
|
|
1229
1398
|
get isDead() {
|
|
1230
1399
|
return this.dead;
|
|
1231
1400
|
}
|
|
@@ -1243,6 +1412,7 @@ var RunReporter = class {
|
|
|
1243
1412
|
this.abort();
|
|
1244
1413
|
this.dead = true;
|
|
1245
1414
|
this.clearFlushTimer();
|
|
1415
|
+
this.clearProgressTimer();
|
|
1246
1416
|
this.buffer = [];
|
|
1247
1417
|
this.itemsClosed = true;
|
|
1248
1418
|
this.clearItemsTimer();
|
|
@@ -1322,13 +1492,63 @@ var RunReporter = class {
|
|
|
1322
1492
|
reportSuccess() {
|
|
1323
1493
|
this.stopCancelWatch();
|
|
1324
1494
|
this.clearFlushTimer();
|
|
1495
|
+
this.forceFinalProgress();
|
|
1325
1496
|
this.enqueue({ status: "succeeded", logs: this.takeLogs() });
|
|
1326
1497
|
}
|
|
1327
1498
|
reportFailure(error) {
|
|
1328
1499
|
this.stopCancelWatch();
|
|
1329
1500
|
this.clearFlushTimer();
|
|
1501
|
+
this.forceFinalProgress();
|
|
1330
1502
|
this.enqueue({ status: "failed", error, logs: this.takeLogs() });
|
|
1331
1503
|
}
|
|
1504
|
+
// ── Progresso ────────────────────────────────────────────────────────────────
|
|
1505
|
+
/** Valida, clampa e marca o snapshot como pendente; agenda flush só se nada mais vai sair. */
|
|
1506
|
+
setProgress(current, total) {
|
|
1507
|
+
if (this.dead) return;
|
|
1508
|
+
if (total != null && (!Number.isInteger(total) || total < 1)) {
|
|
1509
|
+
if (!this.progressWarned) {
|
|
1510
|
+
this.progressWarned = true;
|
|
1511
|
+
this.logger.warn(`ctx.progress: total inv\xE1lido (${String(total)}) \u2014 precisa ser inteiro >= 1; ignorado`);
|
|
1512
|
+
}
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
const safeCurrent = Number.isFinite(current) ? Math.max(0, Math.floor(current)) : this.progressCurrent;
|
|
1516
|
+
const next = total == null ? safeCurrent : Math.min(safeCurrent, total);
|
|
1517
|
+
if (next === this.progressCurrent && total === this.progressTotal) return;
|
|
1518
|
+
this.progressCurrent = next;
|
|
1519
|
+
this.progressTotal = total;
|
|
1520
|
+
if (total == null) return;
|
|
1521
|
+
this.progressDirty = true;
|
|
1522
|
+
if (this.progressTimer) return;
|
|
1523
|
+
this.progressTimer = setTimeout(() => {
|
|
1524
|
+
this.progressTimer = void 0;
|
|
1525
|
+
this.flushProgress();
|
|
1526
|
+
}, PROGRESS_FLUSH_MS);
|
|
1527
|
+
unrefTimer(this.progressTimer);
|
|
1528
|
+
}
|
|
1529
|
+
flushProgress() {
|
|
1530
|
+
this.clearProgressTimer();
|
|
1531
|
+
if (this.dead || !this.progressDirty) return;
|
|
1532
|
+
if (this.buffer.length > 0) this.flushLogs();
|
|
1533
|
+
else this.enqueue({ status: "running" });
|
|
1534
|
+
}
|
|
1535
|
+
clearProgressTimer() {
|
|
1536
|
+
if (this.progressTimer) {
|
|
1537
|
+
clearTimeout(this.progressTimer);
|
|
1538
|
+
this.progressTimer = void 0;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
/** O PATCH terminal sempre leva o snapshot final (o app mostra "87/100" numa run que falhou). */
|
|
1542
|
+
forceFinalProgress() {
|
|
1543
|
+
this.clearProgressTimer();
|
|
1544
|
+
this.progressDirty = this.progressTotal != null;
|
|
1545
|
+
}
|
|
1546
|
+
/** Consome o snapshot pendente para pegar carona no próximo PATCH. */
|
|
1547
|
+
takeProgress() {
|
|
1548
|
+
if (!this.progressDirty || this.progressTotal == null) return void 0;
|
|
1549
|
+
this.progressDirty = false;
|
|
1550
|
+
return { current: this.progressCurrent, total: this.progressTotal };
|
|
1551
|
+
}
|
|
1332
1552
|
/**
|
|
1333
1553
|
* Heartbeat de cancelamento: enquanto o handler roda, um PATCH 'running' vazio
|
|
1334
1554
|
* periódico faz o servidor responder 409 se a run foi cancelada no app — o que
|
|
@@ -1591,11 +1811,14 @@ var RunReporter = class {
|
|
|
1591
1811
|
new Promise((resolve) => unrefTimer(setTimeout(resolve, timeoutMs)))
|
|
1592
1812
|
]);
|
|
1593
1813
|
}
|
|
1594
|
-
enqueue(
|
|
1814
|
+
enqueue(updateIn) {
|
|
1595
1815
|
if (this.dead) {
|
|
1596
|
-
this.salvageLogs(
|
|
1816
|
+
this.salvageLogs(updateIn.logs);
|
|
1597
1817
|
return;
|
|
1598
1818
|
}
|
|
1819
|
+
this.clearProgressTimer();
|
|
1820
|
+
const progress = this.takeProgress();
|
|
1821
|
+
const update = progress ? { ...updateIn, progress } : updateIn;
|
|
1599
1822
|
this.pendingUpdates++;
|
|
1600
1823
|
this.chain = this.chain.then(async () => {
|
|
1601
1824
|
if (this.dead) {
|
|
@@ -1621,6 +1844,7 @@ var RunReporter = class {
|
|
|
1621
1844
|
this.buffer.unshift(...update.logs);
|
|
1622
1845
|
this.scheduleFlush();
|
|
1623
1846
|
}
|
|
1847
|
+
if (update.progress && this.progressTotal != null) this.progressDirty = true;
|
|
1624
1848
|
this.logger.error(`update da run ${this.runId} perdido:`, error);
|
|
1625
1849
|
}
|
|
1626
1850
|
}).finally(() => {
|
|
@@ -1842,7 +2066,10 @@ var TaskAgent = class {
|
|
|
1842
2066
|
// o servidor calcula a tolerância de offline (3×) a partir disto em
|
|
1843
2067
|
// agentes poll-only — sem o campo, um poll lento flaparia offline/online.
|
|
1844
2068
|
// Clampado à faixa aceita pelo schema do poll (1s..15min).
|
|
1845
|
-
poll_interval_ms: Math.min(Math.max(this.pollIntervalMs, 1e3), 9e5)
|
|
2069
|
+
poll_interval_ms: Math.min(Math.max(this.pollIntervalMs, 1e3), 9e5),
|
|
2070
|
+
// recursos da máquina — alimenta a série da instância em agentes sem heartbeat
|
|
2071
|
+
// (o servidor grava no máx. 1 ponto/30s por instância)
|
|
2072
|
+
machine: this.options.machineSampler?.sample()
|
|
1846
2073
|
},
|
|
1847
2074
|
max: Math.min(MAX_CONCURRENCY, this.concurrency - this.activeRuns.size),
|
|
1848
2075
|
tasks: [...this.registry.keys()]
|
|
@@ -1990,7 +2217,9 @@ var DEFAULT_MAX_BREADCRUMBS = 100;
|
|
|
1990
2217
|
var client;
|
|
1991
2218
|
var scope = new Scope();
|
|
1992
2219
|
var heartbeat;
|
|
2220
|
+
var machineSampler;
|
|
1993
2221
|
var agent;
|
|
2222
|
+
var uninstallGlobalHandlers;
|
|
1994
2223
|
var registry = /* @__PURE__ */ new Map();
|
|
1995
2224
|
var warnedTasksDisabled = false;
|
|
1996
2225
|
function init(options) {
|
|
@@ -2003,21 +2232,26 @@ function init(options) {
|
|
|
2003
2232
|
void agent.stop(0);
|
|
2004
2233
|
agent = void 0;
|
|
2005
2234
|
}
|
|
2235
|
+
uninstallGlobalHandlers?.();
|
|
2236
|
+
uninstallGlobalHandlers = void 0;
|
|
2006
2237
|
warnedTasksDisabled = false;
|
|
2007
2238
|
const config = resolveConfig(options);
|
|
2008
2239
|
client = new Client(options, config);
|
|
2240
|
+
machineSampler = options.machineMetrics === false ? void 0 : new MachineSampler(options.instanceId, client.logger);
|
|
2241
|
+
void machineSampler?.start();
|
|
2242
|
+
client.attachMachineSampler(machineSampler);
|
|
2009
2243
|
if (options.captureUnhandled !== false) {
|
|
2010
|
-
installGlobalHandlers(client, () => scope);
|
|
2244
|
+
uninstallGlobalHandlers = installGlobalHandlers(client, () => scope);
|
|
2011
2245
|
}
|
|
2012
2246
|
if (options.heartbeat) {
|
|
2013
2247
|
const heartbeatOptions = options.heartbeat === true ? {} : options.heartbeat;
|
|
2014
|
-
heartbeat = new Heartbeat(client, heartbeatOptions, options.instanceId);
|
|
2248
|
+
heartbeat = new Heartbeat(client, heartbeatOptions, options.instanceId, machineSampler);
|
|
2015
2249
|
heartbeat.start();
|
|
2016
2250
|
}
|
|
2017
2251
|
if (options.tasks) {
|
|
2018
2252
|
const tasksOptions = options.tasks === true ? {} : options.tasks;
|
|
2019
2253
|
agent = new TaskAgent(
|
|
2020
|
-
{ ...tasksOptions, config, instanceId: options.instanceId, debug: options.debug, client },
|
|
2254
|
+
{ ...tasksOptions, config, instanceId: options.instanceId, debug: options.debug, client, machineSampler },
|
|
2021
2255
|
registry
|
|
2022
2256
|
);
|
|
2023
2257
|
}
|