@pager/minion-army 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.js CHANGED
@@ -1,7 +1,7 @@
1
1
  module.exports = {
2
2
  extends: '@hapi/eslint-config-hapi',
3
3
  parserOptions: {
4
- ecmaVersion: 12
4
+ ecmaVersion: 9
5
5
  },
6
6
  rules: {
7
7
  'no-console': 2
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [2.2.1](https://github.com/pagerinc/minion-army/compare/v2.2.0...v2.2.1) (2024-03-20)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **ODIN-13:** patch version bump ([#459](https://github.com/pagerinc/minion-army/issues/459)) ([70a1bc2](https://github.com/pagerinc/minion-army/commit/70a1bc26df8bd77a4d7c675cfcb9a7bf0b171f91))
7
+
8
+ # [2.2.0](https://github.com/pagerinc/minion-army/compare/v2.1.0...v2.2.0) (2024-03-20)
9
+
10
+
11
+ ### Features
12
+
13
+ * **ODIN-13:** set NR transaction name based on worker name ([#458](https://github.com/pagerinc/minion-army/issues/458)) ([b0bb358](https://github.com/pagerinc/minion-army/commit/b0bb3583bcd9adfeb82653ce62e95a506d922a04))
14
+
1
15
  # [2.1.0](https://github.com/pagerinc/minion-army/compare/v2.0.0...v2.1.0) (2023-05-08)
2
16
 
3
17
 
package/cloudbuild.yaml CHANGED
@@ -33,7 +33,8 @@ tags:
33
33
  - 'npm'
34
34
  - 'nodejs'
35
35
 
36
- secrets:
37
- - kmsKeyName: projects/production-197117/locations/global/keyRings/gcb/cryptoKeys/main
38
- secretEnv:
39
- NPM_TOKEN: 'CiUA/4lqmXwRPPaGHe+X7TS7mwqARNCw5QFq7yfq7ESHaJrf+tzeElEADvOwrLQvnxCLG2wy+H2vD+DWHMosEgIfzpKNBJAVHX1u4FSwIF5utaN6tMIrLuZB18HnK2SKpsXTPvB/+0Eoz1acnj6WO+slz+GUGUnxefU='
36
+ availableSecrets:
37
+ secretManager:
38
+ - versionName: projects/145393225073/secrets/npm-token-publish/versions/latest
39
+ env: NPM_TOKEN
40
+
package/lib/index.js CHANGED
@@ -4,10 +4,10 @@ const Minion = require('@pager/minion');
4
4
  const { EventEmitter } = require('events');
5
5
  const Jackrabbit = require('@pager/jackrabbit');
6
6
  const Joi = require('joi');
7
+ const NewRelic = require('newrelic');
7
8
  const Schema = require('./schema');
8
- const { createLoggerContext } = require('./loggingUtils');
9
9
 
10
- const validatorFactory = (handler, schema) => (payload, ...rest) => { // eslint-disable-line
10
+ const validatorFactory = (handler, schema) => (payload, metadata) => { // eslint-disable-line
11
11
 
12
12
  const { error, value } = schema.validate(payload, { stripUnknown: true });
13
13
 
@@ -15,7 +15,7 @@ const validatorFactory = (handler, schema) => (payload, ...rest) => { // eslint-
15
15
  throw error;
16
16
  }
17
17
 
18
- return handler(value, ...rest);
18
+ return handler(value, metadata);
19
19
  };
20
20
 
21
21
  const createExchange = (connection, workerConfig, exchangeMap) => {
@@ -84,15 +84,9 @@ module.exports = (_manifest) => {
84
84
  ...manifest.defaults,
85
85
  ...worker.config
86
86
  };
87
-
88
- let handlerWithLoggerContext = handlerWithValidation;
89
- if (manifest.logger) {
90
- handlerWithLoggerContext = createLoggerContext(manifest.logger, worker.config.name, handlerWithValidation);
91
- }
92
-
93
87
  const exchange = createExchange(manifest.connection, workerConfig, exchangeMap);
94
88
 
95
- const minion = Minion(handlerWithLoggerContext, { ...workerConfig, exchange });
89
+ const minion = Minion(handlerWithValidation, { ...workerConfig, exchange });
96
90
 
97
91
  minion.on('ready', checkReady);
98
92
  minion.on('message', (m, meta) => eventEmitter.emit('message', worker.config.name, m, meta));
@@ -113,6 +107,8 @@ module.exports = (_manifest) => {
113
107
 
114
108
  const start = () => Object.values(minions).forEach((minion) => minion.start());
115
109
 
110
+ eventEmitter.on('message', (name, _message, _meta) => NewRelic.setTransactionName(name));
111
+
116
112
  return Object.assign(eventEmitter, {
117
113
  exchangeMap,
118
114
  minions,
package/lib/schema.js CHANGED
@@ -36,8 +36,5 @@ module.exports = Joi.object({
36
36
  rabbitUrl: Joi.string()
37
37
  }),
38
38
  defaults: config,
39
- workers: Joi.array().items(worker),
40
- logger: Joi.object({
41
- child: Joi.func().required()
42
- }).unknown(true)
39
+ workers: Joi.array().items(worker)
43
40
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pager/minion-army",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "Microservice Framework for RabbitMQ Workers",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -25,11 +25,9 @@
25
25
  "homepage": "https://github.com/pagerinc/minion#readme",
26
26
  "dependencies": {
27
27
  "@pager/jackrabbit": "5.x",
28
- "@pager/minion": "3.x",
29
- "lodash": "^4.17.21"
28
+ "@pager/minion": "3.x"
30
29
  },
31
30
  "devDependencies": {
32
- "@faker-js/faker": "^8.0.1",
33
31
  "@hapi/eslint-config-hapi": "13.x",
34
32
  "@hapi/eslint-plugin-hapi": "4.x",
35
33
  "@pager/semantic-release-config": "2.x",
@@ -37,11 +35,11 @@
37
35
  "eslint": "7.x",
38
36
  "joi": "^17.2.1",
39
37
  "nyc": "15.x",
40
- "semantic-release": "21.x",
41
- "sinon": "^15.0.4"
38
+ "semantic-release": "21.x"
42
39
  },
43
40
  "peerDependencies": {
44
- "joi": "^17.2.0"
41
+ "joi": "^17.2.0",
42
+ "newrelic": "11.x"
45
43
  },
46
44
  "renovate": {
47
45
  "extends": [
package/test/index.js CHANGED
@@ -4,41 +4,8 @@ const { EventEmitter } = require('events');
4
4
  const Test = require('ava');
5
5
  const Joi = require('joi');
6
6
 
7
- const Sinon = require('sinon');
8
- const { faker } = require('@faker-js/faker');
9
-
10
7
  const Army = require('../lib/index');
11
8
 
12
- const sandbox = Sinon.createSandbox();
13
-
14
-
15
- Test.beforeEach((t) => {
16
-
17
- t.context.logger = {
18
- child: sandbox.stub(),
19
- info: sandbox.stub()
20
- };
21
- t.context.rabbit = {
22
- topic: () => ({
23
- publish: sandbox.spy()
24
- }),
25
- direct: () => ({
26
- publish: sandbox.spy()
27
- })
28
- };
29
- t.context.metadata = {
30
- properties: {
31
- headers: {
32
- eventId: faker.string.uuid()
33
- }
34
- },
35
- fields: {
36
- routingKey: faker.string.uuid()
37
- }
38
- };
39
-
40
- });
41
-
42
9
  Test('Creates army from manifest and workers work', async (t) => {
43
10
 
44
11
  const manifest = {
@@ -432,49 +399,3 @@ Test('Army uses worker exchange overrides', (t) => {
432
399
  const army = Army(manifest);
433
400
  t.deepEqual(Object.keys(army.exchangeMap), ['direct.events.something.happened', 'topic.my-other-exchange']);
434
401
  });
435
-
436
-
437
- Test('Army starts with logger context', async (t) => {
438
-
439
- const { context: { rabbit, logger, metadata } } = t;
440
-
441
- const minionWorkerName = faker.word.sample();
442
-
443
- const handler = sandbox.spy();
444
-
445
- const manifest = {
446
- connection: {
447
- rabbit
448
- },
449
- defaults: {
450
- exchangeName: faker.word.sample()
451
- },
452
- workers: [
453
- {
454
- handler,
455
- config: {
456
- name: minionWorkerName,
457
- key: faker.word.sample()
458
- }
459
- }
460
- ],
461
- logger
462
- };
463
-
464
- const army = Army(manifest);
465
- t.truthy(army);
466
-
467
- const event = {
468
- data: faker.word.sample()
469
- };
470
-
471
- const childLogger = sandbox.spy();
472
-
473
- t.context.logger.child.returns(childLogger);
474
-
475
- await army.minions[minionWorkerName].handle(event, metadata);
476
-
477
- Sinon.assert.calledOnceWithExactly(logger.child, { eventId: metadata.properties.headers.eventId, routingKey: metadata.fields.routingKey, minionWorkerName });
478
-
479
- Sinon.assert.calledOnceWithExactly(handler, event, metadata, { logger: childLogger });
480
- });
@@ -1,112 +0,0 @@
1
- 'use strict';
2
-
3
- const { v4: Uuid } = require('uuid');
4
-
5
- const Lodash = require('lodash');
6
-
7
- /**
8
- * This is a wrapper around the handler that creates a pino style logger and
9
- * adds it to a context object as a third argument of the handler
10
- *
11
- * @param {*} logger a Pino style logger
12
- * @param {*} minionWorkerName the name of the minion army worker
13
- * @param {*} handler the handler to be wrapped
14
- * @returns
15
- */
16
- exports.createLoggerContext = (logger, minionWorkerName, handler) => {
17
-
18
- return (value, metadata, context = {}) => {
19
-
20
- let eventId;
21
- try {
22
- eventId = metadata?.properties?.headers?.eventId || Uuid();
23
- const routingKey = metadata?.fields?.routingKey;
24
-
25
- context.logger = (context.logger || logger).child({ eventId, routingKey, minionWorkerName });
26
- }
27
- catch (error) {
28
- // eslint-disable-next-line no-console
29
- console.log('There was an error while creating a child logger in %s for eventId(%s): %o', minionWorkerName, eventId, error);
30
- }
31
-
32
- return handler(value, metadata, context);
33
- };
34
- };
35
-
36
- /**
37
- * This utility crteates a wrapper that adds a field from the event into the logger.
38
- *
39
- * Usage:
40
- *
41
- * const Logger = require('@pager/logger');
42
- * const Army = require('@pager/minion-army');
43
- *
44
- * const injectEncounterIdFromEvent = injectFieldFromEventAs(Logger, 'encounterId', 'triageId');
45
- *
46
- * const handler = (message, metadata, context) {
47
- * context.logger.info('handling message');
48
- * }
49
- *
50
- * const army = Army({
51
- * workers: [
52
- * {
53
- * handler: injectEncounterIdFromEvent(handler),
54
- * config: {
55
- * name: `events.foo.encounter.state.updated`,
56
- * key: '#.encounter.state.updated'
57
- * },
58
- * validate: Schemas.states
59
- * },
60
- * });
61
- *
62
- * @param {*} logger a Pino style logger
63
- * @param {*} loggedFieldName what is the name of the field in the log line
64
- * @param {*} eventFieldName what is the name of the field in the event payload
65
- * @returns
66
- */
67
- exports.injectFieldFromEventAs = (logger, loggedFieldName, eventFieldName) => (handler) => { // eslint-disable-line @hapi/hapi/scope-start, @hapi/hapi/no-arrowception
68
-
69
- return (value, metadata, context = {}) => {
70
-
71
- context.logger = (context.logger || logger).child({ [loggedFieldName]: value[eventFieldName] });
72
-
73
- return handler(value, metadata, context);
74
- };
75
- };
76
-
77
- /**
78
- * This utility function sets up default event handlers that log
79
- *
80
- * Usage:
81
- *
82
- * const Logger = require('@pager/logger');
83
- * const Army = require('@pager/minion-army');
84
- *
85
- * const army = Army({ ... });
86
- * addDefaultLoggingEventHandlers(army, 'UpdatedUserArmy', Logger);
87
- *
88
- * @param {*} army: the Army instance
89
- * @param {*} armyName: a unique identifier for this instance of Army
90
- * @param {*} parentLogger: a Pino style logger
91
- */
92
- exports.addDefaultLoggingEventHandlers = (parentLogger, army, armyName) => {
93
-
94
- const logger = parentLogger.child({ armyName });
95
-
96
- army.on('error', (error) => {
97
-
98
- logger.error({ error }, 'Handler error in %s', armyName);
99
- });
100
-
101
- army.on('message', (queue, event, metadata) => {
102
-
103
- const pickedMetadata = Lodash.pick(metadata, ['properties', 'fields']);
104
-
105
- logger.info({ queue, event, metadata: pickedMetadata }, 'Got event in %s', armyName);
106
- });
107
-
108
- army.on('ready', (queue) => {
109
-
110
- logger.info({ queue }, 'Ready to consume on %s by %s', queue.name, armyName);
111
- });
112
- };
@@ -1,178 +0,0 @@
1
- 'use strict';
2
-
3
- const Test = require('ava');
4
-
5
- const Sinon = require('sinon');
6
- const { faker } = require('@faker-js/faker');
7
-
8
- const Army = require('../lib/index');
9
- const { createLoggerContext, injectFieldFromEventAs, addDefaultLoggingEventHandlers } = require('../lib/loggingUtils');
10
-
11
- const sandbox = Sinon.createSandbox();
12
-
13
-
14
- Test.beforeEach((t) => {
15
-
16
- t.context.logger = {
17
- child: sandbox.stub()
18
- };
19
- t.context.metadata = {
20
- properties: {
21
- headers: {
22
- eventId: faker.string.uuid()
23
- }
24
- },
25
- fields: {
26
- routingKey: faker.string.uuid()
27
- }
28
- };
29
- t.context.event = sandbox.spy();
30
- t.context.minionWorkerName = faker.word.sample();
31
- t.context.handler = sandbox.spy();
32
- t.context.rabbit = {
33
- topic: () => ({
34
- publish: sandbox.spy()
35
- })
36
- };
37
- });
38
-
39
- Test.afterEach((t) => {
40
-
41
- sandbox.restore();
42
- });
43
-
44
- Test('createLoggerContext wraps a handler', (t) => {
45
-
46
- const { context: { logger, event, metadata, minionWorkerName, handler } } = t;
47
-
48
- const wrappedHandler = createLoggerContext(logger, minionWorkerName, handler);
49
-
50
- const childLogger = sandbox.spy();
51
-
52
- t.context.logger.child.returns(childLogger);
53
-
54
- wrappedHandler(event, metadata);
55
-
56
- Sinon.assert.calledOnceWithExactly(logger.child, { eventId: metadata.properties.headers.eventId, routingKey: metadata.fields.routingKey, minionWorkerName });
57
-
58
- Sinon.assert.calledOnceWithExactly(handler, event, metadata, { logger: childLogger });
59
-
60
- t.pass();
61
- });
62
-
63
- Test('createLoggerContext does not fail if the logger fails', (t) => {
64
-
65
- const { context: { logger, event, metadata, minionWorkerName, handler } } = t;
66
-
67
- const wrappedHandler = createLoggerContext(logger, minionWorkerName, handler);
68
-
69
- t.context.logger.child.throws(new Error('failed to create logger'));
70
-
71
- wrappedHandler(event, metadata);
72
-
73
- Sinon.assert.calledOnceWithExactly(logger.child, { eventId: metadata.properties.headers.eventId, routingKey: metadata.fields.routingKey, minionWorkerName });
74
-
75
- Sinon.assert.calledOnceWithExactly(handler, event, metadata, {});
76
-
77
- t.pass();
78
- });
79
-
80
- Test('injectFieldFromEventAs adds field to the logger', (t) => {
81
-
82
- const { context: { logger, metadata, handler } } = t;
83
-
84
- const wrappedHandler = injectFieldFromEventAs(logger, 'encounterId', 'triageId')(handler);
85
-
86
- const childLogger = sandbox.spy();
87
-
88
- t.context.logger.child.returns(childLogger);
89
-
90
- const event = {
91
- triageId: faker.database.mongodbObjectId()
92
- };
93
-
94
- wrappedHandler(event, metadata);
95
-
96
- Sinon.assert.calledOnceWithExactly(logger.child, { encounterId: event.triageId });
97
-
98
- Sinon.assert.calledOnceWithExactly(handler, event, metadata, { logger: childLogger });
99
-
100
- t.pass();
101
- });
102
-
103
- Test('injectFieldFromEventAs does not add the field to the logger if it is missing', (t) => {
104
-
105
- const { context: { logger, metadata, handler } } = t;
106
-
107
- const wrappedHandler = injectFieldFromEventAs(logger, 'encounterId', 'triageId')(handler);
108
-
109
- const childLogger = sandbox.spy();
110
-
111
- t.context.logger.child.returns(childLogger);
112
-
113
- const event = {};
114
-
115
- wrappedHandler(event, metadata);
116
-
117
- Sinon.assert.calledOnceWithExactly(logger.child, { encounterId: undefined });
118
-
119
- Sinon.assert.calledOnceWithExactly(handler, event, metadata, { logger: childLogger });
120
-
121
- t.pass();
122
- });
123
-
124
-
125
- Test('addDefaultLoggingEventHandlers adds the handlers', (t) => {
126
-
127
- const { context: { logger, rabbit, metadata } } = t;
128
-
129
- const workerName = faker.word.sample();
130
- const queueName = faker.word.sample();
131
-
132
- const manifest = {
133
- connection: {
134
- rabbit
135
- },
136
- defaults: {
137
- exchangeName: faker.word.sample()
138
- },
139
- workers: [
140
- {
141
- handler: sandbox.spy(),
142
- config: {
143
- name: workerName,
144
- key: queueName
145
- }
146
- }
147
- ]
148
- };
149
-
150
- const army = Army(manifest);
151
-
152
- t.truthy(army);
153
-
154
- const childLogger = {
155
- info: sandbox.spy()
156
- };
157
-
158
- t.context.logger.child.returns(childLogger);
159
-
160
- const armyName = faker.word.sample();
161
-
162
- addDefaultLoggingEventHandlers(logger, army, armyName);
163
-
164
- Sinon.assert.calledOnceWithExactly(logger.child, { armyName });
165
-
166
- const event = {
167
- data: faker.word.sample()
168
- };
169
-
170
- army.minions[workerName].handle(event, metadata);
171
-
172
- const expectedMetadata = {
173
- properties: metadata.properties,
174
- fields: metadata.fields
175
- };
176
-
177
- Sinon.assert.calledOnceWithExactly(childLogger.info, { queue: workerName, event, metadata: expectedMetadata }, 'Got event in %s', armyName);
178
- });