@cargolift-cdi/util-rabbitmq 0.1.64 → 0.2.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 +70 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/integration-event.publisher.d.ts +42 -0
- package/dist/integration-event.publisher.d.ts.map +1 -0
- package/dist/integration-event.publisher.js +77 -0
- package/dist/integration-event.publisher.js.map +1 -0
- package/dist/integration-publisher.service.d.ts +5 -31
- package/dist/integration-publisher.service.d.ts.map +1 -1
- package/dist/integration-publisher.service.js +11 -69
- package/dist/integration-publisher.service.js.map +1 -1
- package/dist/rabbitmq-connection.manager.d.ts +19 -0
- package/dist/rabbitmq-connection.manager.d.ts.map +1 -0
- package/dist/rabbitmq-connection.manager.js +57 -0
- package/dist/rabbitmq-connection.manager.js.map +1 -0
- package/dist/rabbitmq-publisher-dlq.service.d.ts +1 -1
- package/dist/rabbitmq-publisher-dlq.service.d.ts.map +1 -1
- package/dist/rabbitmq-publisher-dlq.service.js +61 -11
- package/dist/rabbitmq-publisher-dlq.service.js.map +1 -1
- package/dist/rabbitmq-publisher.service.d.ts +3 -8
- package/dist/rabbitmq-publisher.service.d.ts.map +1 -1
- package/dist/rabbitmq-publisher.service.js +18 -156
- package/dist/rabbitmq-publisher.service.js.map +1 -1
- package/dist/rabbitmq.constants.d.ts +7 -0
- package/dist/rabbitmq.constants.d.ts.map +1 -0
- package/dist/rabbitmq.constants.js +14 -0
- package/dist/rabbitmq.constants.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,2 +1,72 @@
|
|
|
1
1
|
# @cargolift-cdi/util-rabbitmq
|
|
2
2
|
|
|
3
|
+
Utilitários para publicação de mensagens RabbitMQ com confirmação (publisher confirms), enriquecimento de envelope e convenções de integração.
|
|
4
|
+
|
|
5
|
+
## Principais Componentes
|
|
6
|
+
|
|
7
|
+
- `RabbitMQPublisherService`: camada de baixo nível (confirmação, timeout, backpressure, headers contextuais).
|
|
8
|
+
- `IntegrationEventPublisher`: fachada de alto nível para eventos de integração HTTP → RabbitMQ.
|
|
9
|
+
- `publishToDlqAndAck`: envia mensagem original (enriquecida) para DLQ e faz ack.
|
|
10
|
+
- `RabbitMQConnectionManager`: reutiliza conexão evitando overhead de conexão por mensagem.
|
|
11
|
+
|
|
12
|
+
## Exemplo Rápido
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class DemoService {
|
|
17
|
+
constructor(private readonly integration: IntegrationEventPublisher) {}
|
|
18
|
+
|
|
19
|
+
async send(data: any) {
|
|
20
|
+
await this.integration.publish({
|
|
21
|
+
routingKey: 'integration.erp.demo',
|
|
22
|
+
payload: data,
|
|
23
|
+
raw: { returnMeta: true }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Metadados de Publicação
|
|
30
|
+
`RabbitMQPublisherService.publish` aceita `returnMeta: true` em `opts` retornando:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
{
|
|
34
|
+
correlationId: string;
|
|
35
|
+
exchange: string;
|
|
36
|
+
routingKey: string;
|
|
37
|
+
pattern: string;
|
|
38
|
+
sizeBytes: number;
|
|
39
|
+
durationMs: number;
|
|
40
|
+
confirmedAt: string;
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## DLQ Enriquecida
|
|
45
|
+
`publishToDlqAndAck` tenta embutir JSON com:
|
|
46
|
+
```jsonc
|
|
47
|
+
{
|
|
48
|
+
"failedAt": "2025-09-30T12:34:56.000Z",
|
|
49
|
+
"error": { "name": "Error", "message": "...", "stack": "..." },
|
|
50
|
+
"originalHeaders": { ... },
|
|
51
|
+
"originalPayload": { ... }
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
Header `x-dlq-enriched` indica `1` (sucesso) ou `0` (fallback raw).
|
|
55
|
+
|
|
56
|
+
## Variáveis de Ambiente
|
|
57
|
+
| Nome | Descrição | Default |
|
|
58
|
+
|------|-----------|---------|
|
|
59
|
+
| `RABBITMQ_URL` | URL de conexão | (obrigatório) |
|
|
60
|
+
| `RABBITMQ_EXCHANGE` | Exchange default integração | `integration.inbound` |
|
|
61
|
+
| `RABBITMQ_ALTERNATE_EXCHANGE` | Alternate exchange | `integration.inbound.ae` |
|
|
62
|
+
| `RABBITMQ_EXCHANGE_TYPE` | Tipo do exchange | `topic` |
|
|
63
|
+
| `RABBITMQ_PUBLISH_TIMEOUT_MS` | Timeout confirmação | `5000` |
|
|
64
|
+
|
|
65
|
+
## Boas Práticas
|
|
66
|
+
- Reutilize a instância injetada (não crie manualmente o publisher baixo nível).
|
|
67
|
+
- Evite payloads muito grandes (considerar compressão se `sizeBytes > ~256KB`).
|
|
68
|
+
- Log de debug seletivo (considere flag futura `DEBUG_RABBIT_PUBLISH`).
|
|
69
|
+
|
|
70
|
+
## Licença
|
|
71
|
+
MIT
|
|
72
|
+
|
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export * from './rabbitmq-publisher.service.js';
|
|
6
6
|
export * from './rabbitmq-publisher-dlq.service.js';
|
|
7
|
-
export * from './integration-publisher.
|
|
7
|
+
export * from './integration-event.publisher.js';
|
|
8
|
+
export * from './rabbitmq-connection.manager.js';
|
|
9
|
+
export * from './rabbitmq.constants.js';
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,5 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export * from './rabbitmq-publisher.service.js';
|
|
6
6
|
export * from './rabbitmq-publisher-dlq.service.js';
|
|
7
|
-
export * from './integration-publisher.
|
|
7
|
+
export * from './integration-event.publisher.js';
|
|
8
|
+
export * from './rabbitmq-connection.manager.js';
|
|
9
|
+
export * from './rabbitmq.constants.js';
|
|
8
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { LoggerContextService } from '@cargolift-cdi/common';
|
|
2
|
+
import { RabbitMQPublisherService } from './rabbitmq-publisher.service.js';
|
|
3
|
+
import { EnvelopeMessage } from '@cargolift-cdi/types';
|
|
4
|
+
/**
|
|
5
|
+
* IntegrationEventPublisher
|
|
6
|
+
* --------------------------------------------------
|
|
7
|
+
* Publicador de alto nível para eventos de integração.
|
|
8
|
+
* Regras aplicadas:
|
|
9
|
+
* - Defaults de exchange / alternate exchange / exchangeType
|
|
10
|
+
* - Extração de IP e user-agent de uma Request HTTP (se fornecida)
|
|
11
|
+
* - Normalização de envelope (correlation_id, eventType, source, timestamp)
|
|
12
|
+
* - Headers padronizados (x-correlation-id, x-trace, x-source)
|
|
13
|
+
* - Encaminha para RabbitMQPublisherService (baixo nível) com possibilidade de confirmação
|
|
14
|
+
*
|
|
15
|
+
* Use este serviço quando publicar eventos sem querer lidar com detalhes de configuração.
|
|
16
|
+
*/
|
|
17
|
+
export interface PublishIntegrationEventOptions {
|
|
18
|
+
exchange?: string;
|
|
19
|
+
routingKey: string;
|
|
20
|
+
req?: Request;
|
|
21
|
+
payload?: any;
|
|
22
|
+
envelope?: Partial<EnvelopeMessage>;
|
|
23
|
+
headers?: Record<string, any>;
|
|
24
|
+
raw?: {
|
|
25
|
+
exchangeType?: string;
|
|
26
|
+
assertExchangeOptions?: any;
|
|
27
|
+
publishOptions?: any;
|
|
28
|
+
persistent?: boolean;
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
returnMeta?: boolean;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export declare class IntegrationEventPublisher {
|
|
34
|
+
private readonly publisher;
|
|
35
|
+
private readonly logger;
|
|
36
|
+
private readonly defaultExchange;
|
|
37
|
+
private readonly defaultExchangeType;
|
|
38
|
+
private readonly defaultAlternateExchange;
|
|
39
|
+
constructor(publisher: RabbitMQPublisherService, logger: LoggerContextService);
|
|
40
|
+
publish(opts: PublishIntegrationEventOptions): Promise<void | any>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=integration-event.publisher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration-event.publisher.d.ts","sourceRoot":"","sources":["../src/integration-event.publisher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAkB,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,GAAG,CAAC,EAAE;QACJ,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,qBAAqB,CAAC,EAAE,GAAG,CAAC;QAC5B,cAAc,CAAC,EAAE,GAAG,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC;CACH;AAED,qBACa,yBAAyB;IAMlC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0D;IAC1F,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAW;IAC/C,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAuE;gBAG7F,SAAS,EAAE,wBAAwB,EACnC,MAAM,EAAE,oBAAoB;IAGzC,OAAO,CAAC,IAAI,EAAE,8BAA8B,GAAG,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC;CA+CzE"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { Injectable } from '@nestjs/common';
|
|
11
|
+
import { LoggerContextService } from '@cargolift-cdi/common';
|
|
12
|
+
import { RabbitMQPublisherService } from './rabbitmq-publisher.service.js';
|
|
13
|
+
let IntegrationEventPublisher = class IntegrationEventPublisher {
|
|
14
|
+
constructor(publisher, logger) {
|
|
15
|
+
this.publisher = publisher;
|
|
16
|
+
this.logger = logger;
|
|
17
|
+
this.defaultExchange = process.env.RABBITMQ_EXCHANGE || 'integration.inbound';
|
|
18
|
+
this.defaultExchangeType = 'topic';
|
|
19
|
+
this.defaultAlternateExchange = process.env.RABBITMQ_ALTERNATE_EXCHANGE || 'integration.inbound.ae';
|
|
20
|
+
}
|
|
21
|
+
async publish(opts) {
|
|
22
|
+
const ctx = this.logger.getContext();
|
|
23
|
+
const exchange = opts.exchange || this.defaultExchange;
|
|
24
|
+
const routingKey = opts.routingKey;
|
|
25
|
+
const userAgent = opts.req?.headers?.['user-agent'] || 'unknown';
|
|
26
|
+
const ip = extractIp(opts.req);
|
|
27
|
+
const envelope = {
|
|
28
|
+
correlation_id: opts.envelope?.correlation_id || ctx?.correlation_id,
|
|
29
|
+
eventType: opts.envelope?.eventType || routingKey,
|
|
30
|
+
source: {
|
|
31
|
+
ip: opts.envelope?.source?.ip || ip,
|
|
32
|
+
user_agent: opts.envelope?.source?.user_agent || userAgent,
|
|
33
|
+
},
|
|
34
|
+
timestamp: opts.envelope?.timestamp,
|
|
35
|
+
...opts.envelope,
|
|
36
|
+
};
|
|
37
|
+
const headers = {
|
|
38
|
+
'x-correlation-id': envelope.correlation_id,
|
|
39
|
+
'x-trace': envelope?.trace || ctx?.trace,
|
|
40
|
+
'x-source': JSON.stringify(envelope.source),
|
|
41
|
+
...(opts.headers || {}),
|
|
42
|
+
};
|
|
43
|
+
return this.publisher.publish(exchange, routingKey, envelope, (opts.payload || opts.req?.body), {
|
|
44
|
+
exchangeType: opts.raw?.exchangeType || this.defaultExchangeType,
|
|
45
|
+
assertExchangeOptions: {
|
|
46
|
+
durable: true,
|
|
47
|
+
alternateExchange: this.defaultAlternateExchange,
|
|
48
|
+
...(opts.raw?.assertExchangeOptions || {}),
|
|
49
|
+
},
|
|
50
|
+
headers,
|
|
51
|
+
persistent: opts.raw?.persistent ?? true,
|
|
52
|
+
publishOptions: opts.raw?.publishOptions,
|
|
53
|
+
timeoutMs: opts.raw?.timeoutMs,
|
|
54
|
+
returnMeta: opts.raw?.returnMeta,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
IntegrationEventPublisher = __decorate([
|
|
59
|
+
Injectable(),
|
|
60
|
+
__metadata("design:paramtypes", [RabbitMQPublisherService,
|
|
61
|
+
LoggerContextService])
|
|
62
|
+
], IntegrationEventPublisher);
|
|
63
|
+
export { IntegrationEventPublisher };
|
|
64
|
+
function extractIp(req) {
|
|
65
|
+
if (!req)
|
|
66
|
+
return '0.0.0.0';
|
|
67
|
+
const xfwd = req.headers?.['x-forwarded-for'];
|
|
68
|
+
if (typeof xfwd === 'string' && xfwd.length > 0) {
|
|
69
|
+
return xfwd.split(',')[0].trim();
|
|
70
|
+
}
|
|
71
|
+
return (req.ip ||
|
|
72
|
+
req.connection?.remoteAddress ||
|
|
73
|
+
req.socket?.remoteAddress ||
|
|
74
|
+
req.info?.remoteAddress ||
|
|
75
|
+
'0.0.0.0');
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=integration-event.publisher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration-event.publisher.js","sourceRoot":"","sources":["../src/integration-event.publisher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,37 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { RabbitMQPublisherService } from './rabbitmq-publisher.service.js';
|
|
3
|
-
import { EnvelopeMessage } from '@cargolift-cdi/types';
|
|
1
|
+
import { IntegrationEventPublisher, PublishIntegrationEventOptions } from './integration-event.publisher.js';
|
|
4
2
|
/**
|
|
5
|
-
*
|
|
6
|
-
* Centraliza defaults e reduz verbosidade nos controllers.
|
|
3
|
+
* @deprecated Use IntegrationEventPublisher
|
|
7
4
|
*/
|
|
8
|
-
export
|
|
9
|
-
exchange?: string;
|
|
10
|
-
routingKey: string;
|
|
11
|
-
req?: Request;
|
|
12
|
-
payload?: any;
|
|
13
|
-
envelope?: Partial<EnvelopeMessage>;
|
|
14
|
-
headers?: Record<string, any>;
|
|
15
|
-
raw?: {
|
|
16
|
-
exchangeType?: string;
|
|
17
|
-
assertExchangeOptions?: any;
|
|
18
|
-
publishOptions?: any;
|
|
19
|
-
persistent?: boolean;
|
|
20
|
-
timeoutMs?: number;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
export declare class IntegrationPublisherService {
|
|
24
|
-
private readonly publisher;
|
|
25
|
-
private readonly logger;
|
|
26
|
-
private readonly defaultExchange;
|
|
27
|
-
private readonly defaultExchangeType;
|
|
28
|
-
private readonly defaultAlternateExchange;
|
|
29
|
-
constructor(publisher: RabbitMQPublisherService, logger: LoggerContextService);
|
|
5
|
+
export declare class IntegrationPublisherService extends IntegrationEventPublisher {
|
|
30
6
|
/**
|
|
31
|
-
*
|
|
32
|
-
* Exemplo de uso:
|
|
33
|
-
* await integrationPublisher.publish({ routingKey: 'integration.erp.demo', payload, envelope: { source } })
|
|
7
|
+
* @deprecated Use publish de IntegrationEventPublisher
|
|
34
8
|
*/
|
|
35
|
-
publish(opts:
|
|
9
|
+
publish(opts: PublishIntegrationEventOptions): Promise<any>;
|
|
36
10
|
}
|
|
37
11
|
//# sourceMappingURL=integration-publisher.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-publisher.service.d.ts","sourceRoot":"","sources":["../src/integration-publisher.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"integration-publisher.service.d.ts","sourceRoot":"","sources":["../src/integration-publisher.service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,MAAM,kCAAkC,CAAC;AAE7G;;GAEG;AACH,qBACa,2BAA4B,SAAQ,yBAAyB;IACxE;;OAEG;IACY,OAAO,CAAC,IAAI,EAAE,8BAA8B,GAAG,OAAO,CAAC,GAAG,CAAC;CAG3E"}
|
|
@@ -4,82 +4,24 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
// DEPRECATED: manter arquivo para compatibilidade e facilitar migração.
|
|
8
|
+
// Use IntegrationEventPublisher em vez de IntegrationPublisherService.
|
|
9
|
+
// Será removido em versão futura (>=0.2.0).
|
|
10
10
|
import { Injectable } from '@nestjs/common';
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
this.publisher = publisher;
|
|
17
|
-
this.logger = logger;
|
|
18
|
-
this.defaultExchange = process.env.RABBITMQ_EXCHANGE || 'integration.inbound';
|
|
19
|
-
this.defaultExchangeType = 'topic';
|
|
20
|
-
this.defaultAlternateExchange = process.env.RABBITMQ_ALTERNATE_EXCHANGE || 'integration.inbound.ae';
|
|
21
|
-
}
|
|
11
|
+
import { IntegrationEventPublisher } from './integration-event.publisher.js';
|
|
12
|
+
/**
|
|
13
|
+
* @deprecated Use IntegrationEventPublisher
|
|
14
|
+
*/
|
|
15
|
+
let IntegrationPublisherService = class IntegrationPublisherService extends IntegrationEventPublisher {
|
|
22
16
|
/**
|
|
23
|
-
*
|
|
24
|
-
* Exemplo de uso:
|
|
25
|
-
* await integrationPublisher.publish({ routingKey: 'integration.erp.demo', payload, envelope: { source } })
|
|
17
|
+
* @deprecated Use publish de IntegrationEventPublisher
|
|
26
18
|
*/
|
|
27
19
|
async publish(opts) {
|
|
28
|
-
|
|
29
|
-
const exchange = opts.exchange || this.defaultExchange;
|
|
30
|
-
const routingKey = opts.routingKey;
|
|
31
|
-
const userAgent = opts.req?.headers?.['user-agent'] || 'unknown';
|
|
32
|
-
const ip = extractIp(opts.req);
|
|
33
|
-
const envelope = {
|
|
34
|
-
correlation_id: opts.envelope?.correlation_id || ctx?.correlation_id,
|
|
35
|
-
eventType: opts.envelope?.eventType || routingKey,
|
|
36
|
-
source: {
|
|
37
|
-
ip: opts.envelope?.source?.ip || ip,
|
|
38
|
-
user_agent: opts.envelope?.source?.user_agent || userAgent,
|
|
39
|
-
...(opts.envelope?.source || {}),
|
|
40
|
-
},
|
|
41
|
-
timestamp: opts.envelope?.timestamp, // será preenchido pelo publisher se faltar
|
|
42
|
-
...opts.envelope,
|
|
43
|
-
};
|
|
44
|
-
const headers = {
|
|
45
|
-
'x-correlation-id': envelope.correlation_id,
|
|
46
|
-
'x-trace': envelope?.trace || ctx?.trace,
|
|
47
|
-
'x-source': envelope?.source || ctx?.source,
|
|
48
|
-
...(opts.headers || {}),
|
|
49
|
-
};
|
|
50
|
-
await this.publisher.publish(exchange, routingKey, envelope, (opts.payload || opts.req?.body), {
|
|
51
|
-
exchangeType: opts.raw?.exchangeType || this.defaultExchangeType,
|
|
52
|
-
assertExchangeOptions: {
|
|
53
|
-
durable: true,
|
|
54
|
-
alternateExchange: this.defaultAlternateExchange,
|
|
55
|
-
...(opts.raw?.assertExchangeOptions || {}),
|
|
56
|
-
},
|
|
57
|
-
headers,
|
|
58
|
-
persistent: opts.raw?.persistent ?? true,
|
|
59
|
-
publishOptions: opts.raw?.publishOptions,
|
|
60
|
-
timeoutMs: opts.raw?.timeoutMs,
|
|
61
|
-
});
|
|
20
|
+
return super.publish(opts);
|
|
62
21
|
}
|
|
63
22
|
};
|
|
64
23
|
IntegrationPublisherService = __decorate([
|
|
65
|
-
Injectable()
|
|
66
|
-
__metadata("design:paramtypes", [RabbitMQPublisherService,
|
|
67
|
-
LoggerContextService])
|
|
24
|
+
Injectable()
|
|
68
25
|
], IntegrationPublisherService);
|
|
69
26
|
export { IntegrationPublisherService };
|
|
70
|
-
// Helper isolado para evitar replicação de lógica ao extrair IP.
|
|
71
|
-
function extractIp(req) {
|
|
72
|
-
if (!req)
|
|
73
|
-
return '0.0.0.0';
|
|
74
|
-
const xfwd = req.headers?.['x-forwarded-for'];
|
|
75
|
-
if (typeof xfwd === 'string' && xfwd.length > 0) {
|
|
76
|
-
return xfwd.split(',')[0].trim();
|
|
77
|
-
}
|
|
78
|
-
// Express/Nest usual fields
|
|
79
|
-
return (req.ip ||
|
|
80
|
-
req.connection?.remoteAddress ||
|
|
81
|
-
req.socket?.remoteAddress ||
|
|
82
|
-
req.info?.remoteAddress ||
|
|
83
|
-
'0.0.0.0');
|
|
84
|
-
}
|
|
85
27
|
//# sourceMappingURL=integration-publisher.service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-publisher.service.js","sourceRoot":"","sources":["../src/integration-publisher.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"integration-publisher.service.js","sourceRoot":"","sources":["../src/integration-publisher.service.ts"],"names":[],"mappings":";;;;;;AAAA,wEAAwE;AACxE,uEAAuE;AACvE,4CAA4C;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,yBAAyB,EAAkC,MAAM,kCAAkC,CAAC;AAE7G;;GAEG;AAEI,IAAM,2BAA2B,GAAjC,MAAM,2BAA4B,SAAQ,yBAAyB;IACxE;;OAEG;IACM,KAAK,CAAC,OAAO,CAAC,IAAoC;QACzD,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;CACF,CAAA;AAPY,2BAA2B;IADvC,UAAU,EAAE;GACA,2BAA2B,CAOvC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { LoggerContextService } from '@cargolift-cdi/common';
|
|
2
|
+
/**
|
|
3
|
+
* Singleton leve para reutilizar conexão e (opcionalmente) canais de confirmação.
|
|
4
|
+
* Não implementa pool complexo; foco em reduzir overhead de connect.
|
|
5
|
+
*/
|
|
6
|
+
export declare class RabbitMQConnectionManager {
|
|
7
|
+
private readonly url;
|
|
8
|
+
private readonly logger?;
|
|
9
|
+
private static instance;
|
|
10
|
+
private connection?;
|
|
11
|
+
private connecting?;
|
|
12
|
+
private constructor();
|
|
13
|
+
static get(url: string, logger?: LoggerContextService): RabbitMQConnectionManager;
|
|
14
|
+
getConnection(): Promise<any>;
|
|
15
|
+
createConfirmChannel(): Promise<any>;
|
|
16
|
+
close(force?: boolean): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export declare function getRabbitConnectionManager(logger?: LoggerContextService): RabbitMQConnectionManager;
|
|
19
|
+
//# sourceMappingURL=rabbitmq-connection.manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rabbitmq-connection.manager.d.ts","sourceRoot":"","sources":["../src/rabbitmq-connection.manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAG7D;;;GAGG;AACH,qBAAa,yBAAyB;IAOhB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAN1E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA4B;IAGnD,OAAO,CAAC,UAAU,CAAC,CAAM;IACzB,OAAO,CAAC,UAAU,CAAC,CAAe;IAElC,OAAO;IAEP,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,oBAAoB;IAK/C,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC;IAkB7B,oBAAoB,IAAI,OAAO,CAAC,GAAG,CAAC;IAMpC,KAAK,CAAC,KAAK,UAAQ;CAM1B;AAED,wBAAgB,0BAA0B,CAAC,MAAM,CAAC,EAAE,oBAAoB,6BAIvE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as amqplib from 'amqplib';
|
|
2
|
+
import { assertRabbitEnv } from './rabbitmq.constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* Singleton leve para reutilizar conexão e (opcionalmente) canais de confirmação.
|
|
5
|
+
* Não implementa pool complexo; foco em reduzir overhead de connect.
|
|
6
|
+
*/
|
|
7
|
+
export class RabbitMQConnectionManager {
|
|
8
|
+
constructor(url, logger) {
|
|
9
|
+
this.url = url;
|
|
10
|
+
this.logger = logger;
|
|
11
|
+
}
|
|
12
|
+
static get(url, logger) {
|
|
13
|
+
if (!this.instance)
|
|
14
|
+
this.instance = new RabbitMQConnectionManager(url, logger);
|
|
15
|
+
return this.instance;
|
|
16
|
+
}
|
|
17
|
+
async getConnection() {
|
|
18
|
+
if (this.connection)
|
|
19
|
+
return this.connection;
|
|
20
|
+
if (this.connecting)
|
|
21
|
+
return this.connecting;
|
|
22
|
+
this.connecting = amqplib.connect(this.url).then((conn) => {
|
|
23
|
+
this.connection = conn;
|
|
24
|
+
conn.on('error', (err) => {
|
|
25
|
+
try {
|
|
26
|
+
this.logger?.error('RabbitMQ connection error', err, { application: { name: 'util-rabbitmq', function: 'RabbitMQConnectionManager' } });
|
|
27
|
+
}
|
|
28
|
+
catch { }
|
|
29
|
+
});
|
|
30
|
+
conn.on('close', () => {
|
|
31
|
+
this.connection = undefined;
|
|
32
|
+
});
|
|
33
|
+
return conn;
|
|
34
|
+
}).finally(() => { this.connecting = undefined; });
|
|
35
|
+
return this.connecting;
|
|
36
|
+
}
|
|
37
|
+
async createConfirmChannel() {
|
|
38
|
+
const conn = await this.getConnection();
|
|
39
|
+
const channel = await conn.createConfirmChannel();
|
|
40
|
+
return channel;
|
|
41
|
+
}
|
|
42
|
+
async close(force = false) {
|
|
43
|
+
if (force && this.connection) {
|
|
44
|
+
try {
|
|
45
|
+
await this.connection.close();
|
|
46
|
+
}
|
|
47
|
+
catch { }
|
|
48
|
+
this.connection = undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function getRabbitConnectionManager(logger) {
|
|
53
|
+
assertRabbitEnv(logger);
|
|
54
|
+
const url = process.env.RABBITMQ_URL;
|
|
55
|
+
return RabbitMQConnectionManager.get(url, logger);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=rabbitmq-connection.manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rabbitmq-connection.manager.js","sourceRoot":"","sources":["../src/rabbitmq-connection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;;GAGG;AACH,MAAM,OAAO,yBAAyB;IAOpC,YAAqC,GAAW,EAAmB,MAA6B;QAA3D,QAAG,GAAH,GAAG,CAAQ;QAAmB,WAAM,GAAN,MAAM,CAAuB;IAAG,CAAC;IAEpG,MAAM,CAAC,GAAG,CAAC,GAAW,EAAE,MAA6B;QACnD,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,yBAAyB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC/E,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC;QAC5C,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC;QAE5C,IAAI,CAAC,UAAU,GAAI,OAAe,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAS,EAAE,EAAE;YACtE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YAC3B,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAQ,EAAE,EAAE;gBACxB,IAAI,CAAC;oBAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,2BAA2B,EAAE,GAAU,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,2BAA2B,EAAE,EAAE,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;YAClK,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBACpB,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;YAC9B,CAAC,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QAEnD,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,oBAAoB;QACxB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAClD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK;QACvB,IAAI,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC;gBAAC,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YAC/C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC9B,CAAC;IACH,CAAC;CACF;AAED,MAAM,UAAU,0BAA0B,CAAC,MAA6B;IACtE,eAAe,CAAC,MAAM,CAAC,CAAC;IACxB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,YAAa,CAAC;IACtC,OAAO,yBAAyB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -8,5 +8,5 @@ import { LoggerContextService } from '@cargolift-cdi/common';
|
|
|
8
8
|
* @param dlqExchange Exchange da DLQ (opcional)
|
|
9
9
|
* @param dlqRoutingKey Routing key da DLQ (opcional)
|
|
10
10
|
*/
|
|
11
|
-
export declare function publishToDlqAndAck(channel: RabbitMQChannel, originalMsg: RabbitMQMessage, logger: LoggerContextService, error:
|
|
11
|
+
export declare function publishToDlqAndAck(channel: RabbitMQChannel, originalMsg: RabbitMQMessage, logger: LoggerContextService, error: unknown, dlqExchange?: string, dlqRoutingKey?: string): void;
|
|
12
12
|
//# sourceMappingURL=rabbitmq-publisher-dlq.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rabbitmq-publisher-dlq.service.d.ts","sourceRoot":"","sources":["../src/rabbitmq-publisher-dlq.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAiB,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE5E;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,eAAe,EACxB,WAAW,EAAE,eAAe,EAC5B,MAAM,EAAE,oBAAoB,EAC5B,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"rabbitmq-publisher-dlq.service.d.ts","sourceRoot":"","sources":["../src/rabbitmq-publisher-dlq.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAiB,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE5E;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,eAAe,EACxB,WAAW,EAAE,eAAe,EAC5B,MAAM,EAAE,oBAAoB,EAC5B,KAAK,EAAE,OAAO,EACd,WAAW,SAAc,EACzB,aAAa,SAAmB,QA2DjC"}
|
|
@@ -8,20 +8,70 @@ import { BusinessError } from '@cargolift-cdi/common';
|
|
|
8
8
|
* @param dlqRoutingKey Routing key da DLQ (opcional)
|
|
9
9
|
*/
|
|
10
10
|
export function publishToDlqAndAck(channel, originalMsg, logger, error, dlqExchange = 'email.dlx', dlqRoutingKey = 'email.send.dlq') {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
11
|
+
let normalized = { name: 'Error', message: 'Erro desconhecido' };
|
|
12
|
+
if (error instanceof Error) {
|
|
13
|
+
normalized = { name: error.name, message: error.message, stack: error.stack };
|
|
14
|
+
}
|
|
15
|
+
else if (typeof error === 'string') {
|
|
16
|
+
normalized = { name: 'Error', message: error };
|
|
17
|
+
}
|
|
18
|
+
else if (error && typeof error === 'object') {
|
|
19
|
+
try {
|
|
20
|
+
const anyErr = error;
|
|
21
|
+
normalized = { name: anyErr.name || 'Error', message: anyErr.message || JSON.stringify(anyErr), stack: anyErr.stack };
|
|
22
|
+
}
|
|
23
|
+
catch { }
|
|
24
|
+
}
|
|
18
25
|
if (error instanceof BusinessError) {
|
|
19
|
-
logger.businessError(
|
|
26
|
+
logger.businessError(normalized.message, { error: normalized });
|
|
20
27
|
}
|
|
21
28
|
else {
|
|
22
|
-
logger.error(
|
|
29
|
+
logger.error(normalized.message, { error: normalized });
|
|
30
|
+
}
|
|
31
|
+
const originalHeaders = originalMsg.properties.headers || {};
|
|
32
|
+
const headers = {
|
|
33
|
+
...originalHeaders,
|
|
34
|
+
'x-trace': logger.getContext().trace || originalHeaders['x-trace'] || `trace-missing:${process.env.npm_package_name}`,
|
|
35
|
+
'x-error-reason': normalized.message,
|
|
36
|
+
'x-exception-name': normalized.name,
|
|
37
|
+
};
|
|
38
|
+
if (normalized.stack) {
|
|
39
|
+
headers['x-error-stacktrace'] = normalized.stack.substring(0, 4000); // limita tamanho
|
|
40
|
+
}
|
|
41
|
+
// Payload enriquecido mantendo compatibilidade (fallback para conteúdo original)
|
|
42
|
+
let buffer = originalMsg.content;
|
|
43
|
+
try {
|
|
44
|
+
const enriched = {
|
|
45
|
+
failedAt: new Date().toISOString(),
|
|
46
|
+
error: normalized,
|
|
47
|
+
originalHeaders,
|
|
48
|
+
// tenta parsear original para permitir reprocessamento com contexto
|
|
49
|
+
originalPayload: safeParse(originalMsg.content),
|
|
50
|
+
};
|
|
51
|
+
buffer = Buffer.from(JSON.stringify(enriched));
|
|
52
|
+
headers['x-dlq-enriched'] = '1';
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
headers['x-dlq-enriched'] = '0';
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
channel.publish(dlqExchange, dlqRoutingKey, buffer, { headers });
|
|
59
|
+
channel.ack(originalMsg);
|
|
60
|
+
}
|
|
61
|
+
catch (pubErr) {
|
|
62
|
+
logger.error('Falha ao publicar mensagem em DLQ', { originalError: normalized, publishError: pubErr });
|
|
63
|
+
try {
|
|
64
|
+
channel.ack(originalMsg);
|
|
65
|
+
}
|
|
66
|
+
catch { /* evita loop */ }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function safeParse(buf) {
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(buf.toString('utf8'));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
23
75
|
}
|
|
24
|
-
channel.publish(dlqExchange, dlqRoutingKey, originalMsg.content, { headers });
|
|
25
|
-
channel.ack(originalMsg);
|
|
26
76
|
}
|
|
27
77
|
//# sourceMappingURL=rabbitmq-publisher-dlq.service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rabbitmq-publisher-dlq.service.js","sourceRoot":"","sources":["../src/rabbitmq-publisher-dlq.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAwB,MAAM,uBAAuB,CAAC;AAE5E;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAwB,EACxB,WAA4B,EAC5B,MAA4B,EAC5B,
|
|
1
|
+
{"version":3,"file":"rabbitmq-publisher-dlq.service.js","sourceRoot":"","sources":["../src/rabbitmq-publisher-dlq.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import * as amqp from 'amqplib';
|
|
2
|
-
import { EnvelopeMessage } from '@cargolift-cdi/types';
|
|
2
|
+
import { EnvelopeMessage, PublishMeta } from '@cargolift-cdi/types';
|
|
3
3
|
import { LoggerContextService } from '@cargolift-cdi/common';
|
|
4
4
|
export declare class RabbitMQPublisherService {
|
|
5
5
|
private readonly logger;
|
|
6
6
|
constructor(logger: LoggerContextService);
|
|
7
|
-
/**
|
|
8
|
-
* Emite mensagem diretamente com amqplib para garantir que headers virem nas Properties.
|
|
9
|
-
* - pattern: nome da fila/routingKey (ex: 'notifications')
|
|
10
|
-
* - payload: corpo da mensagem
|
|
11
|
-
* - opts: opções opcionais: { exchange, exchangeType, routingKey, headers }
|
|
12
|
-
*/
|
|
13
7
|
/**
|
|
14
8
|
* Publica mensagem em exchange usando ConfirmChannel para garantir confirmação (publisher confirms).
|
|
15
9
|
* Boas práticas amqplib aplicadas:
|
|
@@ -34,6 +28,7 @@ export declare class RabbitMQPublisherService {
|
|
|
34
28
|
persistent?: boolean;
|
|
35
29
|
timeoutMs?: number;
|
|
36
30
|
serialize?: (data: any) => Buffer;
|
|
37
|
-
|
|
31
|
+
returnMeta?: boolean;
|
|
32
|
+
}): Promise<void | PublishMeta>;
|
|
38
33
|
}
|
|
39
34
|
//# sourceMappingURL=rabbitmq-publisher.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rabbitmq-publisher.service.d.ts","sourceRoot":"","sources":["../src/rabbitmq-publisher.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rabbitmq-publisher.service.d.ts","sourceRoot":"","sources":["../src/rabbitmq-publisher.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAO7D,qBACa,wBAAwB;IACO,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,oBAAoB;IAEvF;;;;;;;;;;;;;;OAcG;IACG,OAAO,CACX,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,GAAG,EACZ,IAAI,CAAC,EAAE;QACL,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,qBAAqB,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;QACpD,cAAc,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;QACtC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC;QAClC,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,GACA,OAAO,CAAC,IAAI,GAAG,WAAW,CAAC;CAgH/B"}
|
|
@@ -11,148 +11,14 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
11
11
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
12
|
};
|
|
13
13
|
import { Inject, Injectable } from '@nestjs/common';
|
|
14
|
-
import * as amqp from 'amqplib';
|
|
15
14
|
import { LoggerContextService } from '@cargolift-cdi/common';
|
|
16
15
|
import { v4 as uuidv4 } from 'uuid';
|
|
16
|
+
import { getRabbitConnectionManager } from './rabbitmq-connection.manager.js';
|
|
17
|
+
import { DEFAULT_PUBLISH_TIMEOUT_MS } from './rabbitmq.constants.js';
|
|
17
18
|
let RabbitMQPublisherService = class RabbitMQPublisherService {
|
|
18
|
-
//constructor(private readonly logger: LoggerContextService) { }
|
|
19
19
|
constructor(logger) {
|
|
20
20
|
this.logger = logger;
|
|
21
21
|
}
|
|
22
|
-
/**
|
|
23
|
-
* Emite mensagem diretamente com amqplib para garantir que headers virem nas Properties.
|
|
24
|
-
* - pattern: nome da fila/routingKey (ex: 'notifications')
|
|
25
|
-
* - payload: corpo da mensagem
|
|
26
|
-
* - opts: opções opcionais: { exchange, exchangeType, routingKey, headers }
|
|
27
|
-
*/
|
|
28
|
-
/*
|
|
29
|
-
async emit(
|
|
30
|
-
pattern: string,
|
|
31
|
-
payload: any,
|
|
32
|
-
opts?: {
|
|
33
|
-
exchange?: string;
|
|
34
|
-
exchangeType?: string;
|
|
35
|
-
routingKey?: string;
|
|
36
|
-
headers?: Record<string, any>;
|
|
37
|
-
},
|
|
38
|
-
): Promise<void> {
|
|
39
|
-
const ctx = this.logger.getContext();
|
|
40
|
-
const headers: Record<string, any> = { ...(opts?.headers || {}) };
|
|
41
|
-
|
|
42
|
-
if (ctx?.correlation_id) headers['x-correlation-id'] = ctx.correlation_id;
|
|
43
|
-
if (ctx?.trace) headers['x-trace'] = ctx.trace;
|
|
44
|
-
if (ctx?.producer) headers['x-producer'] = ctx.producer;
|
|
45
|
-
|
|
46
|
-
headers['pattern'] = pattern;
|
|
47
|
-
const messageBody = { pattern, data: payload };
|
|
48
|
-
|
|
49
|
-
// URL do RabbitMQ (use a mesma que está no ClientsModule)
|
|
50
|
-
const url = process.env.RABBITMQ_URL;
|
|
51
|
-
if (!url) throw new Error('RABBITMQ_URL não definido');
|
|
52
|
-
|
|
53
|
-
const connection = await amqp.connect(url);
|
|
54
|
-
|
|
55
|
-
// Evita crash por "Unhandled 'error' event" e garante log com contexto atual
|
|
56
|
-
connection.on('error', (err) => {
|
|
57
|
-
try {
|
|
58
|
-
this.logger?.error('AMQP connection error', err as any,
|
|
59
|
-
{
|
|
60
|
-
application: { name: "util-rabbitmq", function: "RabbitMQPublisherService", action: "emit" },
|
|
61
|
-
data: { rabbitmq: { url, queue: pattern } }
|
|
62
|
-
});
|
|
63
|
-
} catch { }
|
|
64
|
-
});
|
|
65
|
-
connection.on('close', () => {
|
|
66
|
-
// intentionally left blank
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
let channel: amqp.Channel | null = null;
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
channel = await connection.createChannel();
|
|
73
|
-
|
|
74
|
-
channel.on('error', (err) => {
|
|
75
|
-
// intentionally left blank
|
|
76
|
-
});
|
|
77
|
-
channel.on('close', () => {
|
|
78
|
-
// intentionally left blank
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// Alinhar arguments da fila com o que já foi criado (ex.: x-dead-letter-exchange)
|
|
82
|
-
const queueArgs: Record<string, any> = {};
|
|
83
|
-
if (process.env.RABBITMQ_DLX) {
|
|
84
|
-
queueArgs['x-dead-letter-exchange'] = process.env.RABBITMQ_DLX;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Declare a fila com os mesmos argumentos (se houver) para evitar PRECONDITION_FAILED
|
|
88
|
-
const queueOptions = Object.keys(queueArgs).length
|
|
89
|
-
? { durable: true, arguments: queueArgs }
|
|
90
|
-
: { durable: true };
|
|
91
|
-
|
|
92
|
-
const content = Buffer.from(JSON.stringify(messageBody));
|
|
93
|
-
|
|
94
|
-
// Prioridade: opts.exchange > variável de ambiente RABBITMQ_EXCHANGE > enviar direto para fila
|
|
95
|
-
const exchangeToUse = opts?.exchange ?? process.env.RABBITMQ_EXCHANGE;
|
|
96
|
-
const exchangeType = opts?.exchangeType ?? (process.env.RABBITMQ_EXCHANGE_TYPE as any) ?? 'direct';
|
|
97
|
-
const routingKey = opts?.routingKey ?? pattern;
|
|
98
|
-
|
|
99
|
-
if (exchangeToUse) {
|
|
100
|
-
await channel.assertExchange(exchangeToUse, exchangeType, { durable: true });
|
|
101
|
-
const published = channel.publish(exchangeToUse, routingKey, content, {
|
|
102
|
-
persistent: true,
|
|
103
|
-
headers,
|
|
104
|
-
});
|
|
105
|
-
if (!published) {
|
|
106
|
-
// backpressure: aguardar 'drain' se necessário (simplificado)
|
|
107
|
-
await new Promise<void>((res) => channel!.once('drain', () => res()));
|
|
108
|
-
}
|
|
109
|
-
this.logger.info(`Mensagem publicada no exchange "${exchangeToUse}" com routingKey "${routingKey}"`, {
|
|
110
|
-
application: { name: "util-rabbitmq", function: "RabbitMQPublisherService", action: "emit" },
|
|
111
|
-
data: { rabbitmq: { queue: pattern, exchange: exchangeToUse, routingKey } },
|
|
112
|
-
});
|
|
113
|
-
} else {
|
|
114
|
-
// certifica que a fila existe antes de enviar diretamente
|
|
115
|
-
|
|
116
|
-
// await channel.assertQueue(pattern, queueOptions);
|
|
117
|
-
// channel.sendToQueue(pattern, content, {
|
|
118
|
-
// persistent: true,
|
|
119
|
-
// headers,
|
|
120
|
-
// });
|
|
121
|
-
|
|
122
|
-
channel.sendToQueue(pattern, content, {
|
|
123
|
-
persistent: true,
|
|
124
|
-
headers,
|
|
125
|
-
});
|
|
126
|
-
this.logger.info(`Mensagem publicada na fila do RabbitMQ "${pattern}"`, {
|
|
127
|
-
application: { name: "util-rabbitmq", function: "RabbitMQPublisherService", action: "emit" },
|
|
128
|
-
data: { rabbitmq: { queue: pattern } },
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
await channel.close();
|
|
133
|
-
} catch (err) {
|
|
134
|
-
// Loga com contexto e relança para que o controller/filtro capture
|
|
135
|
-
this.logger.error(`Erro ao publicar mensagem no RabbitMQ "${pattern}"`, err as any, {
|
|
136
|
-
application: { name: "util-rabbitmq", function: "RabbitMQPublisherService", action: "emit" },
|
|
137
|
-
data: { rabbitmq: { queue: pattern } },
|
|
138
|
-
});
|
|
139
|
-
throw err;
|
|
140
|
-
} finally {
|
|
141
|
-
try {
|
|
142
|
-
if (channel) {
|
|
143
|
-
try {
|
|
144
|
-
await channel.close();
|
|
145
|
-
} catch { }
|
|
146
|
-
}
|
|
147
|
-
} catch { }
|
|
148
|
-
try {
|
|
149
|
-
await connection.close();
|
|
150
|
-
} catch {
|
|
151
|
-
// ignora erros ao fechar conexão
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
*/
|
|
156
22
|
/**
|
|
157
23
|
* Publica mensagem em exchange usando ConfirmChannel para garantir confirmação (publisher confirms).
|
|
158
24
|
* Boas práticas amqplib aplicadas:
|
|
@@ -200,23 +66,11 @@ let RabbitMQPublisherService = class RabbitMQPublisherService {
|
|
|
200
66
|
};
|
|
201
67
|
const serialize = opts?.serialize || ((data) => Buffer.from(JSON.stringify(data)));
|
|
202
68
|
const content = serialize(messageBody);
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
throw new Error('RABBITMQ_URL não definido');
|
|
206
|
-
const connection = await amqp.connect(url);
|
|
207
|
-
connection.on('error', (err) => {
|
|
208
|
-
try {
|
|
209
|
-
this.logger?.error('AMQP connection error', err, {
|
|
210
|
-
application: { ...this.logger.getContext().application, function: 'RabbitMQPublisherService', action: 'publish', method: undefined },
|
|
211
|
-
data: { rabbitmq: { url, exchange, routingKey } },
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
catch { }
|
|
215
|
-
});
|
|
216
|
-
connection.on('close', () => { });
|
|
69
|
+
const started = performance.now?.() || Date.now();
|
|
70
|
+
const manager = getRabbitConnectionManager(this.logger);
|
|
217
71
|
let channel = null;
|
|
218
72
|
try {
|
|
219
|
-
channel = await
|
|
73
|
+
channel = await manager.createConfirmChannel();
|
|
220
74
|
channel.on('error', (err) => {
|
|
221
75
|
this.logger.error('Erro no ConfirmChannel', err, {
|
|
222
76
|
application: { ...this.logger.getContext().application, function: 'RabbitMQPublisherService', action: 'publish', method: undefined },
|
|
@@ -233,7 +87,7 @@ let RabbitMQPublisherService = class RabbitMQPublisherService {
|
|
|
233
87
|
contentType: 'application/json',
|
|
234
88
|
...opts?.publishOptions,
|
|
235
89
|
};
|
|
236
|
-
const timeoutMs = opts?.timeoutMs ??
|
|
90
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_PUBLISH_TIMEOUT_MS;
|
|
237
91
|
await new Promise((resolve, reject) => {
|
|
238
92
|
let settled = false;
|
|
239
93
|
const timer = setTimeout(() => {
|
|
@@ -265,6 +119,18 @@ let RabbitMQPublisherService = class RabbitMQPublisherService {
|
|
|
265
119
|
application: { ...this.logger.getContext().application, function: 'RabbitMQPublisherService', action: 'publish', method: undefined },
|
|
266
120
|
data: { rabbitmq: { exchange, routingKey, pattern } },
|
|
267
121
|
});
|
|
122
|
+
if (opts?.returnMeta) {
|
|
123
|
+
const end = performance.now?.() || Date.now();
|
|
124
|
+
return {
|
|
125
|
+
correlationId: envelope.correlation_id,
|
|
126
|
+
exchange,
|
|
127
|
+
routingKey,
|
|
128
|
+
pattern,
|
|
129
|
+
sizeBytes: content.byteLength,
|
|
130
|
+
durationMs: +(end - started),
|
|
131
|
+
confirmedAt: new Date().toISOString()
|
|
132
|
+
};
|
|
133
|
+
}
|
|
268
134
|
}
|
|
269
135
|
catch (err) {
|
|
270
136
|
this.logger.error(`Erro ao publicar (publishConfirm) no exchange "${exchange}"`, err, {
|
|
@@ -283,10 +149,6 @@ let RabbitMQPublisherService = class RabbitMQPublisherService {
|
|
|
283
149
|
}
|
|
284
150
|
}
|
|
285
151
|
catch { }
|
|
286
|
-
try {
|
|
287
|
-
await connection.close();
|
|
288
|
-
}
|
|
289
|
-
catch { }
|
|
290
152
|
}
|
|
291
153
|
}
|
|
292
154
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rabbitmq-publisher.service.js","sourceRoot":"","sources":["../src/rabbitmq-publisher.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"rabbitmq-publisher.service.js","sourceRoot":"","sources":["../src/rabbitmq-publisher.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { LoggerContextService } from '@cargolift-cdi/common';
|
|
2
|
+
export declare const DEFAULT_EXCHANGE: string;
|
|
3
|
+
export declare const DEFAULT_EXCHANGE_TYPE: string;
|
|
4
|
+
export declare const DEFAULT_ALTERNATE_EXCHANGE: string;
|
|
5
|
+
export declare const DEFAULT_PUBLISH_TIMEOUT_MS: number;
|
|
6
|
+
export declare function assertRabbitEnv(logger?: LoggerContextService): void;
|
|
7
|
+
//# sourceMappingURL=rabbitmq.constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rabbitmq.constants.d.ts","sourceRoot":"","sources":["../src/rabbitmq.constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,eAAO,MAAM,gBAAgB,QAAyD,CAAC;AACvF,eAAO,MAAM,qBAAqB,QAAgD,CAAC;AACnF,eAAO,MAAM,0BAA0B,QAAsE,CAAC;AAC9G,eAAO,MAAM,0BAA0B,QAA0D,CAAC;AAElG,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,oBAAoB,QAQ5D"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const DEFAULT_EXCHANGE = process.env.RABBITMQ_EXCHANGE || 'integration.inbound';
|
|
2
|
+
export const DEFAULT_EXCHANGE_TYPE = process.env.RABBITMQ_EXCHANGE_TYPE || 'topic';
|
|
3
|
+
export const DEFAULT_ALTERNATE_EXCHANGE = process.env.RABBITMQ_ALTERNATE_EXCHANGE || 'integration.inbound.ae';
|
|
4
|
+
export const DEFAULT_PUBLISH_TIMEOUT_MS = Number(process.env.RABBITMQ_PUBLISH_TIMEOUT_MS || 5000);
|
|
5
|
+
export function assertRabbitEnv(logger) {
|
|
6
|
+
const required = ['RABBITMQ_URL'];
|
|
7
|
+
const missing = required.filter((k) => !process.env[k]);
|
|
8
|
+
if (missing.length) {
|
|
9
|
+
const msg = `Variáveis de ambiente ausentes para RabbitMQ: ${missing.join(', ')}`;
|
|
10
|
+
logger?.error?.(msg, { application: { name: 'util-rabbitmq', function: 'assertRabbitEnv' } });
|
|
11
|
+
throw new Error(msg);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=rabbitmq.constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rabbitmq.constants.js","sourceRoot":"","sources":["../src/rabbitmq.constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,qBAAqB,CAAC;AACvF,MAAM,CAAC,MAAM,qBAAqB,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,OAAO,CAAC;AACnF,MAAM,CAAC,MAAM,0BAA0B,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,wBAAwB,CAAC;AAC9G,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,IAAI,CAAC,CAAC;AAElG,MAAM,UAAU,eAAe,CAAC,MAA6B;IAC3D,MAAM,QAAQ,GAAG,CAAC,cAAc,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,iDAAiD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClF,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC;QAC9F,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|