@onlineapps/service-common 1.0.4 → 1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlineapps/service-common",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Common utilities for both infrastructure services and business services",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -32,6 +32,12 @@ const {
32
32
  getServiceConfig,
33
33
  getInfrastructureHealthConfig
34
34
  } = require('./runtime-config');
35
+ const {
36
+ publishToMonitoringResilient,
37
+ publishToMonitoringWorkflow,
38
+ publishToMonitoringServices,
39
+ isQueueUnavailableError
40
+ } = require('./monitoring-publish');
35
41
 
36
42
  module.exports = {
37
43
  // Infrastructure readiness utilities (used by both infrastructure and business services)
@@ -59,7 +65,13 @@ module.exports = {
59
65
  getInfrastructureHealthConfig,
60
66
 
61
67
  // Reporting utilities
62
- sendMonitoringFailFallbackEmail
68
+ sendMonitoringFailFallbackEmail,
69
+
70
+ // Resilient monitoring publish utilities
71
+ publishToMonitoringResilient,
72
+ publishToMonitoringWorkflow,
73
+ publishToMonitoringServices,
74
+ isQueueUnavailableError
63
75
  };
64
76
 
65
77
 
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Resilient monitoring publish helper
3
+ *
4
+ * Publishes to monitoring queues (monitoring.workflow, monitoring.services) with fail-safe behavior.
5
+ * If the queue doesn't exist or RabbitMQ is unavailable, logs the error and continues without failing.
6
+ *
7
+ * This ensures services can start and operate even if monitoring queues aren't ready yet.
8
+ * Monitoring queues are created when health:all is true, so this is a temporary state during startup.
9
+ */
10
+
11
+ /**
12
+ * Check if error indicates queue doesn't exist or RabbitMQ is unavailable
13
+ */
14
+ function isQueueUnavailableError(error) {
15
+ if (!error) return false;
16
+
17
+ const errorMessage = error.message || String(error);
18
+ const errorCode = error.code || '';
19
+
20
+ // RabbitMQ connection errors
21
+ if (errorCode === 'ECONNREFUSED' || errorCode === 'ENOTFOUND' || errorCode === 'ETIMEDOUT') {
22
+ return true;
23
+ }
24
+
25
+ // Queue doesn't exist errors (from RabbitMQ)
26
+ if (errorMessage.includes('NOT_FOUND') ||
27
+ errorMessage.includes('404') ||
28
+ errorMessage.includes('no queue') ||
29
+ errorMessage.includes('queue does not exist') ||
30
+ errorMessage.includes('Channel closed') ||
31
+ errorMessage.includes('Connection closed')) {
32
+ return true;
33
+ }
34
+
35
+ return false;
36
+ }
37
+
38
+ /**
39
+ * Resilient publish to monitoring queue
40
+ *
41
+ * @param {Object} mqClient - MQ client instance (must have publish method)
42
+ * @param {string} queueName - Queue name (e.g., 'monitoring.workflow', 'monitoring.services')
43
+ * @param {Object} message - Message to publish
44
+ * @param {Object} logger - Logger instance (optional, for logging)
45
+ * @param {Object} context - Additional context for logging (optional)
46
+ * @returns {Promise<boolean>} - true if published successfully, false otherwise
47
+ */
48
+ async function publishToMonitoringResilient(mqClient, queueName, message, logger = null, context = {}) {
49
+ if (!mqClient || typeof mqClient.publish !== 'function') {
50
+ if (logger) {
51
+ logger.warn('Monitoring publish skipped: mqClient not available', context);
52
+ }
53
+ return false;
54
+ }
55
+
56
+ try {
57
+ await mqClient.publish(queueName, message);
58
+
59
+ if (logger) {
60
+ logger.debug(`Published to ${queueName}`, {
61
+ ...context,
62
+ event_type: message.event_type,
63
+ workflow_id: message.workflow_id,
64
+ service_name: message.service_name
65
+ });
66
+ }
67
+
68
+ return true;
69
+ } catch (error) {
70
+ // Check if this is a queue unavailable error
71
+ if (isQueueUnavailableError(error)) {
72
+ // Queue doesn't exist yet or RabbitMQ is unavailable - log but don't fail
73
+ if (logger) {
74
+ logger.warn(`Monitoring queue ${queueName} not available (queue may not exist yet or RabbitMQ unavailable)`, {
75
+ ...context,
76
+ error: error.message,
77
+ event_type: message.event_type,
78
+ workflow_id: message.workflow_id,
79
+ service_name: message.service_name
80
+ });
81
+ }
82
+ return false;
83
+ }
84
+
85
+ // Other errors - log as warning but don't fail
86
+ if (logger) {
87
+ logger.warn(`Failed to publish to monitoring queue ${queueName}`, {
88
+ ...context,
89
+ error: error.message,
90
+ errorCode: error.code,
91
+ event_type: message.event_type,
92
+ workflow_id: message.workflow_id,
93
+ service_name: message.service_name
94
+ });
95
+ }
96
+
97
+ return false;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Resilient publish to monitoring.workflow queue
103
+ *
104
+ * @param {Object} mqClient - MQ client instance
105
+ * @param {Object} message - Message with event_type, workflow_id, etc.
106
+ * @param {Object} logger - Logger instance (optional)
107
+ * @param {Object} context - Additional context for logging (optional)
108
+ * @returns {Promise<boolean>}
109
+ */
110
+ async function publishToMonitoringWorkflow(mqClient, message, logger = null, context = {}) {
111
+ return publishToMonitoringResilient(mqClient, 'monitoring.workflow', message, logger, context);
112
+ }
113
+
114
+ /**
115
+ * Resilient publish to monitoring.services queue
116
+ *
117
+ * @param {Object} mqClient - MQ client instance
118
+ * @param {Object} message - Message with event_type, service_name, etc.
119
+ * @param {Object} logger - Logger instance (optional)
120
+ * @param {Object} context - Additional context for logging (optional)
121
+ * @returns {Promise<boolean>}
122
+ */
123
+ async function publishToMonitoringServices(mqClient, message, logger = null, context = {}) {
124
+ return publishToMonitoringResilient(mqClient, 'monitoring.services', message, logger, context);
125
+ }
126
+
127
+ module.exports = {
128
+ publishToMonitoringResilient,
129
+ publishToMonitoringWorkflow,
130
+ publishToMonitoringServices,
131
+ isQueueUnavailableError
132
+ };
133
+