hobots 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -84
- package/dist/index.cjs +478 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +144 -19
- package/dist/index.d.ts +144 -19
- package/dist/index.js +522 -33
- package/dist/index.js.map +1 -1
- package/dist/manager/protocol.cjs.map +1 -1
- package/dist/manager/protocol.d.cts +3 -3
- package/dist/manager/protocol.d.ts +3 -3
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +6 -3
- package/dist/protocol.d.ts +6 -3
- package/docs/README.md +24 -17
- package/docs/api-reference.md +32 -20
- package/docs/getting-started.md +46 -29
- package/docs/manager.md +30 -25
- package/docs/monitor.md +28 -26
- package/docs/protocol.md +26 -12
- package/package.json +11 -16
- package/dist/chunk-FW32OR7V.js +0 -75
- package/dist/chunk-FW32OR7V.js.map +0 -1
- package/dist/manager.cjs +0 -519
- package/dist/manager.cjs.map +0 -1
- package/dist/manager.d.cts +0 -118
- package/dist/manager.d.ts +0 -118
- package/dist/manager.js +0 -464
- package/dist/manager.js.map +0 -1
- package/dist/utils-LReLqjzN.d.cts +0 -7
- package/dist/utils-LReLqjzN.d.ts +0 -7
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
SDK JavaScript/TypeScript da **Hobots** para instrumentar funcionários digitais (RPAs) e integrações.
|
|
4
4
|
|
|
5
5
|
- **Monitor** — telemetria que o programa **emite** sozinho: erros com stack trace, performance (transactions/spans), check-ins de cron e heartbeats de uptime.
|
|
6
|
-
- **Manager** — execução **sob demanda**: o agente faz polling no app da Hobots, executa handlers registrados e reporta status
|
|
6
|
+
- **Manager** — execução **sob demanda**: o agente faz polling no app da Hobots, executa handlers registrados e reporta status e logs.
|
|
7
7
|
|
|
8
|
-
Cliente HTTP puro, **sem dependências de runtime**. Requer **Node 18+** (usa o `fetch` global); o Monitor também roda no browser para captura de erros.
|
|
8
|
+
**Um único import e um único `init()`** cobrem as duas capabilities. Cliente HTTP puro, **sem dependências de runtime**. Requer **Node 18+** (usa o `fetch` global); o Monitor também roda no browser para captura de erros.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -17,63 +17,72 @@ npm install hobots
|
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
```js
|
|
20
|
-
import * as
|
|
21
|
-
import * as Manager from 'hobots/manager'; // capability Manager
|
|
20
|
+
import * as Hobots from 'hobots'; // um import só — Monitor e Manager
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
Também funciona em CommonJS: `const
|
|
23
|
+
Também funciona em CommonJS: `const Hobots = require('hobots')`.
|
|
25
24
|
|
|
26
25
|
---
|
|
27
26
|
|
|
28
|
-
##
|
|
27
|
+
## Um SDK, duas capabilities, um `init()`
|
|
29
28
|
|
|
30
|
-
O SDK expõe **duas capabilities
|
|
29
|
+
O SDK expõe **duas capabilities** autenticadas pelo **mesmo Client Secret do projeto**, configuradas em um único `init()`:
|
|
31
30
|
|
|
32
|
-
| Capability |
|
|
31
|
+
| Capability | Como habilita | Para quê | Ciclo de vida |
|
|
33
32
|
| --- | --- | --- | --- |
|
|
34
|
-
| **Monitor** | `
|
|
35
|
-
| **Manager** | `
|
|
33
|
+
| **Monitor** | sempre ativo no `init()` | Telemetria emitida pelo próprio programa: erros, transactions/spans, crons, heartbeat. | Timers `unref`'d — **não** segura o processo. Chame `close()` no fim. |
|
|
34
|
+
| **Manager** | `manager: true` (ou opções) no `init()` | Execução remota sob demanda via polling. | `start()` **segura o processo vivo** até `stop()`/`close()`. |
|
|
36
35
|
|
|
37
36
|
Você usa **uma, outra ou as duas**:
|
|
38
37
|
|
|
39
|
-
- Só saber se o robô quebrou, quanto demora e se está vivo? →
|
|
40
|
-
- Disparar o robô sob demanda a partir de um formulário no app? →
|
|
41
|
-
- Ambos?
|
|
38
|
+
- Só saber se o robô quebrou, quanto demora e se está vivo? → `init({ clientSecret, heartbeat: true })`.
|
|
39
|
+
- Disparar o robô sob demanda a partir de um formulário no app? → `init({ clientSecret, manager: true })` + `register()` + `start()`.
|
|
40
|
+
- Ambos? Passe `heartbeat` e `manager` no mesmo `init()` — o `instanceId` é a identidade única, e os dois canais convergem em **um agente** no painel.
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
Hobots.init({
|
|
44
|
+
clientSecret: 'hb_<64 hex>',
|
|
45
|
+
instanceId: 'vm-cliente-01',
|
|
46
|
+
heartbeat: true, // Monitor: "estou vivo" a cada 30s
|
|
47
|
+
manager: { pollIntervalMs: 5_000 }, // Manager: execução sob demanda
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
Hobots.register('processar-nfe', async (params, ctx) => {
|
|
51
|
+
ctx.log('info', 'começando…');
|
|
52
|
+
return { processadas: 12 };
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
Hobots.start(); // inicia o polling do Manager (segura o processo vivo)
|
|
56
|
+
```
|
|
42
57
|
|
|
43
58
|
---
|
|
44
59
|
|
|
45
|
-
## O
|
|
60
|
+
## O Client Secret
|
|
46
61
|
|
|
47
|
-
|
|
62
|
+
Cada projeto tem **um único Client Secret** — a mesma credencial autentica o Monitor **e** o Manager:
|
|
48
63
|
|
|
49
64
|
```
|
|
50
|
-
|
|
51
|
-
Manager: https://<managerKey>@<host>/<projectSlug> ← manager key (secreta), via Bearer
|
|
65
|
+
hb_<64 hex>
|
|
52
66
|
```
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
- **Manager** usa a **manager key** (chave secreta do agente, criada em `/manager/agents`) e o `projectSlug`. **Não** é a chave de ingestão; nunca vai na URL da requisição, só no header `Authorization: Bearer`.
|
|
68
|
+
(Chaves antigas, 64 hex puros, continuam válidas no servidor.) A credencial é **secreta** e viaja sempre no header `Authorization: Bearer` — nunca na URL. Copie o Client Secret no app, em **Configurações → Projetos** — os snippets de integração já vêm prontos. O SDK fala com a API oficial `https://api.hobots.app` automaticamente; em desenvolvimento, aponte para outro host com a env `HOBOTS_API_URL` (ex.: `HOBOTS_API_URL=http://localhost:3001`).
|
|
56
69
|
|
|
57
70
|
---
|
|
58
71
|
|
|
59
72
|
## Monitor
|
|
60
73
|
|
|
61
|
-
|
|
62
|
-
import * as Monitor from 'hobots';
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Todas as funções abaixo são **no-op seguras** se `Monitor.init()` não foi chamado (com aviso no console).
|
|
74
|
+
Todas as funções abaixo são **no-op seguras** se `Hobots.init()` não foi chamado (com aviso no console).
|
|
66
75
|
|
|
67
76
|
### `init(options)`
|
|
68
77
|
|
|
69
78
|
Inicialize **uma vez**, o mais cedo possível no processo. Cria o cliente, instala handlers globais de erro (a menos que `captureUnhandled: false`) e inicia o heartbeat se configurado.
|
|
70
79
|
|
|
71
80
|
```js
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
Hobots.init({
|
|
82
|
+
clientSecret: 'hb_<64 hex>',
|
|
74
83
|
environment: 'production',
|
|
75
84
|
release: 'robo-nfe@1.4.2',
|
|
76
|
-
|
|
85
|
+
instanceId: 'vm-cliente-01',
|
|
77
86
|
tags: { squad: 'automacoes' },
|
|
78
87
|
heartbeat: true, // "estou vivo" a cada 30s
|
|
79
88
|
});
|
|
@@ -81,16 +90,17 @@ Monitor.init({
|
|
|
81
90
|
|
|
82
91
|
| Opção | Tipo | Default | Descrição |
|
|
83
92
|
| --- | --- | --- | --- |
|
|
84
|
-
| `
|
|
93
|
+
| `clientSecret` | `string` | **obrigatório** | o Client Secret do projeto (`hb_<64 hex>`), copiado em **Configurações → Projetos** |
|
|
85
94
|
| `environment` | `string` | `'production'` | ambiente lógico |
|
|
86
95
|
| `release` | `string` | — | versão do programa, ex. `robo-nfe@1.4.2` |
|
|
87
|
-
| `
|
|
96
|
+
| `instanceId` | `string` | **obrigatório** | identidade única da instância — heartbeat do Monitor e agente do Manager convergem nela |
|
|
88
97
|
| `tags` | `Record<string,string>` | — | tags aplicadas a todos os eventos |
|
|
89
98
|
| `sampleRate` | `number` | `1` | amostragem de erros (0..1) |
|
|
90
99
|
| `tracesSampleRate` | `number` | `1` | amostragem de transactions (0..1) |
|
|
91
100
|
| `maxBreadcrumbs` | `number` | `100` | tamanho do buffer de breadcrumbs |
|
|
92
101
|
| `captureUnhandled` | `boolean` | `true` | handlers globais de erro (`uncaughtException`/`unhandledRejection`) |
|
|
93
102
|
| `heartbeat` | `boolean \| HeartbeatOptions` | `false` | heartbeat periódico (`true` usa defaults) |
|
|
103
|
+
| `manager` | `boolean \| ManagerOptions` | `false` | habilita o agente Manager (`true` usa defaults) — veja [Manager](#manager) |
|
|
94
104
|
| `beforeSend` | `(event) => event \| null` | — | edita/descarta evento (retorne `null` para descartar) |
|
|
95
105
|
| `debug` | `boolean` | `false` | loga atividade do SDK |
|
|
96
106
|
| `flushIntervalMs` | `number` | `2000` | intervalo do flush automático do transport |
|
|
@@ -102,7 +112,7 @@ Monitor.init({
|
|
|
102
112
|
try {
|
|
103
113
|
await processarNota(nota);
|
|
104
114
|
} catch (error) {
|
|
105
|
-
|
|
115
|
+
Hobots.captureException(error, {
|
|
106
116
|
level: 'error',
|
|
107
117
|
tags: { cliente: 'acme' },
|
|
108
118
|
fingerprint: ['sefaz-timeout'], // agrupa manualmente; sem isso o servidor agrupa pelo stack
|
|
@@ -110,7 +120,7 @@ try {
|
|
|
110
120
|
throw error;
|
|
111
121
|
}
|
|
112
122
|
|
|
113
|
-
|
|
123
|
+
Hobots.captureMessage('Lote processado com sucesso', 'info');
|
|
114
124
|
```
|
|
115
125
|
|
|
116
126
|
Ambas retornam o `event_id` (ou `undefined` se não inicializado). O hint aceita `level`, `tags`, `extra` e `fingerprint`. Erros **não tratados** são capturados e flushados automaticamente antes do processo sair — desligue com `captureUnhandled: false`.
|
|
@@ -122,7 +132,7 @@ Ambas retornam o `event_id` (ou `undefined` se não inicializado). O hint aceita
|
|
|
122
132
|
Trilha do que aconteceu antes do erro; enviada junto do próximo evento (buffer limitado por `maxBreadcrumbs`, mais antigos descartados).
|
|
123
133
|
|
|
124
134
|
```js
|
|
125
|
-
|
|
135
|
+
Hobots.addBreadcrumb({ category: 'nfe', message: 'Baixou XML da nota 123', level: 'info' });
|
|
126
136
|
```
|
|
127
137
|
|
|
128
138
|
### Escopo: tags, usuário, contexto, extras
|
|
@@ -130,26 +140,26 @@ Monitor.addBreadcrumb({ category: 'nfe', message: 'Baixou XML da nota 123', leve
|
|
|
130
140
|
Dados anexados a **todos** os eventos seguintes:
|
|
131
141
|
|
|
132
142
|
```js
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
143
|
+
Hobots.setTag('regiao', 'nordeste');
|
|
144
|
+
Hobots.setTags({ squad: 'automacoes', cliente: 'acme' });
|
|
145
|
+
Hobots.setUser({ id: 'op-42', email: 'op@acme.com' });
|
|
146
|
+
Hobots.setContext('vm', { cpu: 4, ram: '8GB' });
|
|
147
|
+
Hobots.setExtra('ultimoLote', 128);
|
|
138
148
|
```
|
|
139
149
|
|
|
140
150
|
Para um escopo **isolado** (sem vazar para o global), use `withScope`:
|
|
141
151
|
|
|
142
152
|
```js
|
|
143
|
-
|
|
153
|
+
Hobots.withScope((scope) => {
|
|
144
154
|
scope.setTag('lote', '128').setFingerprint(['reprocessamento']);
|
|
145
|
-
|
|
155
|
+
Hobots.captureMessage('Reprocessando lote 128');
|
|
146
156
|
});
|
|
147
157
|
```
|
|
148
158
|
|
|
149
159
|
### Performance: transactions e spans
|
|
150
160
|
|
|
151
161
|
```js
|
|
152
|
-
const tx =
|
|
162
|
+
const tx = Hobots.startTransaction('processar-lote', 'rpa.job');
|
|
153
163
|
|
|
154
164
|
const span = tx.startChild('http.client', 'GET /api/notas');
|
|
155
165
|
await api.buscarNotas();
|
|
@@ -172,7 +182,7 @@ tx.finish(); // só aqui a transaction é enviada (respeitando tracesSam
|
|
|
172
182
|
Monitora jobs agendados: 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:
|
|
173
183
|
|
|
174
184
|
```js
|
|
175
|
-
await
|
|
185
|
+
await Hobots.withMonitor(
|
|
176
186
|
'sync-notas',
|
|
177
187
|
() => executarSync(),
|
|
178
188
|
{ schedule: '0 */2 * * *', timezone: 'America/Fortaleza' }
|
|
@@ -182,9 +192,9 @@ await Monitor.withMonitor(
|
|
|
182
192
|
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:
|
|
183
193
|
|
|
184
194
|
```js
|
|
185
|
-
const id =
|
|
195
|
+
const id = Hobots.checkIn({ monitorSlug: 'sync-notas', status: 'in_progress' });
|
|
186
196
|
// … trabalho …
|
|
187
|
-
|
|
197
|
+
Hobots.checkIn({ monitorSlug: 'sync-notas', status: 'ok', checkInId: id, durationMs: 1234 });
|
|
188
198
|
```
|
|
189
199
|
|
|
190
200
|
### Heartbeat (uptime)
|
|
@@ -192,19 +202,19 @@ Monitor.checkIn({ monitorSlug: 'sync-notas', status: 'ok', checkInId: id, durati
|
|
|
192
202
|
Bate "estou vivo" periodicamente; o servidor acusa o robô **offline** quando os batimentos param.
|
|
193
203
|
|
|
194
204
|
```js
|
|
195
|
-
|
|
196
|
-
|
|
205
|
+
Hobots.init({
|
|
206
|
+
clientSecret,
|
|
197
207
|
heartbeat: { intervalMs: 30_000, name: 'Robô NFe — VM 01' },
|
|
198
208
|
});
|
|
199
209
|
```
|
|
200
210
|
|
|
201
|
-
`heartbeat: true` usa os defaults. Campos: `intervalMs` (30000), `
|
|
211
|
+
`heartbeat: true` usa os defaults. A identidade é o `instanceId` do `init()`. Campos: `intervalMs` (30000), `name` (default: o `instanceId`), `metadata`.
|
|
202
212
|
|
|
203
213
|
### Flush e close
|
|
204
214
|
|
|
205
215
|
```js
|
|
206
|
-
await
|
|
207
|
-
await
|
|
216
|
+
await Hobots.flush(2000); // envia o buffer, mantém o SDK vivo
|
|
217
|
+
await Hobots.close(2000); // flush final + para o heartbeat + fecha o transport
|
|
208
218
|
```
|
|
209
219
|
|
|
210
220
|
Chame `close` antes do processo sair. Os timers do Monitor são `unref`'d — ele **não** segura o processo vivo sozinho.
|
|
@@ -213,50 +223,50 @@ Chame `close` antes do processo sair. Os timers do Monitor são `unref`'d — el
|
|
|
213
223
|
|
|
214
224
|
## Manager
|
|
215
225
|
|
|
216
|
-
|
|
217
|
-
import * as Manager from 'hobots/manager';
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Capability de **execução remota sob demanda**. O agente faz polling no app, executa os handlers registrados quando aparece trabalho e reporta status, logs incrementais e resultado. Credencial própria (**manager key**), singletons próprios, nenhum handler global instalado.
|
|
226
|
+
Capability de **execução remota sob demanda**, habilitada com `manager: true` (ou opções) no `init()`. O agente faz polling no app, executa os handlers registrados quando aparece trabalho e reporta status e logs incrementais. Mesmo Client Secret, mesmo `debug` e o `instanceId` como identidade — nenhum handler global extra é instalado.
|
|
221
227
|
|
|
222
228
|
### Ciclo de vida
|
|
223
229
|
|
|
224
230
|
```js
|
|
225
|
-
|
|
231
|
+
Hobots.init({
|
|
232
|
+
clientSecret: 'hb_<64 hex>',
|
|
233
|
+
instanceId: 'vm-cliente-01',
|
|
234
|
+
manager: true, // ou { pollIntervalMs, concurrency, ... }
|
|
235
|
+
});
|
|
226
236
|
|
|
227
|
-
|
|
237
|
+
Hobots.register('processar-nfe', async (params, ctx) => {
|
|
228
238
|
ctx.log('info', `processando lote ${params.lote}…`);
|
|
229
239
|
if (ctx.signal.aborted) return; // cancelamento cooperativo
|
|
230
|
-
|
|
240
|
+
ctx.log('info', '12 notas processadas');
|
|
231
241
|
});
|
|
232
242
|
|
|
233
|
-
|
|
243
|
+
Hobots.start(); // começa o polling e MANTÉM O PROCESSO VIVO
|
|
234
244
|
|
|
235
245
|
process.on('SIGINT', () => {
|
|
236
|
-
void
|
|
246
|
+
void Hobots.close(15_000).then(() => process.exit(0));
|
|
237
247
|
});
|
|
238
248
|
```
|
|
239
249
|
|
|
240
|
-
- `init(
|
|
241
|
-
- `register(task, handler)` — `task` é o `task_slug` configurado no formulário do app. Registre **antes** de `start()`.
|
|
242
|
-
- `start()` — começa o polling. Lança se `init()` não
|
|
243
|
-
- `stop(timeoutMs?)` — para o polling e aguarda as runs ativas (default 30s). Retorna `false` se estourou o timeout.
|
|
250
|
+
- `init({ manager })` — cria o agente. Chamar `init()` de novo para o agente anterior e o substitui (o registry de handlers é preservado).
|
|
251
|
+
- `register(task, handler)` — `task` é o `task_slug` configurado no formulário do app. Registre **antes** de `start()`. Funciona até antes do `init()`; com o Manager desabilitado, avisa no console.
|
|
252
|
+
- `start()` — começa o polling. Lança se o `init()` não configurou `manager` ou se nenhuma task foi registrada.
|
|
253
|
+
- `stop(timeoutMs?)` — para **só o Manager**: encerra o polling e aguarda as runs ativas (default 30s); a telemetria continua. Retorna `false` se estourou o timeout.
|
|
254
|
+
- `close(timeoutMs?)` — encerra **tudo**: agente (aguardando runs em voo) → heartbeat → flush final do transport.
|
|
244
255
|
|
|
245
|
-
| Opção (`
|
|
256
|
+
| Opção (`ManagerOptions`) | Tipo | Default | Descrição |
|
|
246
257
|
| --- | --- | --- | --- |
|
|
247
|
-
| `dsn` | `string` | **obrigatório** | com a **manager key** (não a chave de ingestão) |
|
|
248
258
|
| `pollIntervalMs` | `number` | `5000` | intervalo entre polls sem trabalho (mínimo `1000`) |
|
|
249
259
|
| `concurrency` | `number` | `1` | runs simultâneas (clamp 1..5) |
|
|
250
|
-
| `agentName` | `string` | hostname | nome exibido no dashboard |
|
|
251
260
|
| `taskTimeoutMs` | `number` | — | timeout client-side por run (não mata o handler; servidor é o backstop) |
|
|
252
261
|
| `logFlushIntervalMs` | `number` | `2000` | intervalo do envio incremental de logs |
|
|
253
|
-
|
|
262
|
+
|
|
263
|
+
O Client Secret, o `debug` e a identidade do agente (`instanceId`) vêm do `init()` — o heartbeat do Monitor e o agente do Manager convergem em **um agente** no painel automaticamente.
|
|
254
264
|
|
|
255
265
|
### O handler e o `RunContext`
|
|
256
266
|
|
|
257
267
|
```ts
|
|
258
|
-
type ManagerTaskHandler<P = Record<string, unknown
|
|
259
|
-
(params: P, ctx: RunContext) =>
|
|
268
|
+
type ManagerTaskHandler<P = Record<string, unknown>> =
|
|
269
|
+
(params: P, ctx: RunContext) => void | Promise<void>;
|
|
260
270
|
|
|
261
271
|
interface RunContext {
|
|
262
272
|
runId: string;
|
|
@@ -266,22 +276,24 @@ interface RunContext {
|
|
|
266
276
|
}
|
|
267
277
|
```
|
|
268
278
|
|
|
269
|
-
- **`params`** — os dados do formulário configurado no app (JSON validado). Tipável: `
|
|
279
|
+
- **`params`** — os dados do formulário configurado no app (JSON validado). Tipável: `Hobots.register<{ lote: number }>(...)`.
|
|
270
280
|
- **`ctx.log(level, message)`** — logs enviados **incrementalmente** ao app (PATCHes com throttle), visíveis na run quase em tempo real.
|
|
271
281
|
- **`ctx.signal`** — `AbortSignal` que dispara quando a run é **cancelada no app**, em **timeout** ou no **shutdown**.
|
|
272
|
-
- **Retorno** —
|
|
282
|
+
- **Retorno** — **ignorado**: o SDK não captura nem envia o valor retornado pelo handler (resultados podem conter dados sensíveis e não são coletados).
|
|
273
283
|
- **Erro lançado** — a run é reportada como `failed` (mensagem cap 10k, stack 20k).
|
|
274
284
|
|
|
285
|
+
> **Dados sensíveis:** `ctx.log()` e mensagens/stack de erros **são enviados ao servidor** e ficam visíveis no app. Não inclua senhas, tokens, dados pessoais ou qualquer informação sensível em logs e mensagens de erro.
|
|
286
|
+
|
|
275
287
|
### Cancelamento cooperativo
|
|
276
288
|
|
|
277
289
|
Uma run cancelada no app **não mata** o handler — o SDK apenas dispara `ctx.signal`. **Verifique `ctx.signal.aborted`** em loops longos:
|
|
278
290
|
|
|
279
291
|
```js
|
|
280
|
-
|
|
292
|
+
Hobots.register('processar-nfe', async (params, ctx) => {
|
|
281
293
|
for (const nota of params.notas) {
|
|
282
294
|
if (ctx.signal.aborted) {
|
|
283
295
|
ctx.log('warning', 'cancelamento detectado — parando');
|
|
284
|
-
return
|
|
296
|
+
return;
|
|
285
297
|
}
|
|
286
298
|
await processar(nota);
|
|
287
299
|
}
|
|
@@ -298,34 +310,66 @@ Manager.register('processar-nfe', async (params, ctx) => {
|
|
|
298
310
|
|
|
299
311
|
### Idempotência (at-least-once)
|
|
300
312
|
|
|
301
|
-
A entrega é **at-least-once**: se o agente morre logo após capturar uma run (antes de reportar
|
|
313
|
+
A entrega é **at-least-once**: se o agente morre logo após capturar uma run (antes de reportar a conclusão), ela é re-entregue quando o agente voltar. Escreva handlers **idempotentes** (use uma chave de deduplicação sua, como o número da nota).
|
|
302
314
|
|
|
303
315
|
---
|
|
304
316
|
|
|
305
317
|
## Encerramento gracioso
|
|
306
318
|
|
|
319
|
+
`close(timeoutMs?)` encerra tudo na ordem certa: para o Manager (aguardando a run atual), para o heartbeat e faz o flush final do transport.
|
|
320
|
+
|
|
307
321
|
```js
|
|
308
|
-
// Monitor: não segura o processo, mas faça o flush final para não perder eventos
|
|
309
|
-
await
|
|
322
|
+
// só Monitor: não segura o processo, mas faça o flush final para não perder eventos
|
|
323
|
+
await Hobots.close(2_000);
|
|
310
324
|
|
|
311
|
-
// Manager: segura o processo por design — aguarde a run atual
|
|
325
|
+
// com Manager: segura o processo por design — aguarde a run atual
|
|
312
326
|
process.on('SIGINT', () => {
|
|
313
|
-
void
|
|
327
|
+
void Hobots.close(15_000).then(() => process.exit(0));
|
|
314
328
|
});
|
|
315
329
|
```
|
|
316
330
|
|
|
331
|
+
Para parar de aceitar execuções **sem** derrubar a telemetria, use `stop(timeoutMs?)`.
|
|
332
|
+
|
|
317
333
|
---
|
|
318
334
|
|
|
319
335
|
## Entry points / exports
|
|
320
336
|
|
|
321
337
|
| Import | Conteúdo |
|
|
322
338
|
| --- | --- |
|
|
323
|
-
| `hobots` |
|
|
324
|
-
| `hobots/protocol` | Tipos do wire format
|
|
325
|
-
|
|
326
|
-
|
|
339
|
+
| `hobots` | Tudo: `init`, Monitor (captura, transactions, crons, heartbeat), Manager (`register`/`start`/`stop`), `close`, classes e tipos. |
|
|
340
|
+
| `hobots/protocol` | Tipos do wire format (Monitor e Manager). |
|
|
341
|
+
|
|
342
|
+
Empacotado em **ESM e CommonJS** com **definições de tipos** (`.d.ts`) para todas as entradas. (`hobots/manager/protocol` segue existindo como alias transitório de tipos.)
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Migração 1.x → 2.x
|
|
347
|
+
|
|
348
|
+
A 2.0 unifica o Manager no import raiz — `hobots/manager` **foi removido**:
|
|
349
|
+
|
|
350
|
+
```diff
|
|
351
|
+
-import * as Monitor from 'hobots';
|
|
352
|
+
-import * as Manager from 'hobots/manager';
|
|
353
|
+
+import * as Hobots from 'hobots';
|
|
354
|
+
|
|
355
|
+
-Monitor.init({ dsn, serverName: 'vm-01', heartbeat: true });
|
|
356
|
+
-Manager.init({ dsn, agentName: 'vm-01' });
|
|
357
|
+
+Hobots.init({ clientSecret, instanceId: 'vm-01', heartbeat: true, manager: true });
|
|
358
|
+
|
|
359
|
+
-Manager.register('minha-task', handler);
|
|
360
|
+
-Manager.start();
|
|
361
|
+
+Hobots.register('minha-task', handler);
|
|
362
|
+
+Hobots.start();
|
|
363
|
+
|
|
364
|
+
-await Manager.stop(15_000);
|
|
365
|
+
-await Monitor.close(3_000);
|
|
366
|
+
+await Hobots.close(15_000);
|
|
367
|
+
```
|
|
327
368
|
|
|
328
|
-
|
|
369
|
+
- A `dsn` (mecanismo antigo, `https://<secretKey>@host/<slug>`) não existe mais — passe `clientSecret` (em desenvolvimento, aponte para outro host com a env `HOBOTS_API_URL`). Copie o Client Secret em **Configurações → Projetos**.
|
|
370
|
+
- `agentName` e `serverName` não existem mais — a identidade do agente é o `instanceId` (obrigatório, sem fallback).
|
|
371
|
+
- As opções do Manager (`pollIntervalMs`, `concurrency`, `taskTimeoutMs`, `logFlushIntervalMs`) vão no campo `manager` do `init()`; `clientSecret` e `debug` não se repetem.
|
|
372
|
+
- Tipos (`ManagerTaskHandler`, `RunContext`, `ManagerOptions`) e classes (`ManagerAgent`, `ManagerApi`) agora vêm de `hobots`; o wire format vem de `hobots/protocol`.
|
|
329
373
|
|
|
330
374
|
---
|
|
331
375
|
|
|
@@ -333,11 +377,11 @@ Empacotado em **ESM e CommonJS** com **definições de tipos** (`.d.ts`) para to
|
|
|
333
377
|
|
|
334
378
|
Guias detalhados acompanham o pacote em [`docs/`](./docs/README.md):
|
|
335
379
|
|
|
336
|
-
- [Getting started](./docs/getting-started.md) — instalação,
|
|
380
|
+
- [Getting started](./docs/getting-started.md) — instalação, Client Secret, primeiro `init`, Monitor vs Hobots.
|
|
337
381
|
- [Monitor](./docs/monitor.md) — erros, breadcrumbs, escopo, transactions/spans, crons, heartbeat.
|
|
338
382
|
- [Manager](./docs/manager.md) — handlers, `RunContext`, cancelamento, concorrência, idempotência.
|
|
339
383
|
- [Referência de API](./docs/api-reference.md) — todas as funções e tabelas de opções com defaults.
|
|
340
|
-
- [Protocolo & transporte](./docs/protocol.md) —
|
|
384
|
+
- [Protocolo & transporte](./docs/protocol.md) — o Client Secret, endpoints, envelope, retries.
|
|
341
385
|
|
|
342
386
|
---
|
|
343
387
|
|