hobots 1.7.5 → 1.8.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 +14 -34
- package/dist/index.cjs +27 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -36
- package/dist/index.d.ts +19 -36
- package/dist/index.js +27 -80
- package/dist/index.js.map +1 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +9 -25
- package/dist/protocol.d.ts +9 -25
- package/docs/README.md +4 -4
- package/docs/api-reference.md +5 -27
- package/docs/concepts.md +27 -51
- package/docs/getting-started.md +1 -1
- package/docs/protocol.md +1 -2
- package/docs/tasks.md +6 -6
- package/docs/{monitor.md → telemetry.md} +13 -35
- package/package.json +2 -2
package/dist/protocol.d.cts
CHANGED
|
@@ -125,18 +125,18 @@ interface EventPayload {
|
|
|
125
125
|
release?: string;
|
|
126
126
|
environment?: string;
|
|
127
127
|
}
|
|
128
|
-
/** Status de
|
|
129
|
-
type
|
|
130
|
-
interface
|
|
128
|
+
/** Status de uma step (etapa). `warning` = terminou, mas merece atenção (não é falha). */
|
|
129
|
+
type StepStatus = 'ok' | 'warning' | 'error' | 'cancelled';
|
|
130
|
+
interface StepData {
|
|
131
131
|
/** 16 hex */
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
step_id: string;
|
|
133
|
+
parent_step_id?: string;
|
|
134
134
|
op?: string;
|
|
135
135
|
description?: string;
|
|
136
|
-
status?:
|
|
136
|
+
status?: StepStatus;
|
|
137
137
|
/** ISO 8601 */
|
|
138
138
|
start_timestamp: string;
|
|
139
|
-
/** ISO 8601 (fim
|
|
139
|
+
/** ISO 8601 (fim da step) */
|
|
140
140
|
timestamp: string;
|
|
141
141
|
data?: Record<string, unknown>;
|
|
142
142
|
}
|
|
@@ -147,26 +147,13 @@ interface TransactionPayload {
|
|
|
147
147
|
status: string;
|
|
148
148
|
start_timestamp: string;
|
|
149
149
|
timestamp: string;
|
|
150
|
-
|
|
150
|
+
steps: StepData[];
|
|
151
151
|
tags?: Record<string, string>;
|
|
152
152
|
release?: string;
|
|
153
153
|
environment?: string;
|
|
154
154
|
/** Correlaciona esta transaction a uma execução de task (ctx.tx dentro de um task handler) */
|
|
155
155
|
run_id?: string;
|
|
156
156
|
}
|
|
157
|
-
type CheckInStatus = 'in_progress' | 'ok' | 'error';
|
|
158
|
-
interface CheckInPayload {
|
|
159
|
-
/** Mesmo id no par in_progress → ok/error para casar início e fim */
|
|
160
|
-
check_in_id: string;
|
|
161
|
-
monitor_slug: string;
|
|
162
|
-
status: CheckInStatus;
|
|
163
|
-
duration_ms?: number;
|
|
164
|
-
/** Expressão cron — permite o servidor criar o monitor automaticamente (upsert) */
|
|
165
|
-
schedule?: string;
|
|
166
|
-
timezone?: string;
|
|
167
|
-
environment?: string;
|
|
168
|
-
release?: string;
|
|
169
|
-
}
|
|
170
157
|
interface HeartbeatPayload {
|
|
171
158
|
instance_id: string;
|
|
172
159
|
name?: string;
|
|
@@ -182,9 +169,6 @@ type EnvelopeItem = {
|
|
|
182
169
|
} | {
|
|
183
170
|
type: 'transaction';
|
|
184
171
|
payload: TransactionPayload;
|
|
185
|
-
} | {
|
|
186
|
-
type: 'check_in';
|
|
187
|
-
payload: CheckInPayload;
|
|
188
172
|
} | {
|
|
189
173
|
type: 'heartbeat';
|
|
190
174
|
payload: HeartbeatPayload;
|
|
@@ -199,4 +183,4 @@ interface Envelope {
|
|
|
199
183
|
items: EnvelopeItem[];
|
|
200
184
|
}
|
|
201
185
|
|
|
202
|
-
export type { AgentInfo, Breadcrumb,
|
|
186
|
+
export type { AgentInfo, Breadcrumb, Envelope, EnvelopeItem, EventPayload, EventUser, ExceptionData, HeartbeatPayload, PollRequest, PollResponse, RunDescriptor, RunError, RunLogEntry, RunLogLevel, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, Severity, StackFrame, StepData, StepStatus, TransactionPayload };
|
package/dist/protocol.d.ts
CHANGED
|
@@ -125,18 +125,18 @@ interface EventPayload {
|
|
|
125
125
|
release?: string;
|
|
126
126
|
environment?: string;
|
|
127
127
|
}
|
|
128
|
-
/** Status de
|
|
129
|
-
type
|
|
130
|
-
interface
|
|
128
|
+
/** Status de uma step (etapa). `warning` = terminou, mas merece atenção (não é falha). */
|
|
129
|
+
type StepStatus = 'ok' | 'warning' | 'error' | 'cancelled';
|
|
130
|
+
interface StepData {
|
|
131
131
|
/** 16 hex */
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
step_id: string;
|
|
133
|
+
parent_step_id?: string;
|
|
134
134
|
op?: string;
|
|
135
135
|
description?: string;
|
|
136
|
-
status?:
|
|
136
|
+
status?: StepStatus;
|
|
137
137
|
/** ISO 8601 */
|
|
138
138
|
start_timestamp: string;
|
|
139
|
-
/** ISO 8601 (fim
|
|
139
|
+
/** ISO 8601 (fim da step) */
|
|
140
140
|
timestamp: string;
|
|
141
141
|
data?: Record<string, unknown>;
|
|
142
142
|
}
|
|
@@ -147,26 +147,13 @@ interface TransactionPayload {
|
|
|
147
147
|
status: string;
|
|
148
148
|
start_timestamp: string;
|
|
149
149
|
timestamp: string;
|
|
150
|
-
|
|
150
|
+
steps: StepData[];
|
|
151
151
|
tags?: Record<string, string>;
|
|
152
152
|
release?: string;
|
|
153
153
|
environment?: string;
|
|
154
154
|
/** Correlaciona esta transaction a uma execução de task (ctx.tx dentro de um task handler) */
|
|
155
155
|
run_id?: string;
|
|
156
156
|
}
|
|
157
|
-
type CheckInStatus = 'in_progress' | 'ok' | 'error';
|
|
158
|
-
interface CheckInPayload {
|
|
159
|
-
/** Mesmo id no par in_progress → ok/error para casar início e fim */
|
|
160
|
-
check_in_id: string;
|
|
161
|
-
monitor_slug: string;
|
|
162
|
-
status: CheckInStatus;
|
|
163
|
-
duration_ms?: number;
|
|
164
|
-
/** Expressão cron — permite o servidor criar o monitor automaticamente (upsert) */
|
|
165
|
-
schedule?: string;
|
|
166
|
-
timezone?: string;
|
|
167
|
-
environment?: string;
|
|
168
|
-
release?: string;
|
|
169
|
-
}
|
|
170
157
|
interface HeartbeatPayload {
|
|
171
158
|
instance_id: string;
|
|
172
159
|
name?: string;
|
|
@@ -182,9 +169,6 @@ type EnvelopeItem = {
|
|
|
182
169
|
} | {
|
|
183
170
|
type: 'transaction';
|
|
184
171
|
payload: TransactionPayload;
|
|
185
|
-
} | {
|
|
186
|
-
type: 'check_in';
|
|
187
|
-
payload: CheckInPayload;
|
|
188
172
|
} | {
|
|
189
173
|
type: 'heartbeat';
|
|
190
174
|
payload: HeartbeatPayload;
|
|
@@ -199,4 +183,4 @@ interface Envelope {
|
|
|
199
183
|
items: EnvelopeItem[];
|
|
200
184
|
}
|
|
201
185
|
|
|
202
|
-
export type { AgentInfo, Breadcrumb,
|
|
186
|
+
export type { AgentInfo, Breadcrumb, Envelope, EnvelopeItem, EventPayload, EventUser, ExceptionData, HeartbeatPayload, PollRequest, PollResponse, RunDescriptor, RunError, RunLogEntry, RunLogLevel, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, Severity, StackFrame, StepData, StepStatus, TransactionPayload };
|
package/docs/README.md
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
# Documentação — hobots
|
|
2
2
|
|
|
3
|
-
SDK JavaScript da **Hobots** para instrumentar
|
|
3
|
+
SDK JavaScript da **Hobots** para instrumentar agentes (RPAs) e integrações. Cliente HTTP puro, sem dependências de runtime, para Node 18+ (a telemetria também roda no browser para captura de erros).
|
|
4
4
|
|
|
5
5
|
O SDK expõe **duas capabilities** autenticadas pelo **mesmo Client Secret do agente**, configuradas em **um único `init()`** com **um único import** (`import * as Hobots from 'hobots'`):
|
|
6
6
|
|
|
7
7
|
| Capability | Como habilita | Para quê |
|
|
8
8
|
| --- | --- | --- |
|
|
9
|
-
| **Telemetria** | sempre ativa no `init()` | O que o programa **emite** sozinho: erros com stack trace (módulo **Issues**), performance (transactions/
|
|
9
|
+
| **Telemetria** | sempre ativa no `init()` | O que o programa **emite** sozinho: erros com stack trace (módulo **Issues**), performance (transactions/etapas) e heartbeats de uptime (módulo **Agentes**). Instala handlers globais de erro; os timers são `unref`'d, então nunca seguram o processo vivo. |
|
|
10
10
|
| **Tasks** | `tasks: true` (ou opções) no `init()` | Execução **sob demanda**: o agente faz polling no app, executa handlers registrados e reporta status/logs — o módulo **Solicitações**. `start()` **mantém o processo vivo** até `stop()`/`close()`. |
|
|
11
11
|
|
|
12
12
|
## Páginas
|
|
13
13
|
|
|
14
|
-
Se termos como transaction,
|
|
14
|
+
Se termos como transaction, step, breadcrumb, tag, context, extra, flush e close ainda não são familiares, comece por **Conceitos** — as outras páginas assumem esse vocabulário.
|
|
15
15
|
|
|
16
16
|
- [Conceitos](./concepts.md) — o vocabulário: o que cada coisa é, por que existe e quando escolher uma em vez da outra.
|
|
17
17
|
- [Getting started](./getting-started.md) — instalação, Client Secret, o `init` único, telemetria e tasks.
|
|
18
|
-
- [Telemetria](./
|
|
18
|
+
- [Telemetria](./telemetry.md) — erros, breadcrumbs, escopo, transactions/etapas e heartbeat.
|
|
19
19
|
- [Tasks](./tasks.md) — registro de handlers, `RunContext`, cancelamento, concorrência, idempotência.
|
|
20
20
|
- [Referência de API](./api-reference.md) — todas as funções e tabelas de opções com defaults.
|
|
21
21
|
- [Protocolo & transporte](./protocol.md) — o Client Secret, endpoints, envelope, retries e onde vive o claim atômico.
|
package/docs/api-reference.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
| Import | Conteúdo |
|
|
6
6
|
| --- | --- |
|
|
7
|
-
| `hobots` | Tudo: `init` único, funções de telemetria, `register`/`start`/`stop` de tasks, `close`, classes (`Client`, `Scope`, `Transaction`, `
|
|
7
|
+
| `hobots` | Tudo: `init` único, funções de telemetria, `register`/`start`/`stop` de tasks, `close`, classes (`Client`, `Scope`, `Transaction`, `Step`), `DEFAULT_BASE_URL`, `scrubSecrets` e tipos. |
|
|
8
8
|
| `hobots/protocol` | Tipos do wire format (telemetria e tasks). |
|
|
9
9
|
|
|
10
10
|
---
|
|
@@ -24,8 +24,6 @@
|
|
|
24
24
|
| `setExtra` | `setExtra(key: string, value: unknown): void` | — |
|
|
25
25
|
| `withScope` | `withScope<T>(cb: (scope: Scope) => T): T` | retorno do callback |
|
|
26
26
|
| `startTransaction` | `startTransaction(name: string, op?: string): Transaction` | transaction (dentro de um handler de task, a própria `ctx.tx`) |
|
|
27
|
-
| `checkIn` | `checkIn(options: CheckInOptions): string \| undefined` | check_in_id |
|
|
28
|
-
| `withMonitor` | `withMonitor<T>(slug: string, fn: () => T \| Promise<T>, options?: WithMonitorOptions): Promise<T>` | retorno de `fn` |
|
|
29
27
|
| `flush` | `flush(timeoutMs = 5_000): Promise<boolean>` | enviou tudo dentro do prazo? |
|
|
30
28
|
| `close` | `close(timeoutMs = 5_000): Promise<boolean>` | para o polling de tasks (aguarda runs) + heartbeat + flush final do transport |
|
|
31
29
|
|
|
@@ -45,12 +43,10 @@ Os conceitos por trás dessas chamadas estão em [Conceitos](./concepts.md); aqu
|
|
|
45
43
|
- **`setExtra(key, value)`** — anexa um dado livre, sem estrutura e sem índice. Conceito e critério de escolha em [Extra](./concepts.md#extra).
|
|
46
44
|
- **`withScope(cb)`** — roda o callback com um **clone** do scope e restaura o original no fim; devolve o que o callback devolver. É **síncrono** — um `await` dentro do callback não isola de código concorrente. Conceito: [withScope](./concepts.md#withscope).
|
|
47
45
|
- **`startTransaction(name, op?)`** — abre uma [transaction](./concepts.md#transaction) de performance. A decisão de [amostragem](./concepts.md#amostragem-samplerate-e-tracessamplerate) acontece **aqui**, não no `finish()`. Nada é enviado até o `finish()`. **Dentro de um handler de task**, devolve a [transaction da própria run](./concepts.md#transaction-de-run-ctxtx) (`ctx.tx`) em vez de criar uma segunda — cada execução tem exatamente uma transaction; fora de um handler, cria uma transaction nova, sem `run_id`.
|
|
48
|
-
- **`checkIn(options)`** — envia um [check-in](./concepts.md#check-in) avulso e devolve o `check_in_id`. Reaproveite o id do `in_progress` para fechar a execução com `ok`/`error`.
|
|
49
|
-
- **`withMonitor(slug, fn, options?)`** — envolve `fn` no par de check-ins (`in_progress` → `ok`/`error`) medindo a duração, e devolve o que `fn` devolver. Em caso de erro, fecha como `error`, captura o evento com a tag `monitor: <slug>` e **relança** a exceção. Passe `schedule` para o servidor criar/atualizar o monitor sozinho e detectar execução perdida.
|
|
50
46
|
- **`flush(timeoutMs = 5_000)`** → `Promise<boolean>` — empurra a fila do transport e aguarda os envios em andamento. `true` = tudo saiu no prazo; `false` = o SDK parou de esperar (os envios em voo seguem tentando). O SDK **continua utilizável** depois. Conceito: [Fila, flush e close](./concepts.md#fila-flush-e-close).
|
|
51
47
|
- **`close(timeoutMs = 5_000)`** → `Promise<boolean>` — encerra tudo na ordem agente → heartbeat → flush final. O `timeoutMs` é gasto **duas vezes** (espera das runs, depois flush). Depois do `close()` o transport está fechado e todo item novo é descartado com aviso no console; não há `reopen()`. Conceito: [Fila, flush e close](./concepts.md#fila-flush-e-close).
|
|
52
48
|
|
|
53
|
-
Classes exportadas: `Client`, `Scope`, `Transaction`, `
|
|
49
|
+
Classes exportadas: `Client`, `Scope`, `Transaction`, `Step`. A resolução da credencial nos endpoints é interna ao `init()` (constante `DEFAULT_BASE_URL = 'https://api2.hobots.app'`, exportada; em desenvolvimento a env `HOBOTS_API_URL` sobrescreve a URL base). A config resolvida fica acessível em `getClient()?.config`:
|
|
54
50
|
|
|
55
51
|
```ts
|
|
56
52
|
getClient()?.config; // {
|
|
@@ -61,12 +57,12 @@ getClient()?.config; // {
|
|
|
61
57
|
// }
|
|
62
58
|
```
|
|
63
59
|
|
|
64
|
-
### Métodos de `Transaction` / `
|
|
60
|
+
### Métodos de `Transaction` / `Step` / `Scope`
|
|
65
61
|
|
|
66
62
|
Todos encadeáveis, exceto `finish()` e `toJSON()`.
|
|
67
63
|
|
|
68
|
-
- **`Transaction`** — `startChild(op?, description?) →
|
|
69
|
-
- **`
|
|
64
|
+
- **`Transaction`** — `startChild(op?, description?) → Step` abre uma [step](./concepts.md#step) direta; `setTag(k, v)` marca a transaction (tags de scope **não** são herdadas); `setStatus(s)` (default `'ok'`); `setName(n)` renomeia antes do envio; `finish()` fecha as etapas abertas, monta o payload e envia — é **idempotente** e não envia nada se a transaction não foi amostrada.
|
|
65
|
+
- **`Step`** — `startChild(op?, description?) → Step` aninha uma filha (profundidade arbitrária); `setStatus(s)` (default `'ok'`); `setData(k, v)` anexa dados só àquela step; `finish()` marca o fim — **opcional**, porque o `finish()` da transaction fecha o que ficou aberto; `toJSON()` serializa no formato do wire.
|
|
70
66
|
- **`Scope`** — `setTag`/`setTags`/`setUser`/`setContext`/`setExtra`/`setExtras`/`setLevel`/`setFingerprint`/`addBreadcrumb`/`clearBreadcrumbs`/`clone`. Alcançável via [`withScope`](./concepts.md#withscope). `setContext(name, null)` apaga o grupo; `setUser(null)` remove o usuário.
|
|
71
67
|
> **Atenção:** `setLevel` **não tem efeito** em `captureException` (que já grava `error`) nem em `captureMessage` (que já grava `info`) — os dois definem o level do evento antes de o scope ser consultado. Use o `hint`.
|
|
72
68
|
|
|
@@ -135,24 +131,6 @@ O teto da fila do transport (200 itens; ao encher, o **mais antigo** é descarta
|
|
|
135
131
|
|
|
136
132
|
`Severity = 'fatal' | 'error' | 'warning' | 'info' | 'debug' | 'success'`. O que cada nível significa (e por que `'success'` existe) em [Level](./concepts.md#level-severity).
|
|
137
133
|
|
|
138
|
-
### CheckInOptions
|
|
139
|
-
|
|
140
|
-
| Campo | Tipo | Descrição |
|
|
141
|
-
| --- | --- | --- |
|
|
142
|
-
| `monitorSlug` | `string` | **obrigatório**; identifica o monitor |
|
|
143
|
-
| `status` | `'in_progress' \| 'ok' \| 'error'` | **obrigatório** |
|
|
144
|
-
| `checkInId` | `string` | reutilize o id do `in_progress` para fechar a execução |
|
|
145
|
-
| `durationMs` | `number` | duração medida |
|
|
146
|
-
| `schedule` | `string` | expressão cron — cria/atualiza o monitor no servidor (upsert) |
|
|
147
|
-
| `timezone` | `string` | fuso do `schedule` |
|
|
148
|
-
|
|
149
|
-
### WithMonitorOptions
|
|
150
|
-
|
|
151
|
-
| Campo | Tipo | Descrição |
|
|
152
|
-
| --- | --- | --- |
|
|
153
|
-
| `schedule` | `string` | expressão cron (upsert do monitor) |
|
|
154
|
-
| `timezone` | `string` | fuso do `schedule` |
|
|
155
|
-
|
|
156
134
|
### TasksOptions
|
|
157
135
|
|
|
158
136
|
Valor do campo `tasks` do `InitOptions`. O Client Secret, o `debug` e a identidade (`instanceId`) vêm do `init()`.
|
package/docs/concepts.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Conceitos
|
|
2
2
|
|
|
3
|
-
Esta página explica **o que cada coisa é** — o vocabulário que as outras páginas usam sem parar: evento, scope, tag, context, extra, breadcrumb, transaction,
|
|
3
|
+
Esta página explica **o que cada coisa é** — o vocabulário que as outras páginas usam sem parar: evento, scope, tag, context, extra, breadcrumb, transaction, step, heartbeat, run, claim, flush, close. As outras páginas mostram **como usar**; aqui está o **por que existe** e **quando você escolhe um em vez do outro**.
|
|
4
4
|
|
|
5
5
|
Não é preciso ler de ponta a ponta. Se você só quer o mapa, o quadro abaixo resolve; se um termo apareceu numa página e você travou, pule direto para a seção dele.
|
|
6
6
|
|
|
@@ -20,10 +20,9 @@ Os defaults numéricos **não** estão aqui — eles vivem em [Tempos e interval
|
|
|
20
20
|
| [Extra](#extra) | Depósito livre, sem estrutura | Não é filtro nem grupo coerente — é anexo |
|
|
21
21
|
| [Breadcrumb](#breadcrumb) | Migalha da trilha que levou até o erro | Marcar cada passo relevante do robô |
|
|
22
22
|
| [Transaction](#transaction) | Unidade de trabalho nomeada, com duração | Medir quanto uma rotina inteira demorou |
|
|
23
|
-
| [
|
|
23
|
+
| [Step](#step) | Uma etapa medida dentro da transaction | Descobrir **onde** o tempo foi gasto |
|
|
24
24
|
| [ctx.tx](#transaction-de-run-ctxtx) | A transaction que o SDK já abriu para a run | Medir as etapas de um handler de task |
|
|
25
25
|
| [Amostragem](#amostragem-samplerate-e-tracessamplerate) | Enviar só uma fração do que acontece | Volume alto demais para enviar tudo |
|
|
26
|
-
| [Check-in](#check-in) | Par de avisos "comecei" / "terminei" de um job agendado | Cron que precisa ser vigiado |
|
|
27
26
|
| [Heartbeat](#heartbeat) | Batimento "estou vivo" | Saber que o robô está de pé, mesmo parado |
|
|
28
27
|
| [instanceId](#instanceid) | A identidade da instância do robô | Sempre — é obrigatório no `init()` |
|
|
29
28
|
| [Release e environment](#release-e-environment) | Qual versão, em qual ambiente | Separar produção de homologação; achar a versão que quebrou |
|
|
@@ -41,11 +40,10 @@ Cada API do SDK alimenta um módulo do app da Hobots (app.hobots.app). O mapa:
|
|
|
41
40
|
|
|
42
41
|
| No SDK | No app |
|
|
43
42
|
| --- | --- |
|
|
44
|
-
| **Agente** —
|
|
43
|
+
| **Agente** — dono do Client Secret (`hb_…`) que autentica tudo | **Configurações → Agentes** (é lá que você copia a credencial) |
|
|
45
44
|
| **Instância** — o par `(project_id, instance_id)`; heartbeat e poll de tasks convergem nele | Módulo **Agentes** (uptime, performance) |
|
|
46
45
|
| **[Evento](#evento)** agrupado em **issue** — `captureException` / `captureMessage` | Módulo **Issues** |
|
|
47
|
-
| **
|
|
48
|
-
| **[Transaction](#transaction) / spans** — `startTransaction` (e [`ctx.tx`](#transaction-de-run-ctxtx) dentro de uma run) | Performance no módulo **Agentes**; nas execuções, a aba de performance da solicitação |
|
|
46
|
+
| **[Transaction](#transaction) / etapas** — `startTransaction` (e [`ctx.tx`](#transaction-de-run-ctxtx) dentro de uma run) | Performance no módulo **Agentes**; nas execuções, a aba de performance da solicitação |
|
|
49
47
|
| **Task / [run](#run)** — `register('task-slug', …)` casa com o `task_slug` do formulário | Módulo **Solicitações** (formulários em **Configurações → Formulários**) |
|
|
50
48
|
|
|
51
49
|
---
|
|
@@ -153,7 +151,7 @@ Tags podem vir de quatro lugares, e em caso de conflito a última vence:
|
|
|
153
151
|
|
|
154
152
|
Ou seja: uma tag no `hint` sobrescreve a mesma tag do scope, que sobrescreve a do `init()`. Use o `init()` para o que é verdade em todo o processo (squad, ambiente), o scope para o que é verdade num trecho, e o `hint` para o que é verdade só naquele evento.
|
|
155
153
|
|
|
156
|
-
> **Atenção:** tags do scope entram em **eventos**, não em [transactions](#transaction). Uma transaction só leva as tags do `init()` mais as que você marcar nela com `tx.setTag()`. [
|
|
154
|
+
> **Atenção:** tags do scope entram em **eventos**, não em [transactions](#transaction). Uma transaction só leva as tags do `init()` mais as que você marcar nela com `tx.setTag()`. [Heartbeats](#heartbeat) não levam tag nenhuma.
|
|
157
155
|
|
|
158
156
|
## Context
|
|
159
157
|
|
|
@@ -218,7 +216,7 @@ Tamanho do buffer: [`maxBreadcrumbs`](./api-reference.md#initoptions).
|
|
|
218
216
|
|
|
219
217
|
## Transaction
|
|
220
218
|
|
|
221
|
-
Uma **transaction** é uma unidade de trabalho **nomeada** e **medida**: ela começa, termina, e o que fica registrado é quanto tempo levou. É a resposta para "quanto demora minha rotina de emissão?" — e, quando você adiciona [
|
|
219
|
+
Uma **transaction** é uma unidade de trabalho **nomeada** e **medida**: ela começa, termina, e o que fica registrado é quanto tempo levou. É a resposta para "quanto demora minha rotina de emissão?" — e, quando você adiciona [etapas](#step), para "onde foram esses minutos?".
|
|
222
220
|
|
|
223
221
|
Enquanto o [evento](#evento) responde _o que quebrou_, a transaction responde _quanto tempo levou_. São os dois eixos da telemetria.
|
|
224
222
|
|
|
@@ -234,37 +232,37 @@ O primeiro argumento é o **nome** (o que agrupa transactions comparáveis no ap
|
|
|
234
232
|
Três coisas que valem saber:
|
|
235
233
|
|
|
236
234
|
- **Nada é enviado até o `finish()`.** A transaction vive em memória; o `finish()` é que monta o payload e enfileira. Se o processo morrer antes, ela simplesmente não existe.
|
|
237
|
-
- **`finish()` é idempotente e fecha o resto.** Chamar duas vezes não envia duas; e ele **finaliza automaticamente**
|
|
235
|
+
- **`finish()` é idempotente e fecha o resto.** Chamar duas vezes não envia duas; e ele **finaliza automaticamente** todas as etapas que ficaram abertas.
|
|
238
236
|
- **A [amostragem](#amostragem-samplerate-e-tracessamplerate) é decidida no `startTransaction()`**, não no `finish()`. Se aquela transaction não foi sorteada, o `finish()` não envia nada — mas os `startChild` continuam funcionando normalmente e não custam quase nada.
|
|
239
237
|
|
|
240
238
|
O `status` default é `'ok'`; encadeáveis: `setStatus`, `setName`, `setTag`.
|
|
241
239
|
|
|
242
240
|
Dentro de um handler de task você **não** cria transaction — já existe uma em [`ctx.tx`](#transaction-de-run-ctxtx), e o `startTransaction()` chamado lá dentro devolve exatamente ela.
|
|
243
241
|
|
|
244
|
-
##
|
|
242
|
+
## Step
|
|
245
243
|
|
|
246
|
-
|
|
244
|
+
Uma **step** (etapa) é medida **dentro** de uma [transaction](#transaction). A transaction diz que a rotina levou 4 minutos; as etapas dizem que 3min40 foram esperando o portal.
|
|
247
245
|
|
|
248
246
|
```js
|
|
249
|
-
const
|
|
247
|
+
const step = tx.startChild('http.client', 'GET /api/notas');
|
|
250
248
|
await api.buscarNotas();
|
|
251
|
-
|
|
249
|
+
step.setData('notas', 42).finish();
|
|
252
250
|
```
|
|
253
251
|
|
|
254
|
-
`startChild(op?, description?)` existe **tanto na transaction quanto
|
|
252
|
+
`startChild(op?, description?)` existe **tanto na transaction quanto na step**, então você aninha quanto quiser — uma step de "processar nota" com filhas de "baixar XML" e "gravar no banco". No app isso vira o **waterfall**: barras encaixadas, cada uma com sua duração.
|
|
255
253
|
|
|
256
|
-
O `op` é a categoria (útil para agrupar "todas as queries") e a `description` é o detalhe humano ("`INSERT INTO notas`"). `setData(chave, valor)` anexa dados
|
|
254
|
+
O `op` é a categoria (útil para agrupar "todas as queries") e a `description` é o detalhe humano ("`INSERT INTO notas`"). `setData(chave, valor)` anexa dados àquela step específica — contagens, tamanhos, ids.
|
|
257
255
|
|
|
258
256
|
- Métodos encadeáveis: `setStatus`, `setData`, `finish`.
|
|
259
|
-
- **Status
|
|
260
|
-
- Esquecer o `finish()` de
|
|
261
|
-
-
|
|
257
|
+
- **Status da step:** `'ok'` (default), `'warning'` (terminou, mas merece atenção — não é falha) ou `'error'` (falhou). No waterfall do app cada um tem sua cor: verde/neutro, âmbar e vermelho. Use `step.setStatus('warning')` para etapas que passaram com ressalva (ex.: retry que deu certo, resultado parcial).
|
|
258
|
+
- Esquecer o `finish()` de uma step **não perde o dado**: o `finish()` da transaction fecha as etapas abertas, marcando o fim naquele instante.
|
|
259
|
+
- As etapas são guardadas numa lista plana ligada por `parent_step_id` — o aninhamento que você vê no app é reconstruído a partir dessas referências, não da ordem das chamadas.
|
|
262
260
|
|
|
263
261
|
## Transaction de run (ctx.tx)
|
|
264
262
|
|
|
265
263
|
Dentro de um handler de task você **não precisa** criar uma transaction: o SDK já abriu uma para aquela execução e entregou em `ctx.tx`. Ela nasce quando o agente captura a run, é **correlacionada** à execução pelo `run_id`, recebe o status conforme o desfecho (`ok`, `error` ou `cancelled`) e é **finalizada automaticamente** quando o handler termina — você nunca chama `ctx.tx.finish()`.
|
|
266
264
|
|
|
267
|
-
O que sobra para você é a parte interessante: marcar as **etapas** do trabalho com [
|
|
265
|
+
O que sobra para você é a parte interessante: marcar as **etapas** do trabalho com [steps](#step). Cada `startChild` vira uma barra no waterfall da aba de performance daquela execução no app.
|
|
268
266
|
|
|
269
267
|
```js
|
|
270
268
|
Hobots.register('processar-nfe', async (params, ctx) => {
|
|
@@ -273,17 +271,17 @@ Hobots.register('processar-nfe', async (params, ctx) => {
|
|
|
273
271
|
login.finish();
|
|
274
272
|
|
|
275
273
|
for (const nota of params.notas) {
|
|
276
|
-
const
|
|
274
|
+
const step = ctx.tx.startChild('nfe', `nota ${nota.numero}`);
|
|
277
275
|
ctx.throwIfCanceled();
|
|
278
276
|
await processar(nota);
|
|
279
|
-
|
|
277
|
+
step.setData('valor', nota.valor).finish();
|
|
280
278
|
}
|
|
281
279
|
});
|
|
282
280
|
```
|
|
283
281
|
|
|
284
|
-
Sem nenhum `startChild` a transaction ainda existe e ainda mede o tempo total da run — o waterfall só fica com uma barra. Cada
|
|
282
|
+
Sem nenhum `startChild` a transaction ainda existe e ainda mede o tempo total da run — o waterfall só fica com uma barra. Cada step que você abre é uma resposta a mais para "onde foram os 4 minutos".
|
|
285
283
|
|
|
286
|
-
- **`Hobots.startTransaction()` dentro de um handler devolve a própria `ctx.tx`.** Cada execução tem exatamente **uma** transaction: o SDK detecta o contexto da run e reutiliza a transaction dela em vez de criar uma segunda —
|
|
284
|
+
- **`Hobots.startTransaction()` dentro de um handler devolve a própria `ctx.tx`.** Cada execução tem exatamente **uma** transaction: o SDK detecta o contexto da run e reutiliza a transaction dela em vez de criar uma segunda — as etapas caem no mesmo waterfall. Fora de um handler, `startTransaction()` cria uma transaction nova, sem `run_id`.
|
|
287
285
|
- `ctx.tx` **não respeita o `tracesSampleRate`** — toda run gera uma transaction. A amostragem vale para as transactions que **você** abre com `startTransaction()` fora de uma run.
|
|
288
286
|
- O nome é `run:<task>` e o `op` é `hobots.task`, preenchidos pelo SDK.
|
|
289
287
|
|
|
@@ -300,39 +298,17 @@ São dois controles independentes, os dois de `0` a `1`:
|
|
|
300
298
|
|
|
301
299
|
O sorteio é por item, no momento em que ele é criado — nunca "1 a cada 10", e sim 10% de chance cada.
|
|
302
300
|
|
|
303
|
-
Quem **nunca** é amostrado: [
|
|
301
|
+
Quem **nunca** é amostrado: [heartbeats](#heartbeat) e a [transaction de run](#transaction-de-run-ctxtx) (`ctx.tx`). São sinais de vida — amostrar transformaria "o robô está offline" num palpite.
|
|
304
302
|
|
|
305
303
|
> **Atenção:** para erros, comece com `sampleRate` em 1 (o default) e só reduza se o volume virar problema de verdade. Amostrar erro significa não ver a falha que aconteceu três vezes — e três vezes é exatamente onde você ainda consegue agir. Para transactions o cálculo é o oposto: reduzir é quase sempre seguro.
|
|
306
304
|
|
|
307
305
|
Nos dois casos, o descarte é silencioso do ponto de vista do seu código: `captureException` ainda devolve um `event_id`. Veja a ressalva em [Evento](#evento).
|
|
308
306
|
|
|
309
|
-
## Check-in
|
|
310
|
-
|
|
311
|
-
Um **check-in** é um aviso de que um job agendado começou ou terminou. Dois check-ins com o **mesmo id** formam um par: `in_progress` na entrada, `ok` ou `error` na saída — e a diferença entre eles é a duração medida.
|
|
312
|
-
|
|
313
|
-
Isso responde a uma pergunta que erro e performance não respondem: **"o cron rodou?"**. Um robô que nunca executa nunca lança exceção — o silêncio é o sintoma, e check-in é como o silêncio fica visível.
|
|
314
|
-
|
|
315
|
-
O jeito recomendado é `withMonitor`, que faz o par sozinho e captura a exceção se houver:
|
|
316
|
-
|
|
317
|
-
```js
|
|
318
|
-
await Hobots.withMonitor('sync-notas', () => executarSync(), {
|
|
319
|
-
schedule: '0 */2 * * *',
|
|
320
|
-
timezone: 'America/Fortaleza',
|
|
321
|
-
});
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
O **`schedule`** (expressão cron) é o campo que muda o jogo: com ele, o servidor **cria ou atualiza o monitor automaticamente** (upsert — você não precisa cadastrar nada no app) e passa a saber quando a próxima execução era esperada. É isso que habilita a detecção de **execução perdida**: se as 4h da manhã passaram e nenhum `in_progress` chegou, o app avisa.
|
|
325
|
-
|
|
326
|
-
Detalhes que importam:
|
|
327
|
-
|
|
328
|
-
- `withMonitor` **relança** a exceção depois de fechar o check-in como `error` e capturar o evento (com a tag `monitor: <slug>`) — o seu `try/catch` em volta continua funcionando igual.
|
|
329
|
-
- Precisa de controle manual (o par não está no mesmo lugar do código)? Use `checkIn` direto e reaproveite o `checkInId` devolvido pelo `in_progress` para fechar a execução.
|
|
330
|
-
|
|
331
307
|
## Heartbeat
|
|
332
308
|
|
|
333
309
|
O **heartbeat** é um batimento periódico dizendo "estou vivo". O servidor conhece a cadência esperada e marca a instância como **offline** quando os batimentos param.
|
|
334
310
|
|
|
335
|
-
|
|
311
|
+
Isso responde a uma pergunta que erro e performance não respondem: **"o robô está de pé?"**. Um robô que fica de plantão esperando trabalho pode passar horas sem lançar exceção — o silêncio é o sintoma, e heartbeat é como o silêncio fica visível.
|
|
336
312
|
|
|
337
313
|
```js
|
|
338
314
|
Hobots.init({
|
|
@@ -361,7 +337,7 @@ O que o torna especial é que ele é a identidade dos **dois** canais ao mesmo t
|
|
|
361
337
|
|
|
362
338
|
## Release e environment
|
|
363
339
|
|
|
364
|
-
**`release`** é a versão do seu programa (`robo-nfe@1.4.2`) e **`environment`** é o ambiente lógico (`production`, `homologacao`). Os dois são anexados a **todo** item enviado: eventos
|
|
340
|
+
**`release`** é a versão do seu programa (`robo-nfe@1.4.2`) e **`environment`** é o ambiente lógico (`production`, `homologacao`). Os dois são anexados a **todo** item enviado: eventos e transactions.
|
|
365
341
|
|
|
366
342
|
Servem a duas perguntas concretas:
|
|
367
343
|
|
|
@@ -409,7 +385,7 @@ Isso também explica por que o intervalo de poll não é a latência típica: el
|
|
|
409
385
|
|
|
410
386
|
## Fila, flush e close
|
|
411
387
|
|
|
412
|
-
O SDK **não** envia um HTTP por evento. Cada `captureException`, transaction
|
|
388
|
+
O SDK **não** envia um HTTP por evento. Cada `captureException`, transaction e heartbeat entra numa **fila em memória**; um timer junta os itens num **envelope** e faz um POST só. É isso que faz a telemetria custar quase nada no caminho crítico do seu robô — e é isso que cria o problema que `flush` e `close` resolvem: **quando o processo morre, a fila morre com ele.**
|
|
413
389
|
|
|
414
390
|
A fila esvazia sozinha em três situações: passou o `flushIntervalMs`, acumulou `maxBatchSize` itens, ou você pediu.
|
|
415
391
|
|
|
@@ -423,7 +399,7 @@ Devolve `true` se tudo saiu dentro do tempo e `false` se estourou. `false` **nã
|
|
|
423
399
|
|
|
424
400
|
Encerra tudo, **nesta ordem**: para o agente de tasks (aguardando as runs em execução) → para o heartbeat → faz o flush final e fecha o transport. É sempre a última linha do seu programa.
|
|
425
401
|
|
|
426
|
-
> **Atenção:** `close()` é **terminal e sem volta**. Depois dele, todo `captureException`, transaction
|
|
402
|
+
> **Atenção:** `close()` é **terminal e sem volta**. Depois dele, todo `captureException`, transaction ou heartbeat é **descartado** com um aviso no console — não existe `reopen()`. Se o programa precisar voltar a emitir telemetria, chame `Hobots.init()` de novo.
|
|
427
403
|
|
|
428
404
|
> **Atenção:** o `timeoutMs` do `close()` é aplicado **duas vezes, em sequência** — uma para esperar as runs de tasks, outra para o flush final. `close(15_000)` pode levar até ~30s no pior caso. Se você tem um SIGTERM com prazo curto (Kubernetes, systemd), dimensione por aí.
|
|
429
405
|
|
|
@@ -453,4 +429,4 @@ Onde ele entra na ordem das coisas: a [amostragem](#amostragem-samplerate-e-trac
|
|
|
453
429
|
|
|
454
430
|
> **Atenção:** `beforeSend` roda no caminho da captura, de forma síncrona. Mantenha a função rápida e sem I/O — e cuidado para não lançar exceção dentro dela.
|
|
455
431
|
|
|
456
|
-
Vale só para eventos. Transactions
|
|
432
|
+
Vale só para eventos. Transactions e heartbeats não passam pelo `beforeSend`.
|
package/docs/getting-started.md
CHANGED
|
@@ -71,7 +71,7 @@ try {
|
|
|
71
71
|
}
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
Chame `Hobots.init` **uma vez**, o mais cedo possível no processo. Detalhes em [Telemetria](./
|
|
74
|
+
Chame `Hobots.init` **uma vez**, o mais cedo possível no processo. Detalhes em [Telemetria](./telemetry.md).
|
|
75
75
|
|
|
76
76
|
## Primeiro agente (tasks)
|
|
77
77
|
|
package/docs/protocol.md
CHANGED
|
@@ -30,13 +30,12 @@ Endpoint fixo `POST /v1/ingest` recebe **envelopes** JSON autenticados por Beare
|
|
|
30
30
|
"items": [
|
|
31
31
|
{ "type": "event", "payload": { /* EventPayload */ } },
|
|
32
32
|
{ "type": "transaction", "payload": { /* TransactionPayload */ } },
|
|
33
|
-
{ "type": "check_in", "payload": { /* CheckInPayload */ } },
|
|
34
33
|
{ "type": "heartbeat", "payload": { /* HeartbeatPayload */ } }
|
|
35
34
|
]
|
|
36
35
|
}
|
|
37
36
|
```
|
|
38
37
|
|
|
39
|
-
Tipos de item: `event`, `transaction`, `
|
|
38
|
+
Tipos de item: `event`, `transaction`, `heartbeat` (definidos em `hobots/protocol`).
|
|
40
39
|
|
|
41
40
|
Um `transaction` pode carregar `run_id`: é assim que a [transaction de uma run](./concepts.md#transaction-de-run-ctxtx) (`ctx.tx`) é correlacionada à execução, e o que permite o app montar o waterfall de performance dentro da solicitação. Transactions abertas com `startTransaction()` fora de uma run não têm esse campo.
|
|
42
41
|
|
package/docs/tasks.md
CHANGED
|
@@ -79,20 +79,20 @@ Hobots.register('processar-nfe', async (params, ctx) => {
|
|
|
79
79
|
login.finish();
|
|
80
80
|
|
|
81
81
|
for (const nota of params.notas) {
|
|
82
|
-
const
|
|
82
|
+
const step = ctx.tx.startChild('nfe', `nota ${nota.numero}`);
|
|
83
83
|
ctx.throwIfCanceled();
|
|
84
84
|
await processar(nota);
|
|
85
|
-
|
|
85
|
+
step.setData('valor', nota.valor).finish();
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
Cada `startChild` vira uma barra no waterfall da aba de performance daquela execução no app — é como você responde "onde foram os 4 minutos". Sem
|
|
90
|
+
Cada `startChild` vira uma barra no waterfall da aba de performance daquela execução no app — é como você responde "onde foram os 4 minutos". Sem nenhuma step, a transaction ainda mede o tempo total da run; o waterfall só fica com uma barra.
|
|
91
91
|
|
|
92
|
-
- **`startTransaction()` dentro do handler devolve a própria `ctx.tx`.** Cada execução tem exatamente **uma** transaction: se o seu código (ou uma lib sua já instrumentada) chamar `Hobots.startTransaction()` dentro de um handler, o SDK detecta o contexto da run e retorna a transaction dela em vez de criar uma segunda —
|
|
92
|
+
- **`startTransaction()` dentro do handler devolve a própria `ctx.tx`.** Cada execução tem exatamente **uma** transaction: se o seu código (ou uma lib sua já instrumentada) chamar `Hobots.startTransaction()` dentro de um handler, o SDK detecta o contexto da run e retorna a transaction dela em vez de criar uma segunda — as etapas caem no mesmo waterfall. Fora de um handler, `startTransaction()` cria uma transaction nova, sem `run_id`.
|
|
93
93
|
- `ctx.tx` **não respeita o `tracesSampleRate`** — toda run gera uma transaction. A amostragem vale só para as transactions abertas com `startTransaction()` fora de uma run.
|
|
94
|
-
-
|
|
95
|
-
- Marque etapas com ressalva usando `
|
|
94
|
+
- Step que você esquecer aberta é fechada no `finish()` da transaction, então o dado não se perde.
|
|
95
|
+
- Marque etapas com ressalva usando `step.setStatus('warning')` (ex.: retry que deu certo, resultado parcial): elas aparecem em âmbar no waterfall, distintas de sucesso e de falha (`'error'`).
|
|
96
96
|
|
|
97
97
|
## Cancelamento cooperativo
|
|
98
98
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Telemetria
|
|
2
2
|
|
|
3
|
-
Capability de telemetria: erros (módulo **Issues**), performance e uptime (módulo **Agentes**)
|
|
3
|
+
Capability de telemetria: erros (módulo **Issues**), performance e uptime (módulo **Agentes**). Sempre ativa no `init()` único:
|
|
4
4
|
|
|
5
5
|
```js
|
|
6
6
|
import * as Hobots from 'hobots';
|
|
@@ -88,18 +88,18 @@ Hobots.withScope((scope) => {
|
|
|
88
88
|
|
|
89
89
|
> **Atenção:** `withScope` é **síncrono** — ele troca o scope global e restaura no fim do callback. Se você der `await` lá dentro, o scope isolado vale para qualquer código que capturar eventos enquanto aquele `await` está pendente. Em código concorrente (várias runs em paralelo), passe as tags no `hint`: `captureException(error, { tags: { lote: '128' } })`. Conceito: [withScope](./concepts.md#withscope).
|
|
90
90
|
|
|
91
|
-
## Performance: transactions e
|
|
91
|
+
## Performance: transactions e etapas
|
|
92
92
|
|
|
93
|
-
Uma **transaction** é uma unidade de trabalho nomeada e medida ("quanto minha rotina demorou");
|
|
93
|
+
Uma **transaction** é uma unidade de trabalho nomeada e medida ("quanto minha rotina demorou"); as **etapas** são as unidades dentro dela ("onde o tempo foi gasto"). Conceitos: [Transaction](./concepts.md#transaction) · [Step](./concepts.md#step).
|
|
94
94
|
|
|
95
95
|
```js
|
|
96
96
|
const tx = Hobots.startTransaction('processar-lote', 'rpa.job');
|
|
97
97
|
|
|
98
|
-
const
|
|
98
|
+
const step = tx.startChild('http.client', 'GET /api/notas');
|
|
99
99
|
await api.buscarNotas();
|
|
100
|
-
|
|
100
|
+
step.setData('notas', 42).finish();
|
|
101
101
|
|
|
102
|
-
const filho =
|
|
102
|
+
const filho = step.startChild('db.query', 'INSERT INTO notas'); // etapas aninham
|
|
103
103
|
await gravar();
|
|
104
104
|
filho.finish();
|
|
105
105
|
|
|
@@ -107,37 +107,15 @@ tx.setStatus('ok'); // ou 'error'
|
|
|
107
107
|
tx.finish(); // só aqui a transaction é enviada (respeitando tracesSampleRate)
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
- `startChild(op?, description?)` existe tanto em `Transaction` quanto em `
|
|
111
|
-
- Métodos encadeáveis: `setStatus`, `setData` (
|
|
112
|
-
- Status de
|
|
113
|
-
- `finish()` na transaction fecha
|
|
114
|
-
- A decisão de amostragem acontece no **`startTransaction()`**, não no `finish()`. Esquecer o `finish()` de
|
|
110
|
+
- `startChild(op?, description?)` existe tanto em `Transaction` quanto em `Step` (aninhamento arbitrário).
|
|
111
|
+
- Métodos encadeáveis: `setStatus`, `setData` (step), `setTag`/`setName` (transaction).
|
|
112
|
+
- Status de step: `'ok'` (default), `'warning'` (atenção, não é falha) ou `'error'` — cores distintas no waterfall.
|
|
113
|
+
- `finish()` na transaction fecha etapas abertas e envia o payload; nada é enviado se ela não foi amostrada. É **idempotente** — chamar duas vezes não envia duas.
|
|
114
|
+
- A decisão de amostragem acontece no **`startTransaction()`**, não no `finish()`. Esquecer o `finish()` de uma step não perde o dado: ela é fechada no instante em que a transaction fecha.
|
|
115
115
|
- Uma transaction leva as tags do `init()` e as que você marcar com `tx.setTag()` — ela **não** herda as tags do scope.
|
|
116
116
|
|
|
117
117
|
Dentro de um handler de task, `startTransaction()` **retorna a transaction da própria run** ([`ctx.tx`](./concepts.md#transaction-de-run-ctxtx)) em vez de criar uma segunda — cada execução tem exatamente **uma** transaction. Fora de um handler, ela cria uma transaction nova, sem correlação com run nenhuma.
|
|
118
118
|
|
|
119
|
-
## Crons (check-ins)
|
|
120
|
-
|
|
121
|
-
Monitora jobs agendados — o módulo **Monitores** do app: um check-in `in_progress` na entrada, `ok`/`error` na saída, com duração medida. O jeito recomendado é `withMonitor`, que faz o par e captura exceções:
|
|
122
|
-
|
|
123
|
-
```js
|
|
124
|
-
await Hobots.withMonitor(
|
|
125
|
-
'sync-notas',
|
|
126
|
-
() => executarSync(),
|
|
127
|
-
{ schedule: '0 */2 * * *', timezone: 'America/Fortaleza' }
|
|
128
|
-
);
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
O `schedule` (expressão cron) faz o servidor **criar/atualizar o monitor automaticamente** (upsert) e habilita a detecção de **execução perdida**. Para controle manual, use `checkIn` diretamente (veja [Referência](./api-reference.md#checkinoptions)):
|
|
132
|
-
|
|
133
|
-
```js
|
|
134
|
-
const id = Hobots.checkIn({ monitorSlug: 'sync-notas', status: 'in_progress' });
|
|
135
|
-
// … trabalho …
|
|
136
|
-
Hobots.checkIn({ monitorSlug: 'sync-notas', status: 'ok', checkInId: id, durationMs: 1234 });
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
`withMonitor` **relança** a exceção depois de fechar o check-in como `error` e capturar o evento (com a tag `monitor: <slug>`) — o seu `try/catch` em volta continua funcionando igual. Conceito: [Check-in](./concepts.md#check-in).
|
|
140
|
-
|
|
141
119
|
## Heartbeat (uptime)
|
|
142
120
|
|
|
143
121
|
Bate "estou vivo" periodicamente; o servidor acusa o robô **offline** quando os batimentos param.
|
|
@@ -157,7 +135,7 @@ Essa identidade é a mesma que o poll de tasks envia (`agent.instance_id`) — o
|
|
|
157
135
|
|
|
158
136
|
## Flush e close
|
|
159
137
|
|
|
160
|
-
Nada é enviado na hora: cada evento, transaction
|
|
138
|
+
Nada é enviado na hora: cada evento, transaction e heartbeat entra numa **fila em memória** e sai em lote. É por isso que essas duas funções existem — quando o processo morre, a fila morre com ele. Conceito: [Fila, flush e close](./concepts.md#fila-flush-e-close).
|
|
161
139
|
|
|
162
140
|
```js
|
|
163
141
|
await Hobots.flush(2000); // envia o que está em buffer, mantém o SDK vivo
|
|
@@ -168,6 +146,6 @@ O `timeoutMs` é opcional nas duas — o default é 5s (veja [Tempos e intervalo
|
|
|
168
146
|
|
|
169
147
|
Chame `close` antes do processo sair. Os timers da telemetria são `unref`'d, então ela **não** segura o processo vivo sozinha (só o `start()` das tasks segura).
|
|
170
148
|
|
|
171
|
-
> **Atenção:** `close()` é **terminal**. Depois dele, todo evento, transaction
|
|
149
|
+
> **Atenção:** `close()` é **terminal**. Depois dele, todo evento, transaction ou heartbeat novo é **descartado** com aviso no console — não existe `reopen()`. Se o programa precisar voltar a emitir telemetria, chame `Hobots.init()` de novo.
|
|
172
150
|
|
|
173
151
|
> **Atenção:** o `timeoutMs` do `close()` é gasto **duas vezes, em sequência** — uma esperando as runs de tasks, outra no flush final. `close(15_000)` pode levar até ~30s no pior caso. Dimensione por aí se o seu SIGTERM tem prazo curto.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hobots",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "SDK JavaScript da Hobots — telemetria (erros, transactions
|
|
3
|
+
"version": "1.8.0",
|
|
4
|
+
"description": "SDK JavaScript da Hobots — telemetria (erros, transactions e heartbeats) e execução remota de tarefas sob demanda (tasks) para RPAs e integrações. Um único import e um único init().",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"license": "MIT",
|