@ductape/sdk 0.0.4-v99 → 0.0.5
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/dist/agents/agent-context.d.ts +3 -1
- package/dist/agents/agent-context.js +19 -3
- package/dist/agents/agent-context.js.map +1 -1
- package/dist/agents/agents.service.js +9 -5
- package/dist/agents/agents.service.js.map +1 -1
- package/dist/agents/types/agents.types.d.ts +14 -1
- package/dist/agents/types/agents.types.js.map +1 -1
- package/dist/api/services/appApi.service.js +15 -6
- package/dist/api/services/appApi.service.js.map +1 -1
- package/dist/api/services/logsApi.service.d.ts +51 -0
- package/dist/api/services/logsApi.service.js +19 -2
- package/dist/api/services/logsApi.service.js.map +1 -1
- package/dist/api/services/processorApi.service.d.ts +568 -2
- package/dist/api/services/processorApi.service.js +412 -21
- package/dist/api/services/processorApi.service.js.map +1 -1
- package/dist/api/services/productsApi.service.d.ts +20 -0
- package/dist/api/services/productsApi.service.js +44 -15
- package/dist/api/services/productsApi.service.js.map +1 -1
- package/dist/api/services/secretsApi.service.js +0 -11
- package/dist/api/services/secretsApi.service.js.map +1 -1
- package/dist/api/services/webhooksApi.service.js +13 -6
- package/dist/api/services/webhooksApi.service.js.map +1 -1
- package/dist/api/services/workflowApi.service.js +30 -12
- package/dist/api/services/workflowApi.service.js.map +1 -1
- package/dist/api/urls.d.ts +26 -0
- package/dist/api/urls.js +30 -3
- package/dist/api/urls.js.map +1 -1
- package/dist/apps/validators/joi-validators/update.appAction.validator.js +12 -1
- package/dist/apps/validators/joi-validators/update.appAction.validator.js.map +1 -1
- package/dist/brokers/brokers.service.d.ts +140 -2
- package/dist/brokers/brokers.service.js +444 -36
- package/dist/brokers/brokers.service.js.map +1 -1
- package/dist/brokers/types/index.d.ts +251 -0
- package/dist/brokers/utils/providers/rabbitmq.service.d.ts +14 -4
- package/dist/brokers/utils/providers/rabbitmq.service.js +22 -35
- package/dist/brokers/utils/providers/rabbitmq.service.js.map +1 -1
- package/dist/cache/cache.manager.d.ts +84 -5
- package/dist/cache/cache.manager.js +478 -38
- package/dist/cache/cache.manager.js.map +1 -1
- package/dist/cache/cache.service.d.ts +5 -0
- package/dist/cache/cache.service.js +163 -6
- package/dist/cache/cache.service.js.map +1 -1
- package/dist/cache/index.d.ts +1 -1
- package/dist/cache/index.js +3 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/types/index.d.ts +4 -0
- package/dist/database/databases.service.d.ts +70 -2
- package/dist/database/databases.service.js +150 -35
- package/dist/database/databases.service.js.map +1 -1
- package/dist/database/types/dashboard.interface.d.ts +74 -0
- package/dist/database/types/dashboard.interface.js +7 -0
- package/dist/database/types/dashboard.interface.js.map +1 -0
- package/dist/database/types/index.d.ts +1 -0
- package/dist/graph/graphs.service.d.ts +50 -12
- package/dist/graph/graphs.service.js +689 -203
- package/dist/graph/graphs.service.js.map +1 -1
- package/dist/graph/types/connection.interface.d.ts +2 -2
- package/dist/index.d.ts +286 -4
- package/dist/index.js +370 -21
- package/dist/index.js.map +1 -1
- package/dist/logs/logs.types.d.ts +16 -3
- package/dist/logs/logs.types.js +11 -0
- package/dist/logs/logs.types.js.map +1 -1
- package/dist/notifications/notifications.service.d.ts +3 -0
- package/dist/notifications/notifications.service.js +57 -14
- package/dist/notifications/notifications.service.js.map +1 -1
- package/dist/notifications/types/notifications.types.d.ts +50 -0
- package/dist/processor/services/processor.service.d.ts +132 -8
- package/dist/processor/services/processor.service.js +1174 -267
- package/dist/processor/services/processor.service.js.map +1 -1
- package/dist/processor/utils/processor.utils.d.ts +5 -0
- package/dist/processor/utils/processor.utils.js +65 -12
- package/dist/processor/utils/processor.utils.js.map +1 -1
- package/dist/processor/utils/storage.util.js +11 -2
- package/dist/processor/utils/storage.util.js.map +1 -1
- package/dist/products/services/products.service.d.ts +19 -2
- package/dist/products/services/products.service.js +388 -54
- package/dist/products/services/products.service.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productFeature.validator.js +1 -1
- package/dist/products/validators/joi-validators/create.productJob.validator.js +2 -2
- package/dist/products/validators/joi-validators/create.productJob.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productMessageBrokerTopic.validator.js +1 -0
- package/dist/products/validators/joi-validators/create.productMessageBrokerTopic.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productNotification.validator.js +23 -12
- package/dist/products/validators/joi-validators/create.productNotification.validator.js.map +1 -1
- package/dist/resilience/fallback.service.d.ts +1 -0
- package/dist/resilience/fallback.service.js +2 -0
- package/dist/resilience/fallback.service.js.map +1 -1
- package/dist/resilience/quota.service.d.ts +1 -0
- package/dist/resilience/quota.service.js +2 -0
- package/dist/resilience/quota.service.js.map +1 -1
- package/dist/secrets/secrets.resolver.js +4 -1
- package/dist/secrets/secrets.resolver.js.map +1 -1
- package/dist/secrets/secrets.service.js +0 -12
- package/dist/secrets/secrets.service.js.map +1 -1
- package/dist/secrets/secrets.types.d.ts +3 -3
- package/dist/secrets/secrets.types.js +5 -5
- package/dist/secrets/secrets.types.js.map +1 -1
- package/dist/sessions/index.d.ts +1 -1
- package/dist/sessions/index.js +4 -1
- package/dist/sessions/index.js.map +1 -1
- package/dist/sessions/sessions.helper.d.ts +23 -3
- package/dist/sessions/sessions.helper.js +20 -3
- package/dist/sessions/sessions.helper.js.map +1 -1
- package/dist/sessions/sessions.resolver.d.ts +31 -0
- package/dist/sessions/sessions.resolver.js +230 -1
- package/dist/sessions/sessions.resolver.js.map +1 -1
- package/dist/sessions/sessions.service.d.ts +18 -2
- package/dist/sessions/sessions.service.js +121 -57
- package/dist/sessions/sessions.service.js.map +1 -1
- package/dist/sessions/types/index.d.ts +65 -21
- package/dist/storage/storage.service.d.ts +3 -0
- package/dist/storage/storage.service.js +179 -39
- package/dist/storage/storage.service.js.map +1 -1
- package/dist/types/index.types.d.ts +2 -0
- package/dist/types/inputs.types.d.ts +1 -0
- package/dist/types/inputs.types.js +3 -2
- package/dist/types/inputs.types.js.map +1 -1
- package/dist/types/processor.types.d.ts +72 -6
- package/dist/types/processor.types.js.map +1 -1
- package/dist/types/productsBuilder.types.d.ts +10 -0
- package/dist/types/productsBuilder.types.js +4 -0
- package/dist/types/productsBuilder.types.js.map +1 -1
- package/dist/vector/adapters/weaviate.adapter.js +22 -6
- package/dist/vector/adapters/weaviate.adapter.js.map +1 -1
- package/dist/vector/vector-database.service.d.ts +4 -2
- package/dist/vector/vector-database.service.js +71 -29
- package/dist/vector/vector-database.service.js.map +1 -1
- package/dist/workflows/types/workflows.types.d.ts +61 -3
- package/dist/workflows/types/workflows.types.js.map +1 -1
- package/dist/workflows/workflow-builder.js +17 -2
- package/dist/workflows/workflow-builder.js.map +1 -1
- package/dist/workflows/workflow-executor.d.ts +97 -18
- package/dist/workflows/workflow-executor.js +1449 -244
- package/dist/workflows/workflow-executor.js.map +1 -1
- package/dist/workflows/workflows.service.d.ts +2 -0
- package/dist/workflows/workflows.service.js +538 -74
- package/dist/workflows/workflows.service.js.map +1 -1
- package/package.json +11 -1
- package/dist/processor/services/fallback.service.d.ts +0 -5
- package/dist/processor/services/fallback.service.js +0 -43
- package/dist/processor/services/fallback.service.js.map +0 -1
- package/dist/processor/services/messagebrokers/aws-sqs.service.d.ts +0 -15
- package/dist/processor/services/messagebrokers/aws-sqs.service.js +0 -77
- package/dist/processor/services/messagebrokers/aws-sqs.service.js.map +0 -1
- package/dist/processor/services/messagebrokers/google-pubsub.service.d.ts +0 -16
- package/dist/processor/services/messagebrokers/google-pubsub.service.js +0 -34
- package/dist/processor/services/messagebrokers/google-pubsub.service.js.map +0 -1
- package/dist/processor/services/messagebrokers/index.d.ts +0 -3
- package/dist/processor/services/messagebrokers/index.js +0 -26
- package/dist/processor/services/messagebrokers/index.js.map +0 -1
- package/dist/processor/services/messagebrokers/kafka.service.d.ts +0 -14
- package/dist/processor/services/messagebrokers/kafka.service.js +0 -45
- package/dist/processor/services/messagebrokers/kafka.service.js.map +0 -1
- package/dist/processor/services/messagebrokers/messagebrokers.type.d.ts +0 -6
- package/dist/processor/services/messagebrokers/messagebrokers.type.js +0 -3
- package/dist/processor/services/messagebrokers/messagebrokers.type.js.map +0 -1
- package/dist/processor/services/messagebrokers/rabbitmq.service.d.ts +0 -14
- package/dist/processor/services/messagebrokers/rabbitmq.service.js +0 -67
- package/dist/processor/services/messagebrokers/rabbitmq.service.js.map +0 -1
- package/dist/processor/services/messagebrokers/redis.service.d.ts +0 -18
- package/dist/processor/services/messagebrokers/redis.service.js +0 -82
- package/dist/processor/services/messagebrokers/redis.service.js.map +0 -1
- package/dist/processor/services/quota.service.d.ts +0 -15
- package/dist/processor/services/quota.service.js +0 -63
- package/dist/processor/services/quota.service.js.map +0 -1
- package/dist/test/index.d.ts +0 -3
- package/dist/test/index.js +0 -11
- package/dist/test/index.js.map +0 -1
- package/dist/test/test.appBuilder.d.ts +0 -0
- package/dist/test/test.appBuilder.js +0 -1
- package/dist/test/test.appBuilder.js.map +0 -1
- package/dist/test/test.broker.kafka.d.ts +0 -1
- package/dist/test/test.broker.kafka.js +0 -172
- package/dist/test/test.broker.kafka.js.map +0 -1
- package/dist/test/test.broker.nats.d.ts +0 -1
- package/dist/test/test.broker.nats.js +0 -193
- package/dist/test/test.broker.nats.js.map +0 -1
- package/dist/test/test.broker.pubsub.d.ts +0 -1
- package/dist/test/test.broker.pubsub.js +0 -171
- package/dist/test/test.broker.pubsub.js.map +0 -1
- package/dist/test/test.broker.rabbitmq.d.ts +0 -1
- package/dist/test/test.broker.rabbitmq.js +0 -164
- package/dist/test/test.broker.rabbitmq.js.map +0 -1
- package/dist/test/test.broker.redis.d.ts +0 -1
- package/dist/test/test.broker.redis.js +0 -168
- package/dist/test/test.broker.redis.js.map +0 -1
- package/dist/test/test.broker.sqs.d.ts +0 -1
- package/dist/test/test.broker.sqs.js +0 -158
- package/dist/test/test.broker.sqs.js.map +0 -1
- package/dist/test/test.caches.d.ts +0 -1
- package/dist/test/test.caches.js +0 -231
- package/dist/test/test.caches.js.map +0 -1
- package/dist/test/test.database.d.ts +0 -1
- package/dist/test/test.database.dynamo.d.ts +0 -1
- package/dist/test/test.database.dynamo.js +0 -265
- package/dist/test/test.database.dynamo.js.map +0 -1
- package/dist/test/test.database.js +0 -140
- package/dist/test/test.database.js.map +0 -1
- package/dist/test/test.database.mongo.d.ts +0 -1
- package/dist/test/test.database.mongo.js +0 -371
- package/dist/test/test.database.mongo.js.map +0 -1
- package/dist/test/test.database.mysql.d.ts +0 -1
- package/dist/test/test.database.mysql.js +0 -415
- package/dist/test/test.database.mysql.js.map +0 -1
- package/dist/test/test.database.postgres.d.ts +0 -1
- package/dist/test/test.database.postgres.js +0 -412
- package/dist/test/test.database.postgres.js.map +0 -1
- package/dist/test/test.email.brevo.d.ts +0 -1
- package/dist/test/test.email.brevo.js +0 -326
- package/dist/test/test.email.brevo.js.map +0 -1
- package/dist/test/test.email.mailgun.d.ts +0 -1
- package/dist/test/test.email.mailgun.js +0 -352
- package/dist/test/test.email.mailgun.js.map +0 -1
- package/dist/test/test.email.postmark.d.ts +0 -1
- package/dist/test/test.email.postmark.js +0 -316
- package/dist/test/test.email.postmark.js.map +0 -1
- package/dist/test/test.email.sendgrid.d.ts +0 -1
- package/dist/test/test.email.sendgrid.js +0 -365
- package/dist/test/test.email.sendgrid.js.map +0 -1
- package/dist/test/test.email.smtp.d.ts +0 -1
- package/dist/test/test.email.smtp.js +0 -323
- package/dist/test/test.email.smtp.js.map +0 -1
- package/dist/test/test.graph.arangodb.d.ts +0 -1
- package/dist/test/test.graph.arangodb.js +0 -358
- package/dist/test/test.graph.arangodb.js.map +0 -1
- package/dist/test/test.graph.memgraph.d.ts +0 -1
- package/dist/test/test.graph.memgraph.js +0 -320
- package/dist/test/test.graph.memgraph.js.map +0 -1
- package/dist/test/test.graph.neo4j.d.ts +0 -1
- package/dist/test/test.graph.neo4j.js +0 -218
- package/dist/test/test.graph.neo4j.js.map +0 -1
- package/dist/test/test.graph.neptune.d.ts +0 -1
- package/dist/test/test.graph.neptune.js +0 -331
- package/dist/test/test.graph.neptune.js.map +0 -1
- package/dist/test/test.health.d.ts +0 -0
- package/dist/test/test.health.js +0 -1
- package/dist/test/test.health.js.map +0 -1
- package/dist/test/test.import.d.ts +0 -0
- package/dist/test/test.import.js +0 -1
- package/dist/test/test.import.js.map +0 -1
- package/dist/test/test.import.openapi.d.ts +0 -0
- package/dist/test/test.import.openapi.js +0 -1
- package/dist/test/test.import.openapi.js.map +0 -1
- package/dist/test/test.imports.d.ts +0 -1
- package/dist/test/test.imports.js +0 -21
- package/dist/test/test.imports.js.map +0 -1
- package/dist/test/test.logs.d.ts +0 -0
- package/dist/test/test.logs.js +0 -1
- package/dist/test/test.logs.js.map +0 -1
- package/dist/test/test.notifications.d.ts +0 -1
- package/dist/test/test.notifications.js +0 -198
- package/dist/test/test.notifications.js.map +0 -1
- package/dist/test/test.notifiers.d.ts +0 -0
- package/dist/test/test.notifiers.js +0 -1
- package/dist/test/test.notifiers.js.map +0 -1
- package/dist/test/test.processor.d.ts +0 -0
- package/dist/test/test.processor.js +0 -1
- package/dist/test/test.processor.js.map +0 -1
- package/dist/test/test.productBuilder.d.ts +0 -0
- package/dist/test/test.productBuilder.js +0 -1
- package/dist/test/test.productBuilder.js.map +0 -1
- package/dist/test/test.products.d.ts +0 -0
- package/dist/test/test.products.js +0 -1
- package/dist/test/test.products.js.map +0 -1
- package/dist/test/test.push.expo.d.ts +0 -1
- package/dist/test/test.push.expo.js +0 -442
- package/dist/test/test.push.expo.js.map +0 -1
- package/dist/test/test.push.firebase.d.ts +0 -1
- package/dist/test/test.push.firebase.js +0 -409
- package/dist/test/test.push.firebase.js.map +0 -1
- package/dist/test/test.session.d.ts +0 -1
- package/dist/test/test.session.js +0 -299
- package/dist/test/test.session.js.map +0 -1
- package/dist/test/test.sms.nexmo.d.ts +0 -1
- package/dist/test/test.sms.nexmo.js +0 -278
- package/dist/test/test.sms.nexmo.js.map +0 -1
- package/dist/test/test.sms.twilio.d.ts +0 -1
- package/dist/test/test.sms.twilio.js +0 -275
- package/dist/test/test.sms.twilio.js.map +0 -1
- package/dist/test/test.storage.d.ts +0 -1
- package/dist/test/test.storage.js +0 -202
- package/dist/test/test.storage.js.map +0 -1
- package/dist/test/test.triggers.d.ts +0 -1
- package/dist/test/test.triggers.js +0 -314
- package/dist/test/test.triggers.js.map +0 -1
- package/dist/test/test.vector.pinecone.d.ts +0 -1
- package/dist/test/test.vector.pinecone.js +0 -238
- package/dist/test/test.vector.pinecone.js.map +0 -1
- package/dist/test/test.vector.qdrant.d.ts +0 -1
- package/dist/test/test.vector.qdrant.js +0 -307
- package/dist/test/test.vector.qdrant.js.map +0 -1
- package/dist/test/test.vector.weaviate.d.ts +0 -1
- package/dist/test/test.vector.weaviate.js +0 -325
- package/dist/test/test.vector.weaviate.js.map +0 -1
|
@@ -22,6 +22,8 @@ const processorApi_service_1 = require("../api/services/processorApi.service");
|
|
|
22
22
|
const secrets_1 = require("../secrets");
|
|
23
23
|
const cache_manager_1 = require("../cache/cache.manager");
|
|
24
24
|
const sessions_1 = require("../sessions");
|
|
25
|
+
/** Log prefix for broker operations */
|
|
26
|
+
const LOG_PREFIX = '[BrokersService]';
|
|
25
27
|
/**
|
|
26
28
|
* Error class for broker operations
|
|
27
29
|
*/
|
|
@@ -72,6 +74,7 @@ exports.BrokerError = BrokerError;
|
|
|
72
74
|
*/
|
|
73
75
|
class BrokersService {
|
|
74
76
|
constructor(config) {
|
|
77
|
+
var _a;
|
|
75
78
|
this.logService = null;
|
|
76
79
|
this.productId = '';
|
|
77
80
|
this.productTag = '';
|
|
@@ -80,14 +83,195 @@ class BrokersService {
|
|
|
80
83
|
this.cacheManager = null;
|
|
81
84
|
/** Private keys per product for cache encryption */
|
|
82
85
|
this.privateKeys = new Map();
|
|
86
|
+
/** Connection pool for broker services - keyed by broker type + config hash */
|
|
87
|
+
this.brokerServicePool = new Map();
|
|
88
|
+
/** Cache for initialized broker configs - keyed by "productTag:brokerTag:envSlug" */
|
|
89
|
+
this.initializedBrokerCache = new Map();
|
|
90
|
+
/** Cache for initialized products - keyed by productTag */
|
|
91
|
+
this.initializedProducts = new Set();
|
|
92
|
+
/** Cache for registered broker consumers - keyed by consumerTag to track which consumers have been registered */
|
|
93
|
+
this.registeredConsumers = new Set();
|
|
94
|
+
/** Local cache for cache configurations to avoid repeated API calls */
|
|
95
|
+
this.cacheConfigCache = new Map();
|
|
96
|
+
/** Dedupe "Publish to broker - success" when same event is published twice in quick succession (e.g. workflow step run twice) */
|
|
97
|
+
this.lastPublishSuccessLogKey = null;
|
|
98
|
+
this.lastPublishSuccessLogTime = 0;
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// BROKER MESSAGE QUERY METHODS (for workbench with decryption)
|
|
101
|
+
// ============================================================================
|
|
102
|
+
/**
|
|
103
|
+
* Messages namespace for workbench broker message queries
|
|
104
|
+
* All methods decrypt message content before returning
|
|
105
|
+
*/
|
|
106
|
+
this.messages = {
|
|
107
|
+
/**
|
|
108
|
+
* Query broker messages with filtering and pagination
|
|
109
|
+
* Decrypts message content before returning
|
|
110
|
+
*/
|
|
111
|
+
query: async (options) => {
|
|
112
|
+
try {
|
|
113
|
+
await this.initializeProductForEvents(options.product);
|
|
114
|
+
const result = await this.processorApiService.queryBrokerMessages({
|
|
115
|
+
product_tag: options.product,
|
|
116
|
+
env: options.env,
|
|
117
|
+
broker_tag: options.brokerTag,
|
|
118
|
+
topic_tag: options.topicTag,
|
|
119
|
+
producer_tag: options.producerTag,
|
|
120
|
+
consumer_tag: options.consumerTag,
|
|
121
|
+
status: options.status,
|
|
122
|
+
start_date: options.startDate,
|
|
123
|
+
end_date: options.endDate,
|
|
124
|
+
page: options.page,
|
|
125
|
+
limit: options.limit,
|
|
126
|
+
}, this.getUserAccess());
|
|
127
|
+
// Decrypt message content for each message
|
|
128
|
+
const messages = result.messages.map((msg) => (Object.assign(Object.assign({}, msg), { message_decrypted: msg.message_encrypted
|
|
129
|
+
? this.decryptPayload(msg.message_encrypted)
|
|
130
|
+
: undefined })));
|
|
131
|
+
return {
|
|
132
|
+
messages,
|
|
133
|
+
total: result.total,
|
|
134
|
+
page: result.page,
|
|
135
|
+
limit: result.limit,
|
|
136
|
+
hasMore: result.hasMore,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
if (error instanceof BrokerError)
|
|
141
|
+
throw error;
|
|
142
|
+
throw new BrokerError(`Failed to query broker messages: ${error}`, 'QUERY_MESSAGES_FAILED', error);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
/**
|
|
146
|
+
* Get broker producers with pagination
|
|
147
|
+
*/
|
|
148
|
+
getProducers: async (options) => {
|
|
149
|
+
try {
|
|
150
|
+
await this.initializeProductForEvents(options.product);
|
|
151
|
+
return await this.processorApiService.getBrokerProducers({
|
|
152
|
+
product_tag: options.product,
|
|
153
|
+
env: options.env,
|
|
154
|
+
broker_tag: options.brokerTag,
|
|
155
|
+
topic_tag: options.topicTag,
|
|
156
|
+
page: options.page,
|
|
157
|
+
limit: options.limit,
|
|
158
|
+
}, this.getUserAccess());
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
if (error instanceof BrokerError)
|
|
162
|
+
throw error;
|
|
163
|
+
throw new BrokerError(`Failed to get broker producers: ${error}`, 'GET_PRODUCERS_FAILED', error);
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
/**
|
|
167
|
+
* Get broker consumers with pagination
|
|
168
|
+
*/
|
|
169
|
+
getConsumers: async (options) => {
|
|
170
|
+
try {
|
|
171
|
+
await this.initializeProductForEvents(options.product);
|
|
172
|
+
return await this.processorApiService.getBrokerConsumers({
|
|
173
|
+
product_tag: options.product,
|
|
174
|
+
env: options.env,
|
|
175
|
+
broker_tag: options.brokerTag,
|
|
176
|
+
topic_tag: options.topicTag,
|
|
177
|
+
page: options.page,
|
|
178
|
+
limit: options.limit,
|
|
179
|
+
}, this.getUserAccess());
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
if (error instanceof BrokerError)
|
|
183
|
+
throw error;
|
|
184
|
+
throw new BrokerError(`Failed to get broker consumers: ${error}`, 'GET_CONSUMERS_FAILED', error);
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
/**
|
|
188
|
+
* Get broker dead letters with pagination
|
|
189
|
+
* Decrypts message content before returning
|
|
190
|
+
*/
|
|
191
|
+
getDeadLetters: async (options) => {
|
|
192
|
+
try {
|
|
193
|
+
await this.initializeProductForEvents(options.product);
|
|
194
|
+
const result = await this.processorApiService.getBrokerDeadLetters({
|
|
195
|
+
product_tag: options.product,
|
|
196
|
+
env: options.env,
|
|
197
|
+
broker_tag: options.brokerTag,
|
|
198
|
+
topic_tag: options.topicTag,
|
|
199
|
+
consumer_tag: options.consumerTag,
|
|
200
|
+
start_date: options.startDate,
|
|
201
|
+
end_date: options.endDate,
|
|
202
|
+
page: options.page,
|
|
203
|
+
limit: options.limit,
|
|
204
|
+
}, this.getUserAccess());
|
|
205
|
+
// Decrypt message content for dead letters
|
|
206
|
+
const deadLetters = result.deadLetters.map((dl) => (Object.assign(Object.assign({}, dl), { original_message: dl.original_message ? Object.assign(Object.assign({}, dl.original_message), { message_decrypted: dl.original_message.message_encrypted
|
|
207
|
+
? this.decryptPayload(dl.original_message.message_encrypted)
|
|
208
|
+
: undefined }) : dl.original_message })));
|
|
209
|
+
return {
|
|
210
|
+
deadLetters,
|
|
211
|
+
total: result.total,
|
|
212
|
+
page: result.page,
|
|
213
|
+
limit: result.limit,
|
|
214
|
+
hasMore: result.hasMore,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
if (error instanceof BrokerError)
|
|
219
|
+
throw error;
|
|
220
|
+
throw new BrokerError(`Failed to get broker dead letters: ${error}`, 'GET_DEAD_LETTERS_FAILED', error);
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
/**
|
|
224
|
+
* Get comprehensive broker message statistics
|
|
225
|
+
*/
|
|
226
|
+
getStats: async (options) => {
|
|
227
|
+
try {
|
|
228
|
+
await this.initializeProductForEvents(options.product);
|
|
229
|
+
return await this.processorApiService.getBrokerComprehensiveStats({
|
|
230
|
+
product_tag: options.product,
|
|
231
|
+
env: options.env,
|
|
232
|
+
broker_tag: options.brokerTag,
|
|
233
|
+
}, this.getUserAccess());
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
if (error instanceof BrokerError)
|
|
237
|
+
throw error;
|
|
238
|
+
throw new BrokerError(`Failed to get broker stats: ${error}`, 'GET_STATS_FAILED', error);
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
/**
|
|
242
|
+
* Get broker dashboard overview data
|
|
243
|
+
* Decrypts message content for recent messages
|
|
244
|
+
*/
|
|
245
|
+
getDashboard: async (options) => {
|
|
246
|
+
try {
|
|
247
|
+
await this.initializeProductForEvents(options.product);
|
|
248
|
+
const result = await this.processorApiService.getBrokerDashboard({
|
|
249
|
+
product_tag: options.product,
|
|
250
|
+
env: options.env,
|
|
251
|
+
broker_tag: options.brokerTag,
|
|
252
|
+
}, this.getUserAccess());
|
|
253
|
+
// Decrypt recent messages
|
|
254
|
+
const recentMessages = (result.recent_messages || []).map((msg) => (Object.assign(Object.assign({}, msg), { message_decrypted: msg.message_encrypted
|
|
255
|
+
? this.decryptPayload(msg.message_encrypted)
|
|
256
|
+
: undefined })));
|
|
257
|
+
return Object.assign(Object.assign({}, result), { recent_messages: recentMessages });
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
if (error instanceof BrokerError)
|
|
261
|
+
throw error;
|
|
262
|
+
throw new BrokerError(`Failed to get broker dashboard: ${error}`, 'GET_DASHBOARD_FAILED', error);
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
};
|
|
83
266
|
this.config = config;
|
|
84
|
-
this.productBuilderService = new products_service_1.default({
|
|
267
|
+
this.productBuilderService = (_a = config.preInitializedProductBuilder) !== null && _a !== void 0 ? _a : new products_service_1.default({
|
|
85
268
|
workspace_id: config.workspace_id,
|
|
86
269
|
public_key: config.public_key,
|
|
87
270
|
user_id: config.user_id,
|
|
88
271
|
token: config.token,
|
|
89
272
|
env_type: config.env_type,
|
|
90
273
|
redis_client: config.redis_client,
|
|
274
|
+
access_key: config.access_key,
|
|
91
275
|
});
|
|
92
276
|
this.processorApiService = new processorApi_service_1.ProcessorApiService(config.env_type);
|
|
93
277
|
// Initialize CacheManager if Redis client is provided
|
|
@@ -111,16 +295,40 @@ class BrokersService {
|
|
|
111
295
|
token: this.config.token,
|
|
112
296
|
workspace_id: this.config.workspace_id,
|
|
113
297
|
public_key: this.config.public_key,
|
|
298
|
+
access_key: this.config.access_key,
|
|
114
299
|
};
|
|
115
300
|
}
|
|
116
301
|
/**
|
|
117
|
-
* Initialize product and get broker configuration
|
|
302
|
+
* Initialize product and get broker configuration (with caching)
|
|
118
303
|
*/
|
|
119
|
-
async initializeBroker(productTag, envSlug, event) {
|
|
304
|
+
async initializeBroker(productTag, envSlug, event, message) {
|
|
305
|
+
var _a, _b;
|
|
120
306
|
// Parse event to get broker and topic tags
|
|
121
307
|
const { brokerTag, topicTag } = (0, broker_util_1.parseEventString)(event);
|
|
122
|
-
//
|
|
123
|
-
|
|
308
|
+
// Check cache first (keyed by product:broker:env)
|
|
309
|
+
const cacheKey = `${productTag}:${brokerTag}:${envSlug}`;
|
|
310
|
+
const cached = this.initializedBrokerCache.get(cacheKey);
|
|
311
|
+
if (cached) {
|
|
312
|
+
// For cached brokers, just check if topic exists (might be new topic)
|
|
313
|
+
let topic = (_a = cached.broker.topics) === null || _a === void 0 ? void 0 : _a.find(t => t.tag === topicTag);
|
|
314
|
+
if (!topic) {
|
|
315
|
+
if (message) {
|
|
316
|
+
this.ensureTopicRegistered(brokerTag, topicTag, message);
|
|
317
|
+
}
|
|
318
|
+
topic = { tag: topicTag, name: topicTag, sample: message || {} };
|
|
319
|
+
}
|
|
320
|
+
// Determine topic URL
|
|
321
|
+
let topicUrl = topic.name;
|
|
322
|
+
if (cached.brokerEnv.type === types_1.MessageBrokerTypes.AWS_SQS) {
|
|
323
|
+
topicUrl = (0, broker_util_1.getSqsQueueUrl)(topic, envSlug);
|
|
324
|
+
}
|
|
325
|
+
return Object.assign(Object.assign({}, cached), { topic, topicUrl });
|
|
326
|
+
}
|
|
327
|
+
// Initialize product only if not already done
|
|
328
|
+
if (!this.initializedProducts.has(productTag)) {
|
|
329
|
+
await this.productBuilderService.initializeProductByTag(productTag);
|
|
330
|
+
this.initializedProducts.add(productTag);
|
|
331
|
+
}
|
|
124
332
|
this.productTag = productTag;
|
|
125
333
|
this.productId = this.productBuilderService.fetchProductId() || '';
|
|
126
334
|
this.privateKey = this.productBuilderService.fetchPrivateKey();
|
|
@@ -129,15 +337,21 @@ class BrokersService {
|
|
|
129
337
|
if (!broker) {
|
|
130
338
|
throw new BrokerError(`Message Broker ${brokerTag} not found`, 'BROKER_NOT_FOUND');
|
|
131
339
|
}
|
|
340
|
+
if (!broker.envs || !Array.isArray(broker.envs)) {
|
|
341
|
+
throw new BrokerError(`Message Broker ${brokerTag} has no environments configured`, 'BROKER_NO_ENVS');
|
|
342
|
+
}
|
|
132
343
|
// Get environment-specific broker config
|
|
133
344
|
const brokerEnv = broker.envs.find((el) => el.slug === envSlug);
|
|
134
345
|
if (!brokerEnv) {
|
|
135
346
|
throw new BrokerError(`Broker environment for ${envSlug} not found`, 'BROKER_ENV_NOT_FOUND');
|
|
136
347
|
}
|
|
137
|
-
//
|
|
138
|
-
|
|
348
|
+
// Check if topic exists in broker's topics array
|
|
349
|
+
let topic = (_b = broker.topics) === null || _b === void 0 ? void 0 : _b.find(t => t.tag === topicTag);
|
|
139
350
|
if (!topic) {
|
|
140
|
-
|
|
351
|
+
if (message) {
|
|
352
|
+
this.ensureTopicRegistered(brokerTag, topicTag, message);
|
|
353
|
+
}
|
|
354
|
+
topic = { tag: topicTag, name: topicTag, sample: message || {} };
|
|
141
355
|
}
|
|
142
356
|
// Resolve any secret references in broker config
|
|
143
357
|
let resolvedConfig = brokerEnv.config;
|
|
@@ -148,18 +362,23 @@ class BrokersService {
|
|
|
148
362
|
resolvedConfig = resolved.value;
|
|
149
363
|
}
|
|
150
364
|
else {
|
|
151
|
-
throw new BrokerError(`Broker configuration contains secret references but secrets service is not initialized
|
|
152
|
-
`Please ensure the Ductape client is properly initialized.`, 'SECRETS_NOT_INITIALIZED');
|
|
365
|
+
throw new BrokerError(`Broker configuration contains secret references but secrets service is not initialized.`, 'SECRETS_NOT_INITIALIZED');
|
|
153
366
|
}
|
|
154
367
|
}
|
|
155
|
-
// Create
|
|
368
|
+
// Create resolved broker env
|
|
156
369
|
const resolvedBrokerEnv = Object.assign(Object.assign({}, brokerEnv), { config: resolvedConfig });
|
|
157
370
|
// Determine the topic URL/name
|
|
158
371
|
let topicUrl = topic.name;
|
|
159
|
-
// Special handling for AWS SQS which requires queue URLs
|
|
160
372
|
if (brokerEnv.type === types_1.MessageBrokerTypes.AWS_SQS) {
|
|
161
373
|
topicUrl = (0, broker_util_1.getSqsQueueUrl)(topic, envSlug);
|
|
162
374
|
}
|
|
375
|
+
// Cache the result (without topic, as topics may vary per call)
|
|
376
|
+
this.initializedBrokerCache.set(cacheKey, {
|
|
377
|
+
broker,
|
|
378
|
+
topic, // Store last topic, but will be re-evaluated on cache hit
|
|
379
|
+
brokerEnv: resolvedBrokerEnv,
|
|
380
|
+
topicUrl,
|
|
381
|
+
});
|
|
163
382
|
return { broker, topic, brokerEnv: resolvedBrokerEnv, topicUrl };
|
|
164
383
|
}
|
|
165
384
|
/**
|
|
@@ -179,26 +398,109 @@ class BrokersService {
|
|
|
179
398
|
}
|
|
180
399
|
/**
|
|
181
400
|
* Validate cache tag exists in product and return cache configuration
|
|
401
|
+
* Uses local in-memory cache to avoid repeated API calls (5 minute TTL)
|
|
182
402
|
*/
|
|
183
403
|
async validateCache(cacheTag) {
|
|
404
|
+
const cacheKey = `${this.productTag}:${cacheTag}`;
|
|
405
|
+
const cached = this.cacheConfigCache.get(cacheKey);
|
|
406
|
+
const now = Date.now();
|
|
407
|
+
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
408
|
+
// Return cached config if still valid
|
|
409
|
+
if (cached && (now - cached.fetchedAt) < CACHE_TTL) {
|
|
410
|
+
return { expiry: cached.expiry };
|
|
411
|
+
}
|
|
412
|
+
// Fetch from API and cache the result
|
|
184
413
|
const cache = await this.productBuilderService.fetchCache(cacheTag);
|
|
185
414
|
if (!cache) {
|
|
186
415
|
throw new BrokerError(`Cache configuration '${cacheTag}' does not exist`, 'CACHE_NOT_FOUND');
|
|
187
416
|
}
|
|
417
|
+
this.cacheConfigCache.set(cacheKey, { expiry: cache.expiry, fetchedAt: now });
|
|
188
418
|
return { expiry: cache.expiry };
|
|
189
419
|
}
|
|
190
420
|
/**
|
|
191
|
-
*
|
|
421
|
+
* Generate a cache key for the broker service pool
|
|
422
|
+
*/
|
|
423
|
+
getBrokerPoolKey(type, config) {
|
|
424
|
+
var _a;
|
|
425
|
+
// Use type + url/host as the key (url for RabbitMQ, host for others)
|
|
426
|
+
const configKey = (config === null || config === void 0 ? void 0 : config.url) || (config === null || config === void 0 ? void 0 : config.host) || ((_a = config === null || config === void 0 ? void 0 : config.brokers) === null || _a === void 0 ? void 0 : _a[0]) || JSON.stringify(config);
|
|
427
|
+
return `${type}:${configKey}`;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Get or create broker service instance (with connection pooling)
|
|
192
431
|
*/
|
|
193
432
|
async getBrokerService(type, config) {
|
|
194
433
|
if ((0, broker_util_1.isBrowser)()) {
|
|
195
434
|
throw new BrokerError('Broker operations are not supported in browser environment', 'BROWSER_NOT_SUPPORTED');
|
|
196
435
|
}
|
|
436
|
+
// Check if we have a cached connection
|
|
437
|
+
const poolKey = this.getBrokerPoolKey(type, config);
|
|
438
|
+
const existingService = this.brokerServicePool.get(poolKey);
|
|
439
|
+
if (existingService) {
|
|
440
|
+
return existingService;
|
|
441
|
+
}
|
|
197
442
|
const createBrokerService = await (0, broker_util_1.loadBrokerService)();
|
|
198
443
|
if (!createBrokerService) {
|
|
199
444
|
throw new BrokerError('Failed to load broker service', 'BROKER_SERVICE_LOAD_FAILED');
|
|
200
445
|
}
|
|
201
|
-
|
|
446
|
+
const service = createBrokerService(type, config);
|
|
447
|
+
// Store in pool for reuse
|
|
448
|
+
this.brokerServicePool.set(poolKey, service);
|
|
449
|
+
return service;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Disconnect all pooled broker connections (e.g. at end of workflow run). Safe if pool is empty.
|
|
453
|
+
*/
|
|
454
|
+
async disconnectAll() {
|
|
455
|
+
for (const service of this.brokerServicePool.values()) {
|
|
456
|
+
try {
|
|
457
|
+
if (typeof service.disconnect === 'function') {
|
|
458
|
+
await service.disconnect();
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
catch (_a) {
|
|
462
|
+
// Non-fatal
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
this.brokerServicePool.clear();
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Pre-warm broker connections for the given product/env and broker tags.
|
|
469
|
+
* Call before step execution so the first produce step reuses connections. Same auth and secrets as publish.
|
|
470
|
+
*/
|
|
471
|
+
async warmBrokerConnections(options) {
|
|
472
|
+
const { product, env, brokerTags } = options;
|
|
473
|
+
if (brokerTags.length === 0)
|
|
474
|
+
return;
|
|
475
|
+
for (const brokerTag of brokerTags) {
|
|
476
|
+
try {
|
|
477
|
+
const { brokerEnv } = await this.initializeBroker(product, env, `${brokerTag}:_warm`, {});
|
|
478
|
+
const service = await this.getBrokerService(brokerEnv.type, brokerEnv.config);
|
|
479
|
+
if (typeof service.connect === 'function')
|
|
480
|
+
await service.connect();
|
|
481
|
+
}
|
|
482
|
+
catch (_a) {
|
|
483
|
+
// Non-fatal: step will connect on first use
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Auto-register a topic in the background (fire-and-forget)
|
|
489
|
+
* This is intentionally lightweight - no pre-check, no post-fetch
|
|
490
|
+
*/
|
|
491
|
+
ensureTopicRegistered(brokerTag, topicTag, message) {
|
|
492
|
+
const fullTag = `${brokerTag}:${topicTag}`;
|
|
493
|
+
// Fire-and-forget: don't await, let it run in background
|
|
494
|
+
this.productBuilderService.createMessageBrokerTopic({
|
|
495
|
+
tag: fullTag,
|
|
496
|
+
name: topicTag,
|
|
497
|
+
description: `Auto-registered topic for ${fullTag}`,
|
|
498
|
+
sample: JSON.stringify(message || {}),
|
|
499
|
+
idempotent: false,
|
|
500
|
+
}).catch(() => {
|
|
501
|
+
// Silently ignore - topic might already exist or registration failed
|
|
502
|
+
// Either way, the publish should proceed
|
|
503
|
+
});
|
|
202
504
|
}
|
|
203
505
|
/**
|
|
204
506
|
* Auto-register a producer if it doesn't exist
|
|
@@ -244,15 +546,16 @@ class BrokersService {
|
|
|
244
546
|
* Publish a message to a broker topic
|
|
245
547
|
*/
|
|
246
548
|
async publish(options) {
|
|
247
|
-
var _a, _b;
|
|
549
|
+
var _a, _b, _c, _d;
|
|
248
550
|
const process_id = (0, processor_utils_1.generateObjectId)();
|
|
249
551
|
const start = Date.now();
|
|
250
552
|
const { cache } = options;
|
|
251
553
|
let sessionLogFields = {};
|
|
252
554
|
let resolvedMessage = options.message;
|
|
555
|
+
// Parse event string early to have broker/topic tags available for error logging
|
|
556
|
+
const { brokerTag, topicTag } = (0, broker_util_1.parseEventString)(options.event);
|
|
253
557
|
try {
|
|
254
|
-
const { broker, topic, brokerEnv, topicUrl } = await this.initializeBroker(options.product, options.env, options.event);
|
|
255
|
-
const { brokerTag, topicTag } = (0, broker_util_1.parseEventString)(options.event);
|
|
558
|
+
const { broker, topic, brokerEnv, topicUrl } = await this.initializeBroker(options.product, options.env, options.event, options.message);
|
|
256
559
|
// Store private key for cache operations
|
|
257
560
|
if (this.privateKey) {
|
|
258
561
|
this.privateKeys.set(options.product, this.privateKey);
|
|
@@ -261,7 +564,12 @@ class BrokersService {
|
|
|
261
564
|
if (options.session && this.privateKey) {
|
|
262
565
|
// Convert session object { tag, token } to string format "tag:token"
|
|
263
566
|
const sessionToken = `${options.session.tag}:${options.session.token}`;
|
|
264
|
-
const sessionResult = await (0, sessions_1.processSessionForExecution)(sessionToken, this.privateKey, { message: options.message }, options.env
|
|
567
|
+
const sessionResult = await (0, sessions_1.processSessionForExecution)(sessionToken, this.privateKey, { message: options.message }, options.env, {
|
|
568
|
+
fetchSessionSelector: async (sessionTag) => {
|
|
569
|
+
const sessionConfig = await this.productBuilderService.fetchSession(sessionTag);
|
|
570
|
+
return sessionConfig === null || sessionConfig === void 0 ? void 0 : sessionConfig.selector;
|
|
571
|
+
},
|
|
572
|
+
});
|
|
265
573
|
if (sessionResult.error) {
|
|
266
574
|
throw new BrokerError(`Session validation failed: ${sessionResult.error}`, 'SESSION_INVALID');
|
|
267
575
|
}
|
|
@@ -271,7 +579,7 @@ class BrokersService {
|
|
|
271
579
|
// Auto-register producer if not exists
|
|
272
580
|
await this.ensureProducerRegistered(brokerTag, topicTag, options.producer);
|
|
273
581
|
this.initializeLogService();
|
|
274
|
-
const baseLogs = Object.assign({ product_tag: options.product, product_id: this.productId, workspace_id: this.config.workspace_id, env: options.env, process_id, type: types_2.LogEventTypes.
|
|
582
|
+
const baseLogs = Object.assign({ product_tag: options.product, product_id: this.productId, workspace_id: this.config.workspace_id, env: options.env, process_id, type: types_2.LogEventTypes.PRODUCER, parent_tag: brokerTag, child_tag: topicTag, data: { event: options.event } }, sessionLogFields);
|
|
275
583
|
this.logService.add(Object.assign(Object.assign({}, baseLogs), { start, message: 'Publish to broker - initiated', status: types_2.LogEventStatus.PROCESSING }));
|
|
276
584
|
// Check cache for idempotency (prevent duplicate publishes with same data)
|
|
277
585
|
if (cache && this.cacheManager && this.privateKey) {
|
|
@@ -290,22 +598,47 @@ class BrokersService {
|
|
|
290
598
|
if (cached.hit && cached.data) {
|
|
291
599
|
const end = Date.now();
|
|
292
600
|
this.logService.add(Object.assign(Object.assign({}, baseLogs), { start,
|
|
293
|
-
end, message: `Publish to broker - cache hit (${cached.source})`, successful_execution: true, status: types_2.LogEventStatus.SUCCESS, data: { event: options.event, cache_source: cached.source } }));
|
|
601
|
+
end, message: `Publish to broker - cache hit (${cached.source})`, successful_execution: true, status: types_2.LogEventStatus.SUCCESS, data: { event: options.event, cache_source: cached.source }, cache_tag: cache, cache_key: cached.key, cache_status: true }));
|
|
294
602
|
this.logService.publish();
|
|
295
603
|
return cached.data;
|
|
296
604
|
}
|
|
297
605
|
}
|
|
606
|
+
// Generate message_id client-side and track asynchronously (fire-and-forget)
|
|
607
|
+
const producerTag = ((_a = options.producer) === null || _a === void 0 ? void 0 : _a.tag) || `producer-${brokerTag}-${topicTag}`;
|
|
608
|
+
const messageId = (0, processor_utils_1.generateObjectId)();
|
|
609
|
+
// Encrypt message on SDK side - NEVER send private_key over HTTP
|
|
610
|
+
const messageEncrypted = (0, processor_utils_1.encrypt)(JSON.stringify(resolvedMessage), this.privateKey);
|
|
611
|
+
// Track the message in the database (fire-and-forget - no await)
|
|
612
|
+
this.processorApiService.trackBrokerMessage({
|
|
613
|
+
workspace_id: this.config.workspace_id,
|
|
614
|
+
product_id: this.productId,
|
|
615
|
+
product_tag: options.product,
|
|
616
|
+
env: options.env,
|
|
617
|
+
broker_tag: brokerTag,
|
|
618
|
+
topic_tag: topicTag,
|
|
619
|
+
event: options.event,
|
|
620
|
+
producer_tag: producerTag,
|
|
621
|
+
message_encrypted: messageEncrypted,
|
|
622
|
+
process_id,
|
|
623
|
+
session_tag: (_b = options.session) === null || _b === void 0 ? void 0 : _b.tag,
|
|
624
|
+
metadata: { cache: options.cache },
|
|
625
|
+
message_id: messageId,
|
|
626
|
+
}, this.getUserAccess()).catch(() => {
|
|
627
|
+
// Silently ignore tracking errors - non-blocking
|
|
628
|
+
});
|
|
629
|
+
// Add the message_id to the message so consumers can track it
|
|
630
|
+
const messageWithTracking = Object.assign(Object.assign({}, resolvedMessage), { __ductape_message_id: messageId });
|
|
298
631
|
// Get broker service and publish
|
|
299
632
|
const brokerService = await this.getBrokerService(brokerEnv.type, brokerEnv.config);
|
|
300
|
-
await brokerService.publish(topicUrl,
|
|
633
|
+
await brokerService.publish(topicUrl, messageWithTracking);
|
|
301
634
|
const result = {
|
|
302
635
|
success: true,
|
|
303
636
|
process_id,
|
|
304
637
|
};
|
|
305
|
-
// Store in cache for idempotency
|
|
638
|
+
// Store in cache for idempotency (fire-and-forget)
|
|
306
639
|
if (cache && this.cacheManager && this.privateKey) {
|
|
307
640
|
const cacheConfig = await this.validateCache(cache);
|
|
308
|
-
|
|
641
|
+
this.cacheManager.store({
|
|
309
642
|
cache_tag: cache,
|
|
310
643
|
product_tag: options.product,
|
|
311
644
|
component_tag: `${brokerTag}:${topicTag}`,
|
|
@@ -317,18 +650,26 @@ class BrokersService {
|
|
|
317
650
|
}, result);
|
|
318
651
|
}
|
|
319
652
|
const end = Date.now();
|
|
320
|
-
|
|
321
|
-
|
|
653
|
+
const successLogKey = `${options.product}:${options.env}:${options.event}`;
|
|
654
|
+
const now = Date.now();
|
|
655
|
+
const isDuplicateSuccessLog = this.lastPublishSuccessLogKey === successLogKey &&
|
|
656
|
+
now - this.lastPublishSuccessLogTime < BrokersService.PUBLISH_SUCCESS_LOG_DEDUPE_MS;
|
|
657
|
+
if (!isDuplicateSuccessLog) {
|
|
658
|
+
this.logService.add(Object.assign(Object.assign({}, baseLogs), { start,
|
|
659
|
+
end, message: 'Publish to broker - success', successful_execution: true, status: types_2.LogEventStatus.SUCCESS }));
|
|
660
|
+
this.lastPublishSuccessLogKey = successLogKey;
|
|
661
|
+
this.lastPublishSuccessLogTime = now;
|
|
662
|
+
}
|
|
322
663
|
this.logService.publish();
|
|
323
664
|
return result;
|
|
324
665
|
}
|
|
325
666
|
catch (error) {
|
|
326
667
|
const end = Date.now();
|
|
327
668
|
this.initializeLogService();
|
|
328
|
-
(
|
|
669
|
+
(_c = this.logService) === null || _c === void 0 ? void 0 : _c.add(Object.assign({ product_tag: options.product, workspace_id: this.config.workspace_id, env: options.env, process_id,
|
|
329
670
|
start,
|
|
330
|
-
end, type: types_2.LogEventTypes.
|
|
331
|
-
await ((
|
|
671
|
+
end, type: types_2.LogEventTypes.PRODUCER, parent_tag: brokerTag, child_tag: topicTag, message: 'Publish to broker - failed', failed_execution: true, data: { event: options.event, error: String(error) }, status: types_2.LogEventStatus.FAIL }, sessionLogFields));
|
|
672
|
+
await ((_d = this.logService) === null || _d === void 0 ? void 0 : _d.publish());
|
|
332
673
|
if (error instanceof BrokerError) {
|
|
333
674
|
throw error;
|
|
334
675
|
}
|
|
@@ -339,11 +680,12 @@ class BrokersService {
|
|
|
339
680
|
* Subscribe to a broker topic
|
|
340
681
|
*/
|
|
341
682
|
async subscribe(options) {
|
|
342
|
-
var _a, _b;
|
|
683
|
+
var _a, _b, _c;
|
|
343
684
|
const process_id = (0, processor_utils_1.generateObjectId)();
|
|
344
685
|
const start = Date.now();
|
|
345
686
|
try {
|
|
346
|
-
|
|
687
|
+
// For subscribe, we don't auto-register topics - they should already exist
|
|
688
|
+
const { broker, topic, brokerEnv, topicUrl } = await this.initializeBroker(options.product, options.env, options.event, undefined);
|
|
347
689
|
const { brokerTag, topicTag } = (0, broker_util_1.parseEventString)(options.event);
|
|
348
690
|
// Auto-register consumer if not exists
|
|
349
691
|
await this.ensureConsumerRegistered(brokerTag, topicTag, options.consumer);
|
|
@@ -354,15 +696,80 @@ class BrokersService {
|
|
|
354
696
|
workspace_id: this.config.workspace_id,
|
|
355
697
|
env: options.env,
|
|
356
698
|
process_id,
|
|
357
|
-
type: types_2.LogEventTypes.
|
|
699
|
+
type: types_2.LogEventTypes.CONSUMER,
|
|
358
700
|
parent_tag: brokerTag,
|
|
359
701
|
child_tag: topicTag,
|
|
360
702
|
data: { event: options.event },
|
|
361
703
|
};
|
|
362
704
|
this.logService.add(Object.assign(Object.assign({}, baseLogs), { start, message: 'Subscribe to broker - initiated', status: types_2.LogEventStatus.PROCESSING }));
|
|
363
|
-
// Get broker service and subscribe
|
|
705
|
+
// Get broker service and subscribe with message tracking wrapper
|
|
364
706
|
const brokerService = await this.getBrokerService(brokerEnv.type, brokerEnv.config);
|
|
365
|
-
|
|
707
|
+
const consumerTag = ((_a = options.consumer) === null || _a === void 0 ? void 0 : _a.tag) || `consumer-${brokerTag}-${topicTag}`;
|
|
708
|
+
// Pre-cache user access for callback use (avoid repeated calls)
|
|
709
|
+
const userAccess = this.getUserAccess();
|
|
710
|
+
// Wrap the callback to track message consumption (optimized for low latency)
|
|
711
|
+
const wrappedCallback = async (message) => {
|
|
712
|
+
const messageReceiveTime = Date.now();
|
|
713
|
+
const consumeProcessId = (0, processor_utils_1.generateObjectId)();
|
|
714
|
+
// Extract message_id from the message
|
|
715
|
+
const msgWithId = message;
|
|
716
|
+
const messageId = msgWithId.__ductape_message_id;
|
|
717
|
+
// Execute user callback FIRST - this is the critical path
|
|
718
|
+
let callbackSuccess = true;
|
|
719
|
+
let callbackError;
|
|
720
|
+
try {
|
|
721
|
+
await options.callback(message);
|
|
722
|
+
}
|
|
723
|
+
catch (err) {
|
|
724
|
+
callbackSuccess = false;
|
|
725
|
+
callbackError = err;
|
|
726
|
+
}
|
|
727
|
+
const callbackEnd = Date.now();
|
|
728
|
+
// Fire-and-forget: All tracking/logging happens async after callback completes
|
|
729
|
+
// This ensures user callback latency is not affected by our tracking overhead
|
|
730
|
+
setImmediate(() => {
|
|
731
|
+
var _a, _b;
|
|
732
|
+
const consumeBaseLogs = {
|
|
733
|
+
product_tag: options.product,
|
|
734
|
+
product_id: this.productId,
|
|
735
|
+
workspace_id: this.config.workspace_id,
|
|
736
|
+
env: options.env,
|
|
737
|
+
process_id: consumeProcessId,
|
|
738
|
+
type: types_2.LogEventTypes.CONSUMER,
|
|
739
|
+
parent_tag: brokerTag,
|
|
740
|
+
child_tag: topicTag,
|
|
741
|
+
data: { event: options.event, message_id: messageId, consumer_tag: consumerTag },
|
|
742
|
+
};
|
|
743
|
+
if (messageId) {
|
|
744
|
+
// Calculate actual callback processing time
|
|
745
|
+
const processingTime = callbackEnd - messageReceiveTime;
|
|
746
|
+
// Register consumer first, then update status (sequential to avoid race condition)
|
|
747
|
+
this.processorApiService.registerBrokerConsumer({
|
|
748
|
+
message_id: messageId,
|
|
749
|
+
consumer_tag: consumerTag,
|
|
750
|
+
}, userAccess).then(() => {
|
|
751
|
+
// Now update the status with processing time
|
|
752
|
+
return this.processorApiService.updateBrokerConsumerStatus({
|
|
753
|
+
message_id: messageId,
|
|
754
|
+
consumer_tag: consumerTag,
|
|
755
|
+
status: callbackSuccess ? 'success' : 'failed',
|
|
756
|
+
error: callbackError ? String(callbackError) : undefined,
|
|
757
|
+
processing_time: processingTime,
|
|
758
|
+
}, userAccess);
|
|
759
|
+
}).catch(() => { }); // Silently ignore tracking errors
|
|
760
|
+
}
|
|
761
|
+
// Log consumption (fire-and-forget)
|
|
762
|
+
(_a = this.logService) === null || _a === void 0 ? void 0 : _a.add(Object.assign(Object.assign(Object.assign({}, consumeBaseLogs), { start: messageReceiveTime, end: callbackEnd, message: messageId
|
|
763
|
+
? (callbackSuccess ? 'Message consumed - success' : 'Message consumed - failed')
|
|
764
|
+
: 'Message consumed - untracked (no message_id)', successful_execution: callbackSuccess, failed_execution: !callbackSuccess, status: callbackSuccess ? types_2.LogEventStatus.SUCCESS : types_2.LogEventStatus.FAIL }), (callbackError && { data: Object.assign(Object.assign({}, consumeBaseLogs.data), { error: String(callbackError) }) })));
|
|
765
|
+
(_b = this.logService) === null || _b === void 0 ? void 0 : _b.publish();
|
|
766
|
+
});
|
|
767
|
+
// Re-throw callback error if any (so RabbitMQ can handle retry/nack)
|
|
768
|
+
if (callbackError) {
|
|
769
|
+
throw callbackError;
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
await brokerService.subscribe(topicUrl, wrappedCallback);
|
|
366
773
|
const end = Date.now();
|
|
367
774
|
this.logService.add(Object.assign(Object.assign({}, baseLogs), { start,
|
|
368
775
|
end, message: 'Subscribe to broker - success', successful_execution: true, status: types_2.LogEventStatus.SUCCESS }));
|
|
@@ -375,20 +782,20 @@ class BrokersService {
|
|
|
375
782
|
catch (error) {
|
|
376
783
|
const end = Date.now();
|
|
377
784
|
this.initializeLogService();
|
|
378
|
-
(
|
|
785
|
+
(_b = this.logService) === null || _b === void 0 ? void 0 : _b.add({
|
|
379
786
|
product_tag: options.product,
|
|
380
787
|
workspace_id: this.config.workspace_id,
|
|
381
788
|
env: options.env,
|
|
382
789
|
process_id,
|
|
383
790
|
start,
|
|
384
791
|
end,
|
|
385
|
-
type: types_2.LogEventTypes.
|
|
792
|
+
type: types_2.LogEventTypes.CONSUMER,
|
|
386
793
|
message: 'Subscribe to broker - failed',
|
|
387
794
|
failed_execution: true,
|
|
388
795
|
data: { event: options.event, error: String(error) },
|
|
389
796
|
status: types_2.LogEventStatus.FAIL,
|
|
390
797
|
});
|
|
391
|
-
await ((
|
|
798
|
+
await ((_c = this.logService) === null || _c === void 0 ? void 0 : _c.publish());
|
|
392
799
|
if (error instanceof BrokerError) {
|
|
393
800
|
throw error;
|
|
394
801
|
}
|
|
@@ -793,5 +1200,6 @@ class BrokersService {
|
|
|
793
1200
|
}
|
|
794
1201
|
}
|
|
795
1202
|
exports.BrokersService = BrokersService;
|
|
1203
|
+
BrokersService.PUBLISH_SUCCESS_LOG_DEDUPE_MS = 2000;
|
|
796
1204
|
exports.default = BrokersService;
|
|
797
1205
|
//# sourceMappingURL=brokers.service.js.map
|