hobots 1.9.0 → 1.9.2
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 +9 -7
- package/dist/index.cjs +64 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -43
- package/dist/index.d.ts +38 -43
- package/dist/index.js +64 -9
- package/dist/index.js.map +1 -1
- package/docs/api-reference.md +14 -20
- package/docs/concepts.md +1 -1
- package/docs/getting-started.md +1 -1
- package/docs/tasks.md +21 -13
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Breadcrumb, EventUser, Severity, EventPayload, TransactionPayload, HeartbeatPayload, StepStatus, RunLogLevel, StepData, RunAttachmentContentType } from './protocol.cjs';
|
|
2
2
|
export { AgentInfo, Envelope, EnvelopeItem, ExceptionData, PollRequest, PollResponse, RunAttachmentConfirmRequest, RunAttachmentConfirmResponse, RunAttachmentCreateRequest, RunAttachmentCreateResponse, RunDescriptor, RunError, RunLogEntry, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, StackFrame } from './protocol.cjs';
|
|
3
3
|
|
|
4
|
+
/** Aceita tudo que o handler pode ter em mãos: bytes ou um caminho de arquivo (só Node). */
|
|
5
|
+
type AttachInput = Uint8Array | ArrayBuffer | string;
|
|
6
|
+
|
|
4
7
|
/** API oficial da Hobots — o SDK sempre fala com ela em produção. */
|
|
5
8
|
declare const DEFAULT_BASE_URL = "https://api2.hobots.app";
|
|
6
9
|
interface ResolvedConfig {
|
|
@@ -123,31 +126,6 @@ declare class Transaction {
|
|
|
123
126
|
finish(): void;
|
|
124
127
|
}
|
|
125
128
|
|
|
126
|
-
interface AttachOptions {
|
|
127
|
-
/** Legenda curta, exibida sob a miniatura no app. Passa pelo scrub de segredos. */
|
|
128
|
-
caption?: string;
|
|
129
|
-
/** Nível da linha de log que carrega o anexo. Default: 'info' */
|
|
130
|
-
level?: RunLogLevel;
|
|
131
|
-
/** Texto da linha de log. Default: a legenda, ou 'captura de tela' */
|
|
132
|
-
message?: string;
|
|
133
|
-
/** Informe quando os magic bytes não bastarem (o SDK sempre prefere o que detectar). */
|
|
134
|
-
contentType?: RunAttachmentContentType;
|
|
135
|
-
}
|
|
136
|
-
type AttachFailureReason =
|
|
137
|
-
/** A instalação do Hobots não tem anexos habilitados (ou a API é anterior ao recurso) */
|
|
138
|
-
'unsupported' | 'too-large' | 'quota' | 'read-failed'
|
|
139
|
-
/** Formato não reconhecido ou fora de PNG/JPEG/WEBP */
|
|
140
|
-
| 'unsupported-format' | 'upload-failed' | 'canceled';
|
|
141
|
-
interface AttachResult {
|
|
142
|
-
/** Id do anexo, o mesmo referenciado na linha de log */
|
|
143
|
-
id: string;
|
|
144
|
-
ok: boolean;
|
|
145
|
-
/** Motivo do insucesso — para diagnóstico; `attach` nunca lança */
|
|
146
|
-
reason?: AttachFailureReason;
|
|
147
|
-
}
|
|
148
|
-
/** Aceita tudo que o handler pode ter em mãos: bytes ou um caminho de arquivo (só Node). */
|
|
149
|
-
type AttachInput = Uint8Array | ArrayBuffer | string;
|
|
150
|
-
|
|
151
129
|
/** Opções de tasks dentro de `init({ tasks: ... })`. Credencial (clientSecret), identidade (instanceId) e debug vêm do init. */
|
|
152
130
|
interface TasksOptions {
|
|
153
131
|
/** Intervalo entre polls sem trabalho. Default: 5_000 (mínimo 1_000) */
|
|
@@ -168,6 +146,13 @@ interface TasksOptions {
|
|
|
168
146
|
* uma run sem reporte por ~60s. Default: 5_000 (mínimo 1_000, máximo 15_000)
|
|
169
147
|
*/
|
|
170
148
|
cancelCheckIntervalMs?: number;
|
|
149
|
+
/**
|
|
150
|
+
* Tempo de graça após ctx.signal disparar (run cancelada no app) antes do
|
|
151
|
+
* agente desistir de esperar o handler e liberar o slot de concorrência. O
|
|
152
|
+
* handler não é morto — se ele nunca checar ctx.signal, pode continuar
|
|
153
|
+
* rodando em segundo plano; só o agente para de esperar por ele. Default: 10_000
|
|
154
|
+
*/
|
|
155
|
+
cancelGraceMs?: number;
|
|
171
156
|
/**
|
|
172
157
|
* Instala handlers de SIGINT/SIGTERM/uncaughtException que reportam as runs
|
|
173
158
|
* ativas como falha (AgentTerminated) antes do processo morrer. Nunca interfere
|
|
@@ -202,22 +187,6 @@ interface RunContext {
|
|
|
202
187
|
throwIfCanceled(): void;
|
|
203
188
|
/** Sleep cancelável: rejeita com `RunCanceled` se ctx.signal disparar antes de ms. */
|
|
204
189
|
sleep(ms: number): Promise<void>;
|
|
205
|
-
/**
|
|
206
|
-
* Anexa uma imagem (print da tela) a uma linha de log da execução — a evidência
|
|
207
|
-
* visual aparece como miniatura junto do log, na aba "logs do agente".
|
|
208
|
-
*
|
|
209
|
-
* Aceita bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo
|
|
210
|
-
* (só em Node). A linha de log é registrada imediatamente; o upload roda em
|
|
211
|
-
* segundo plano e **nunca bloqueia nem lança** — falhas viram um aviso no log da
|
|
212
|
-
* run e um `{ ok: false, reason }` no retorno, que pode ser ignorado com `void`.
|
|
213
|
-
*
|
|
214
|
-
* PNG, JPEG ou WEBP, até 5 MB, no máximo 20 anexos por execução.
|
|
215
|
-
*
|
|
216
|
-
* ```ts
|
|
217
|
-
* await ctx.attach(await page.screenshot(), { caption: 'portal após o login' });
|
|
218
|
-
* ```
|
|
219
|
-
*/
|
|
220
|
-
attach(image: AttachInput, options?: AttachOptions): Promise<AttachResult>;
|
|
221
190
|
}
|
|
222
191
|
/** O retorno do handler é ignorado — nada além de status/logs/erro é enviado ao servidor. */
|
|
223
192
|
type TaskHandler<P = Record<string, unknown>> = (params: P, ctx: RunContext) => void | Promise<void>;
|
|
@@ -265,17 +234,43 @@ interface InitOptions {
|
|
|
265
234
|
/** Itens por envelope antes de flush imediato. Default: 10 */
|
|
266
235
|
maxBatchSize?: number;
|
|
267
236
|
}
|
|
237
|
+
/** Imagem enviada junto de um capture* — com legenda e content-type opcionais. */
|
|
238
|
+
interface CaptureAttachment {
|
|
239
|
+
/** Bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo (só em Node) */
|
|
240
|
+
image: AttachInput;
|
|
241
|
+
/** Legenda curta, exibida sob a miniatura no app. Passa pelo scrub de segredos. */
|
|
242
|
+
caption?: string;
|
|
243
|
+
/** Informe quando os magic bytes não bastarem (o SDK sempre prefere o que detectar). */
|
|
244
|
+
contentType?: RunAttachmentContentType;
|
|
245
|
+
}
|
|
268
246
|
interface CaptureHint {
|
|
269
247
|
level?: Severity;
|
|
270
248
|
tags?: Record<string, string>;
|
|
271
249
|
extra?: Record<string, unknown>;
|
|
272
250
|
fingerprint?: string[];
|
|
251
|
+
/**
|
|
252
|
+
* Print da tela enviado junto da captura. Dentro de uma execução de task, a imagem
|
|
253
|
+
* vira anexo da linha de log da execução que espelha o evento — miniatura na aba
|
|
254
|
+
* "logs do agente". Fora de uma execução não há onde pendurar a imagem: o SDK
|
|
255
|
+
* descarta com um aviso. O upload roda em segundo plano e **nunca bloqueia nem lança**.
|
|
256
|
+
*
|
|
257
|
+
* PNG, JPEG ou WEBP, até 5 MB, no máximo 20 anexos por execução.
|
|
258
|
+
*
|
|
259
|
+
* ```ts
|
|
260
|
+
* Hobots.captureException(error, { attachment: { image: await page.screenshot(), caption: 'tela no momento do erro' } });
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
attachment?: AttachInput | CaptureAttachment;
|
|
273
264
|
}
|
|
274
265
|
|
|
275
266
|
/** Inicializa o SDK. Chame uma vez, o mais cedo possível no programa. */
|
|
276
267
|
declare function init(options: InitOptions): void;
|
|
277
268
|
declare function getClient(): Client | undefined;
|
|
278
|
-
/**
|
|
269
|
+
/**
|
|
270
|
+
* Captura uma exceção e retorna o event_id (undefined se o SDK não foi inicializado).
|
|
271
|
+
* `hint.attachment` envia um print junto — dentro de uma execução de task, ele aparece
|
|
272
|
+
* como miniatura na linha de log da run correspondente ao erro.
|
|
273
|
+
*/
|
|
279
274
|
declare function captureException(error: unknown, hint?: CaptureHint): string | undefined;
|
|
280
275
|
declare function captureMessage(message: string, level?: Severity, hint?: CaptureHint): string | undefined;
|
|
281
276
|
/** Registra um breadcrumb — anexado aos próximos eventos como trilha do que aconteceu antes. */
|
|
@@ -308,4 +303,4 @@ declare function close(timeoutMs?: number): Promise<boolean>;
|
|
|
308
303
|
|
|
309
304
|
declare function scrubSecrets(text: string): string;
|
|
310
305
|
|
|
311
|
-
export { type
|
|
306
|
+
export { type AttachInput, Breadcrumb, type BreadcrumbInput, type CaptureAttachment, type CaptureHint, Client, DEFAULT_BASE_URL, EventPayload, EventUser, type HeartbeatOptions, HeartbeatPayload, type InitOptions, RunAttachmentContentType, type RunContext, RunLogLevel, Scope, Severity, Step, StepData, type TaskHandler, type TasksOptions, Transaction, TransactionPayload, addBreadcrumb, captureException, captureMessage, close, flush, getClient, init, register, scrubSecrets, setContext, setExtra, setTag, setTags, setUser, start, startTransaction, stop, withScope };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Breadcrumb, EventUser, Severity, EventPayload, TransactionPayload, HeartbeatPayload, StepStatus, RunLogLevel, StepData, RunAttachmentContentType } from './protocol.js';
|
|
2
2
|
export { AgentInfo, Envelope, EnvelopeItem, ExceptionData, PollRequest, PollResponse, RunAttachmentConfirmRequest, RunAttachmentConfirmResponse, RunAttachmentCreateRequest, RunAttachmentCreateResponse, RunDescriptor, RunError, RunLogEntry, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, StackFrame } from './protocol.js';
|
|
3
3
|
|
|
4
|
+
/** Aceita tudo que o handler pode ter em mãos: bytes ou um caminho de arquivo (só Node). */
|
|
5
|
+
type AttachInput = Uint8Array | ArrayBuffer | string;
|
|
6
|
+
|
|
4
7
|
/** API oficial da Hobots — o SDK sempre fala com ela em produção. */
|
|
5
8
|
declare const DEFAULT_BASE_URL = "https://api2.hobots.app";
|
|
6
9
|
interface ResolvedConfig {
|
|
@@ -123,31 +126,6 @@ declare class Transaction {
|
|
|
123
126
|
finish(): void;
|
|
124
127
|
}
|
|
125
128
|
|
|
126
|
-
interface AttachOptions {
|
|
127
|
-
/** Legenda curta, exibida sob a miniatura no app. Passa pelo scrub de segredos. */
|
|
128
|
-
caption?: string;
|
|
129
|
-
/** Nível da linha de log que carrega o anexo. Default: 'info' */
|
|
130
|
-
level?: RunLogLevel;
|
|
131
|
-
/** Texto da linha de log. Default: a legenda, ou 'captura de tela' */
|
|
132
|
-
message?: string;
|
|
133
|
-
/** Informe quando os magic bytes não bastarem (o SDK sempre prefere o que detectar). */
|
|
134
|
-
contentType?: RunAttachmentContentType;
|
|
135
|
-
}
|
|
136
|
-
type AttachFailureReason =
|
|
137
|
-
/** A instalação do Hobots não tem anexos habilitados (ou a API é anterior ao recurso) */
|
|
138
|
-
'unsupported' | 'too-large' | 'quota' | 'read-failed'
|
|
139
|
-
/** Formato não reconhecido ou fora de PNG/JPEG/WEBP */
|
|
140
|
-
| 'unsupported-format' | 'upload-failed' | 'canceled';
|
|
141
|
-
interface AttachResult {
|
|
142
|
-
/** Id do anexo, o mesmo referenciado na linha de log */
|
|
143
|
-
id: string;
|
|
144
|
-
ok: boolean;
|
|
145
|
-
/** Motivo do insucesso — para diagnóstico; `attach` nunca lança */
|
|
146
|
-
reason?: AttachFailureReason;
|
|
147
|
-
}
|
|
148
|
-
/** Aceita tudo que o handler pode ter em mãos: bytes ou um caminho de arquivo (só Node). */
|
|
149
|
-
type AttachInput = Uint8Array | ArrayBuffer | string;
|
|
150
|
-
|
|
151
129
|
/** Opções de tasks dentro de `init({ tasks: ... })`. Credencial (clientSecret), identidade (instanceId) e debug vêm do init. */
|
|
152
130
|
interface TasksOptions {
|
|
153
131
|
/** Intervalo entre polls sem trabalho. Default: 5_000 (mínimo 1_000) */
|
|
@@ -168,6 +146,13 @@ interface TasksOptions {
|
|
|
168
146
|
* uma run sem reporte por ~60s. Default: 5_000 (mínimo 1_000, máximo 15_000)
|
|
169
147
|
*/
|
|
170
148
|
cancelCheckIntervalMs?: number;
|
|
149
|
+
/**
|
|
150
|
+
* Tempo de graça após ctx.signal disparar (run cancelada no app) antes do
|
|
151
|
+
* agente desistir de esperar o handler e liberar o slot de concorrência. O
|
|
152
|
+
* handler não é morto — se ele nunca checar ctx.signal, pode continuar
|
|
153
|
+
* rodando em segundo plano; só o agente para de esperar por ele. Default: 10_000
|
|
154
|
+
*/
|
|
155
|
+
cancelGraceMs?: number;
|
|
171
156
|
/**
|
|
172
157
|
* Instala handlers de SIGINT/SIGTERM/uncaughtException que reportam as runs
|
|
173
158
|
* ativas como falha (AgentTerminated) antes do processo morrer. Nunca interfere
|
|
@@ -202,22 +187,6 @@ interface RunContext {
|
|
|
202
187
|
throwIfCanceled(): void;
|
|
203
188
|
/** Sleep cancelável: rejeita com `RunCanceled` se ctx.signal disparar antes de ms. */
|
|
204
189
|
sleep(ms: number): Promise<void>;
|
|
205
|
-
/**
|
|
206
|
-
* Anexa uma imagem (print da tela) a uma linha de log da execução — a evidência
|
|
207
|
-
* visual aparece como miniatura junto do log, na aba "logs do agente".
|
|
208
|
-
*
|
|
209
|
-
* Aceita bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo
|
|
210
|
-
* (só em Node). A linha de log é registrada imediatamente; o upload roda em
|
|
211
|
-
* segundo plano e **nunca bloqueia nem lança** — falhas viram um aviso no log da
|
|
212
|
-
* run e um `{ ok: false, reason }` no retorno, que pode ser ignorado com `void`.
|
|
213
|
-
*
|
|
214
|
-
* PNG, JPEG ou WEBP, até 5 MB, no máximo 20 anexos por execução.
|
|
215
|
-
*
|
|
216
|
-
* ```ts
|
|
217
|
-
* await ctx.attach(await page.screenshot(), { caption: 'portal após o login' });
|
|
218
|
-
* ```
|
|
219
|
-
*/
|
|
220
|
-
attach(image: AttachInput, options?: AttachOptions): Promise<AttachResult>;
|
|
221
190
|
}
|
|
222
191
|
/** O retorno do handler é ignorado — nada além de status/logs/erro é enviado ao servidor. */
|
|
223
192
|
type TaskHandler<P = Record<string, unknown>> = (params: P, ctx: RunContext) => void | Promise<void>;
|
|
@@ -265,17 +234,43 @@ interface InitOptions {
|
|
|
265
234
|
/** Itens por envelope antes de flush imediato. Default: 10 */
|
|
266
235
|
maxBatchSize?: number;
|
|
267
236
|
}
|
|
237
|
+
/** Imagem enviada junto de um capture* — com legenda e content-type opcionais. */
|
|
238
|
+
interface CaptureAttachment {
|
|
239
|
+
/** Bytes (`Uint8Array`/`ArrayBuffer`/`Buffer`) ou um caminho de arquivo (só em Node) */
|
|
240
|
+
image: AttachInput;
|
|
241
|
+
/** Legenda curta, exibida sob a miniatura no app. Passa pelo scrub de segredos. */
|
|
242
|
+
caption?: string;
|
|
243
|
+
/** Informe quando os magic bytes não bastarem (o SDK sempre prefere o que detectar). */
|
|
244
|
+
contentType?: RunAttachmentContentType;
|
|
245
|
+
}
|
|
268
246
|
interface CaptureHint {
|
|
269
247
|
level?: Severity;
|
|
270
248
|
tags?: Record<string, string>;
|
|
271
249
|
extra?: Record<string, unknown>;
|
|
272
250
|
fingerprint?: string[];
|
|
251
|
+
/**
|
|
252
|
+
* Print da tela enviado junto da captura. Dentro de uma execução de task, a imagem
|
|
253
|
+
* vira anexo da linha de log da execução que espelha o evento — miniatura na aba
|
|
254
|
+
* "logs do agente". Fora de uma execução não há onde pendurar a imagem: o SDK
|
|
255
|
+
* descarta com um aviso. O upload roda em segundo plano e **nunca bloqueia nem lança**.
|
|
256
|
+
*
|
|
257
|
+
* PNG, JPEG ou WEBP, até 5 MB, no máximo 20 anexos por execução.
|
|
258
|
+
*
|
|
259
|
+
* ```ts
|
|
260
|
+
* Hobots.captureException(error, { attachment: { image: await page.screenshot(), caption: 'tela no momento do erro' } });
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
attachment?: AttachInput | CaptureAttachment;
|
|
273
264
|
}
|
|
274
265
|
|
|
275
266
|
/** Inicializa o SDK. Chame uma vez, o mais cedo possível no programa. */
|
|
276
267
|
declare function init(options: InitOptions): void;
|
|
277
268
|
declare function getClient(): Client | undefined;
|
|
278
|
-
/**
|
|
269
|
+
/**
|
|
270
|
+
* Captura uma exceção e retorna o event_id (undefined se o SDK não foi inicializado).
|
|
271
|
+
* `hint.attachment` envia um print junto — dentro de uma execução de task, ele aparece
|
|
272
|
+
* como miniatura na linha de log da run correspondente ao erro.
|
|
273
|
+
*/
|
|
279
274
|
declare function captureException(error: unknown, hint?: CaptureHint): string | undefined;
|
|
280
275
|
declare function captureMessage(message: string, level?: Severity, hint?: CaptureHint): string | undefined;
|
|
281
276
|
/** Registra um breadcrumb — anexado aos próximos eventos como trilha do que aconteceu antes. */
|
|
@@ -308,4 +303,4 @@ declare function close(timeoutMs?: number): Promise<boolean>;
|
|
|
308
303
|
|
|
309
304
|
declare function scrubSecrets(text: string): string;
|
|
310
305
|
|
|
311
|
-
export { type
|
|
306
|
+
export { type AttachInput, Breadcrumb, type BreadcrumbInput, type CaptureAttachment, type CaptureHint, Client, DEFAULT_BASE_URL, EventPayload, EventUser, type HeartbeatOptions, HeartbeatPayload, type InitOptions, RunAttachmentContentType, type RunContext, RunLogLevel, Scope, Severity, Step, StepData, type TaskHandler, type TasksOptions, Transaction, TransactionPayload, addBreadcrumb, captureException, captureMessage, close, flush, getClient, init, register, scrubSecrets, setContext, setExtra, setTag, setTags, setUser, start, startTransaction, stop, withScope };
|
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 ? "1.9.
|
|
106
|
+
var SDK_VERSION = true ? "1.9.1" : "0.0.0-dev";
|
|
107
107
|
function isNode() {
|
|
108
108
|
return typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
109
109
|
}
|
|
@@ -1114,8 +1114,7 @@ var RunReporter = class {
|
|
|
1114
1114
|
throwIfCanceled: () => {
|
|
1115
1115
|
if (signal.aborted) throw runCanceledError();
|
|
1116
1116
|
},
|
|
1117
|
-
sleep: (ms) => cancelableSleep(ms, signal)
|
|
1118
|
-
attach: (image, options) => this.attach(image, options)
|
|
1117
|
+
sleep: (ms) => cancelableSleep(ms, signal)
|
|
1119
1118
|
};
|
|
1120
1119
|
}
|
|
1121
1120
|
context;
|
|
@@ -1260,7 +1259,8 @@ var RunReporter = class {
|
|
|
1260
1259
|
/**
|
|
1261
1260
|
* Registra a linha de log com o id do anexo (síncrono, na ordem certa) e dispara
|
|
1262
1261
|
* o upload em segundo plano. Nunca lança: todo caminho de erro vira `{ ok: false }`
|
|
1263
|
-
* com um aviso no log da run.
|
|
1262
|
+
* com um aviso no log da run. Chega ao handler pelos capture* do SDK — o hint
|
|
1263
|
+
* `attachment` de Hobots.captureException/captureMessage cai aqui via run-context-store.
|
|
1264
1264
|
*/
|
|
1265
1265
|
async attach(image, options = {}) {
|
|
1266
1266
|
const id = uuid4();
|
|
@@ -1447,6 +1447,9 @@ async function runWithRunContext(store, fn) {
|
|
|
1447
1447
|
function currentRunTransaction() {
|
|
1448
1448
|
return storage?.getStore()?.tx;
|
|
1449
1449
|
}
|
|
1450
|
+
function currentRunAttach() {
|
|
1451
|
+
return storage?.getStore()?.attach;
|
|
1452
|
+
}
|
|
1450
1453
|
|
|
1451
1454
|
// src/tasks/shutdown.ts
|
|
1452
1455
|
var WATCHED_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
@@ -1498,6 +1501,7 @@ var MIN_POLL_INTERVAL_MS = 1e3;
|
|
|
1498
1501
|
var MAX_CONCURRENCY = 5;
|
|
1499
1502
|
var POLL_RETRY_DELAYS_MS = [1e3, 4e3, 16e3];
|
|
1500
1503
|
var AUTH_FAILURE_INTERVAL_MS = 3e4;
|
|
1504
|
+
var DEFAULT_CANCEL_GRACE_MS = 1e4;
|
|
1501
1505
|
function hostname() {
|
|
1502
1506
|
if (!isNode()) return void 0;
|
|
1503
1507
|
return process.env.HOSTNAME || process.env.COMPUTERNAME || void 0;
|
|
@@ -1516,6 +1520,7 @@ var TaskAgent = class {
|
|
|
1516
1520
|
this.taskTimeoutMs = options.taskTimeoutMs;
|
|
1517
1521
|
this.logFlushIntervalMs = options.logFlushIntervalMs;
|
|
1518
1522
|
this.cancelCheckIntervalMs = options.cancelCheckIntervalMs;
|
|
1523
|
+
this.cancelGraceMs = options.cancelGraceMs ?? DEFAULT_CANCEL_GRACE_MS;
|
|
1519
1524
|
this.logger.debug("agente configurado", { baseUrl: config.tasksBaseUrl });
|
|
1520
1525
|
}
|
|
1521
1526
|
logger;
|
|
@@ -1527,6 +1532,7 @@ var TaskAgent = class {
|
|
|
1527
1532
|
taskTimeoutMs;
|
|
1528
1533
|
logFlushIntervalMs;
|
|
1529
1534
|
cancelCheckIntervalMs;
|
|
1535
|
+
cancelGraceMs;
|
|
1530
1536
|
state = "idle";
|
|
1531
1537
|
timer;
|
|
1532
1538
|
pollAbort;
|
|
@@ -1688,7 +1694,10 @@ var TaskAgent = class {
|
|
|
1688
1694
|
}
|
|
1689
1695
|
this.logger.debug(`executando run ${run.id} (${run.task})`);
|
|
1690
1696
|
try {
|
|
1691
|
-
await runWithRunContext(
|
|
1697
|
+
await runWithRunContext(
|
|
1698
|
+
{ runId: run.id, tx, attach: (image, options) => reporter.attach(image, options) },
|
|
1699
|
+
() => this.invokeWithTimeout(handler, run, reporter)
|
|
1700
|
+
);
|
|
1692
1701
|
await reporter.finalizeAttachments();
|
|
1693
1702
|
tx.setStatus("ok");
|
|
1694
1703
|
tx.finish();
|
|
@@ -1708,14 +1717,26 @@ var TaskAgent = class {
|
|
|
1708
1717
|
}
|
|
1709
1718
|
async invokeWithTimeout(handler, run, reporter) {
|
|
1710
1719
|
const invocation = Promise.resolve().then(() => handler(run.params, reporter.context));
|
|
1711
|
-
|
|
1720
|
+
const races = [];
|
|
1721
|
+
if (this.taskTimeoutMs && this.taskTimeoutMs > 0) {
|
|
1722
|
+
races.push(sleep(this.taskTimeoutMs).then(() => TIMEOUT_SENTINEL));
|
|
1723
|
+
}
|
|
1724
|
+
if (this.cancelGraceMs > 0) {
|
|
1725
|
+
races.push(waitForCancelGrace(reporter.context.signal, this.cancelGraceMs).then(() => CANCEL_SENTINEL));
|
|
1726
|
+
}
|
|
1727
|
+
if (races.length === 0) {
|
|
1712
1728
|
await invocation;
|
|
1713
1729
|
return;
|
|
1714
1730
|
}
|
|
1731
|
+
const outcome = await Promise.race([invocation, ...races]);
|
|
1732
|
+
if (outcome !== TIMEOUT_SENTINEL && outcome !== CANCEL_SENTINEL) return;
|
|
1733
|
+
if (outcome === CANCEL_SENTINEL) {
|
|
1734
|
+
this.logger.warn(
|
|
1735
|
+
`run ${run.id} cancelada \u2014 handler n\xE3o respondeu a ctx.signal em ${this.cancelGraceMs}ms, liberando o slot (o handler pode continuar rodando em segundo plano)`
|
|
1736
|
+
);
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1715
1739
|
const timeoutMs = this.taskTimeoutMs;
|
|
1716
|
-
const timeout = sleep(timeoutMs).then(() => TIMEOUT_SENTINEL);
|
|
1717
|
-
const outcome = await Promise.race([invocation, timeout]);
|
|
1718
|
-
if (outcome !== TIMEOUT_SENTINEL) return;
|
|
1719
1740
|
reporter.abort();
|
|
1720
1741
|
invocation.then(() => this.logger.warn(`run ${run.id} terminou depois do timeout de ${timeoutMs}ms`)).catch(() => this.logger.warn(`run ${run.id} falhou depois do timeout de ${timeoutMs}ms (erro descartado)`));
|
|
1721
1742
|
throw Object.assign(new Error(`timeout ap\xF3s ${timeoutMs}ms (o handler pode continuar em background)`), {
|
|
@@ -1724,6 +1745,16 @@ var TaskAgent = class {
|
|
|
1724
1745
|
}
|
|
1725
1746
|
};
|
|
1726
1747
|
var TIMEOUT_SENTINEL = /* @__PURE__ */ Symbol("task-timeout");
|
|
1748
|
+
var CANCEL_SENTINEL = /* @__PURE__ */ Symbol("task-canceled");
|
|
1749
|
+
function waitForCancelGrace(signal, graceMs) {
|
|
1750
|
+
return new Promise((resolve) => {
|
|
1751
|
+
if (signal.aborted) {
|
|
1752
|
+
setTimeout(resolve, graceMs);
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
signal.addEventListener("abort", () => setTimeout(resolve, graceMs), { once: true });
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1727
1758
|
var MAX_ERROR_MESSAGE_CHARS = 1e4;
|
|
1728
1759
|
var MAX_ERROR_STACK_CHARS = 2e4;
|
|
1729
1760
|
function toRunError(error) {
|
|
@@ -1778,10 +1809,34 @@ function init(options) {
|
|
|
1778
1809
|
function getClient() {
|
|
1779
1810
|
return client;
|
|
1780
1811
|
}
|
|
1812
|
+
function toRunLogLevel(level) {
|
|
1813
|
+
return level === "fatal" ? "error" : level;
|
|
1814
|
+
}
|
|
1815
|
+
function forwardAttachment(attachment, message, level) {
|
|
1816
|
+
const attach = currentRunAttach();
|
|
1817
|
+
if (!attach) {
|
|
1818
|
+
client?.logger.warn("attachment descartado \u2014 s\xF3 \xE9 suportado dentro de uma execu\xE7\xE3o de task (register/start)");
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
const withMeta = typeof attachment === "object" && "image" in attachment ? attachment : { image: attachment };
|
|
1822
|
+
void attach(withMeta.image, {
|
|
1823
|
+
message,
|
|
1824
|
+
level: toRunLogLevel(level),
|
|
1825
|
+
caption: withMeta.caption,
|
|
1826
|
+
contentType: withMeta.contentType
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1781
1829
|
function captureException(error, hint) {
|
|
1830
|
+
if (hint?.attachment) {
|
|
1831
|
+
const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
1832
|
+
forwardAttachment(hint.attachment, message, hint.level ?? "error");
|
|
1833
|
+
}
|
|
1782
1834
|
return client?.captureException(error, hint, scope);
|
|
1783
1835
|
}
|
|
1784
1836
|
function captureMessage(message, level = "info", hint) {
|
|
1837
|
+
if (hint?.attachment) {
|
|
1838
|
+
forwardAttachment(hint.attachment, message, hint.level ?? level);
|
|
1839
|
+
}
|
|
1785
1840
|
return client?.captureMessage(message, level, hint, scope);
|
|
1786
1841
|
}
|
|
1787
1842
|
function addBreadcrumb(crumb) {
|