screwdriver-queue-service 2.0.18 → 2.0.22
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/config/custom-environment-variables.yaml +3 -1
- package/config/default.yaml +3 -1
- package/config/kafka.js +19 -0
- package/lib/queue.js +0 -14
- package/package.json +9 -9
- package/plugins/helper.js +30 -0
- package/plugins/queue/scheduler.js +11 -5
- package/plugins/queue/utils/freezeWindows.js +5 -6
- package/plugins/worker/lib/jobs.js +42 -17
package/config/default.yaml
CHANGED
package/config/kafka.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const config = require('config');
|
|
4
|
+
const kafkaConfig = config.get('kafka');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* get config
|
|
8
|
+
* @returns Object containing kafka config values
|
|
9
|
+
*/
|
|
10
|
+
function get() {
|
|
11
|
+
return {
|
|
12
|
+
kafkaEnabled: kafkaConfig.enabled === 'true',
|
|
13
|
+
useShortRegionName: kafkaConfig.shortRegion === 'true'
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
get
|
|
19
|
+
};
|
package/lib/queue.js
CHANGED
|
@@ -58,20 +58,6 @@ module.exports = class ExecutorQueue {
|
|
|
58
58
|
this.redis[funcName](...args),
|
|
59
59
|
breakerOptions
|
|
60
60
|
);
|
|
61
|
-
this.requestRetryStrategy = response => {
|
|
62
|
-
if (Math.floor(response.statusCode / 100) !== 2) {
|
|
63
|
-
throw new Error('Retry limit reached');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return response;
|
|
67
|
-
};
|
|
68
|
-
this.requestRetryStrategyPostEvent = response => {
|
|
69
|
-
if (Math.floor(response.statusCode / 100) !== 2 && response.statusCode !== 404) {
|
|
70
|
-
throw new Error('Retry limit reached');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return response;
|
|
74
|
-
};
|
|
75
61
|
this.fuseBox = new FuseBox();
|
|
76
62
|
this.fuseBox.addFuse(this.queueBreaker);
|
|
77
63
|
this.fuseBox.addFuse(this.redisBreaker);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "screwdriver-queue-service",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.22",
|
|
4
4
|
"description": "Screwdriver Queue Service API",
|
|
5
5
|
"main": "app.js",
|
|
6
6
|
"directories": {
|
|
@@ -11,28 +11,28 @@
|
|
|
11
11
|
"@hapi/good": "^9.0.1",
|
|
12
12
|
"@hapi/good-console": "^9.0.1",
|
|
13
13
|
"@hapi/good-squeeze": "^6.0.0",
|
|
14
|
-
"@hapi/hapi": "^20.1
|
|
14
|
+
"@hapi/hapi": "^20.2.1",
|
|
15
15
|
"@hapi/hoek": "^9.1.1",
|
|
16
|
-
"amqp-connection-manager": "^3.
|
|
16
|
+
"amqp-connection-manager": "^3.8.1",
|
|
17
17
|
"amqplib": "^0.8.0",
|
|
18
18
|
"blipp": "^4.0.2",
|
|
19
19
|
"circuit-fuses": "^4.0.5",
|
|
20
20
|
"config": "^1.31.0",
|
|
21
|
-
"cron-parser": "^2.
|
|
21
|
+
"cron-parser": "^4.2.1",
|
|
22
22
|
"hapi-auth-jwt2": "^10.2.0",
|
|
23
23
|
"ioredis": "^3.2.2",
|
|
24
|
-
"joi": "^17.
|
|
24
|
+
"joi": "^17.5.0",
|
|
25
25
|
"js-yaml": "^3.14.1",
|
|
26
26
|
"jsonwebtoken": "^8.5.1",
|
|
27
27
|
"laabr": "^6.1.3",
|
|
28
28
|
"node-resque": "^5.5.3",
|
|
29
29
|
"npm-auto-version": "^1.0.0",
|
|
30
30
|
"redlock": "^4.2.0",
|
|
31
|
-
"screwdriver-aws-producer-service": "^1.
|
|
32
|
-
"screwdriver-data-schema": "^21.
|
|
31
|
+
"screwdriver-aws-producer-service": "^1.3.0",
|
|
32
|
+
"screwdriver-data-schema": "^21.16.0",
|
|
33
33
|
"screwdriver-executor-docker": "^5.0.2",
|
|
34
34
|
"screwdriver-executor-jenkins": "^5.0.1",
|
|
35
|
-
"screwdriver-executor-k8s": "^14.
|
|
35
|
+
"screwdriver-executor-k8s": "^14.16.0",
|
|
36
36
|
"screwdriver-executor-k8s-vm": "^4.3.2",
|
|
37
37
|
"screwdriver-executor-router": "^2.1.2",
|
|
38
38
|
"screwdriver-logger": "^1.0.2",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"mockery": "^2.1.0",
|
|
54
54
|
"nyc": "^15.1.0",
|
|
55
55
|
"sinon": "^9.2.4",
|
|
56
|
-
"snyk": "^1.
|
|
56
|
+
"snyk": "^1.814.0",
|
|
57
57
|
"util": "^0.12.2"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
package/plugins/helper.js
CHANGED
|
@@ -7,6 +7,34 @@ const { queuePrefix } = require('../config/redis');
|
|
|
7
7
|
const RETRY_LIMIT = 3;
|
|
8
8
|
const RETRY_DELAY = 5;
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Callback function to retry when HTTP status code is not 2xx
|
|
12
|
+
* @param {Object} response
|
|
13
|
+
* @param {Function} retryWithMergedOptions
|
|
14
|
+
* @return {Object} response
|
|
15
|
+
*/
|
|
16
|
+
function requestRetryStrategy(response) {
|
|
17
|
+
if (Math.floor(response.statusCode / 100) !== 2) {
|
|
18
|
+
throw new Error('Retry limit reached');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return response;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Callback function to retry when HTTP status code is not 2xx and 404
|
|
26
|
+
* @param {Object} response
|
|
27
|
+
* @param {Function} retryWithMergedOptions
|
|
28
|
+
* @return {Object} response
|
|
29
|
+
*/
|
|
30
|
+
function requestRetryStrategyPostEvent(response) {
|
|
31
|
+
if (Math.floor(response.statusCode / 100) !== 2 && response.statusCode !== 404) {
|
|
32
|
+
throw new Error('Retry limit reached');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return response;
|
|
36
|
+
}
|
|
37
|
+
|
|
10
38
|
/**
|
|
11
39
|
*
|
|
12
40
|
* @param {String} method
|
|
@@ -241,6 +269,8 @@ async function processHooks(apiUri, token, webhookConfig, retryStrategyFn) {
|
|
|
241
269
|
}
|
|
242
270
|
|
|
243
271
|
module.exports = {
|
|
272
|
+
requestRetryStrategy,
|
|
273
|
+
requestRetryStrategyPostEvent,
|
|
244
274
|
updateBuildStatus,
|
|
245
275
|
updateStepStop,
|
|
246
276
|
getCurrentStep,
|
|
@@ -38,7 +38,7 @@ async function postBuildEvent(executor, eventConfig) {
|
|
|
38
38
|
scope: ['user']
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
const admin = await helper.getPipelineAdmin(token, apiUri, pipelineId,
|
|
41
|
+
const admin = await helper.getPipelineAdmin(token, apiUri, pipelineId, helper.requestRetryStrategy);
|
|
42
42
|
|
|
43
43
|
if (admin) {
|
|
44
44
|
logger.info(
|
|
@@ -64,7 +64,7 @@ async function postBuildEvent(executor, eventConfig) {
|
|
|
64
64
|
buildEvent.buildId = buildId;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
await helper.createBuildEvent(apiUri, jwt, buildEvent,
|
|
67
|
+
await helper.createBuildEvent(apiUri, jwt, buildEvent, helper.requestRetryStrategyPostEvent);
|
|
68
68
|
} else {
|
|
69
69
|
logger.error(
|
|
70
70
|
`POST event for pipeline failed as no admin found: ${pipelineId}:${job.name}:${job.id}:${buildId}`
|
|
@@ -337,7 +337,7 @@ async function start(executor, config) {
|
|
|
337
337
|
apiUri,
|
|
338
338
|
payload
|
|
339
339
|
},
|
|
340
|
-
|
|
340
|
+
helper.requestRetryStrategy
|
|
341
341
|
)
|
|
342
342
|
.catch(err => {
|
|
343
343
|
logger.error(`frozenBuilds: failed to update build status for build ${buildId}: ${err}`);
|
|
@@ -399,7 +399,7 @@ async function start(executor, config) {
|
|
|
399
399
|
apiUri,
|
|
400
400
|
payload: { stats: build.stats, status: 'QUEUED' }
|
|
401
401
|
},
|
|
402
|
-
|
|
402
|
+
helper.requestRetryStrategy
|
|
403
403
|
);
|
|
404
404
|
}
|
|
405
405
|
}
|
|
@@ -730,7 +730,13 @@ async function queueWebhook(executor, webhookConfig) {
|
|
|
730
730
|
'enqueue',
|
|
731
731
|
executor.webhookQueue,
|
|
732
732
|
'sendWebhook',
|
|
733
|
-
JSON.stringify(
|
|
733
|
+
JSON.stringify({
|
|
734
|
+
webhookConfig,
|
|
735
|
+
token: executor.tokenGen({
|
|
736
|
+
service: 'queue',
|
|
737
|
+
scope: ['webhook_worker']
|
|
738
|
+
})
|
|
739
|
+
})
|
|
734
740
|
);
|
|
735
741
|
}
|
|
736
742
|
|
|
@@ -74,12 +74,11 @@ const timeOutOfWindow = (cronExp, timeToCheck) => {
|
|
|
74
74
|
const utcDayOfWeek = timeToCheck.getUTCDay();
|
|
75
75
|
const utcMonth = timeToCheck.getUTCMonth() + 1;
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const monthField = cronObj._fields.month;
|
|
77
|
+
const minuteField = cronObj.fields.minute;
|
|
78
|
+
const hourField = cronObj.fields.hour;
|
|
79
|
+
const dayOfMonthField = cronObj.fields.dayOfMonth;
|
|
80
|
+
const dayOfWeekField = cronObj.fields.dayOfWeek;
|
|
81
|
+
const monthField = cronObj.fields.month;
|
|
83
82
|
|
|
84
83
|
const includesMinute = minuteField.includes(utcMinutes);
|
|
85
84
|
const includesHour = hourField.includes(utcHours);
|
|
@@ -15,8 +15,8 @@ const blockedByConfig = config.get('plugins').blockedBy;
|
|
|
15
15
|
const { connectionDetails, queuePrefix, runningJobsPrefix, waitingJobsPrefix } = require('../../../config/redis');
|
|
16
16
|
const rabbitmqConf = require('../../../config/rabbitmq');
|
|
17
17
|
const { amqpURI, exchange, connectOptions } = rabbitmqConf.getConfig();
|
|
18
|
-
const
|
|
19
|
-
|
|
18
|
+
const kafkaConfig = require('../../../config/kafka');
|
|
19
|
+
const { kafkaEnabled, useShortRegionName } = kafkaConfig.get();
|
|
20
20
|
const RETRY_LIMIT = 3;
|
|
21
21
|
// This is in milliseconds, reference: https://github.com/actionhero/node-resque/blob/2ffdf0/lib/plugins/Retry.js#L12
|
|
22
22
|
const RETRY_DELAY = 5 * 1000;
|
|
@@ -57,6 +57,17 @@ const blockedByOptions = {
|
|
|
57
57
|
|
|
58
58
|
collapse: blockedByConfig.collapse
|
|
59
59
|
};
|
|
60
|
+
// AWS region map
|
|
61
|
+
const AWS_REGION_MAP = {
|
|
62
|
+
north: 'n',
|
|
63
|
+
west: 'w',
|
|
64
|
+
northeast: 'nw',
|
|
65
|
+
east: 'e',
|
|
66
|
+
south: 's',
|
|
67
|
+
central: 'c',
|
|
68
|
+
southeast: 'se'
|
|
69
|
+
};
|
|
70
|
+
|
|
60
71
|
let rabbitmqConn;
|
|
61
72
|
|
|
62
73
|
/**
|
|
@@ -125,15 +136,33 @@ async function pushToRabbitMq(message, queue, messageId) {
|
|
|
125
136
|
* Push message to Kafka topic
|
|
126
137
|
* @param {Object} message Job and build config metadata
|
|
127
138
|
* @param {String} topic Topic name
|
|
139
|
+
* @param {String} messageId The message id
|
|
128
140
|
*/
|
|
129
|
-
async function pushToKafka(message, topic) {
|
|
130
|
-
const
|
|
141
|
+
async function pushToKafka(message, topic, messageId) {
|
|
142
|
+
const producer = await AWSProducer.connect();
|
|
131
143
|
|
|
132
|
-
if (
|
|
133
|
-
await AWSProducer.sendMessage(message, topic);
|
|
144
|
+
if (producer) {
|
|
145
|
+
await AWSProducer.sendMessage(producer, message, topic, messageId);
|
|
134
146
|
}
|
|
135
147
|
}
|
|
136
148
|
|
|
149
|
+
/**
|
|
150
|
+
*
|
|
151
|
+
* @param {*String} accountId The AWS accountId
|
|
152
|
+
* @param {*String} region The region name
|
|
153
|
+
* @returns String topicName
|
|
154
|
+
*/
|
|
155
|
+
function getTopicName(accountId, region) {
|
|
156
|
+
const items = region.split('-');
|
|
157
|
+
|
|
158
|
+
if (items.length < 3 || !useShortRegionName) {
|
|
159
|
+
return `builds-${accountId}-${region}`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const shortRegion = ''.concat(items[0], AWS_REGION_MAP[items[1]], items[2]);
|
|
163
|
+
|
|
164
|
+
return `builds-${accountId}-${shortRegion}`;
|
|
165
|
+
}
|
|
137
166
|
/**
|
|
138
167
|
* Schedule a job based on mode
|
|
139
168
|
* @method schedule
|
|
@@ -153,9 +182,9 @@ async function schedule(job, buildConfig) {
|
|
|
153
182
|
|
|
154
183
|
if (kafkaEnabled && buildConfig.provider) {
|
|
155
184
|
const { accountId, region } = buildConfig.provider;
|
|
156
|
-
const
|
|
185
|
+
const messageId = `${job}-${buildConfig.buildId}`;
|
|
157
186
|
|
|
158
|
-
return pushToKafka(msg,
|
|
187
|
+
return pushToKafka(msg, getTopicName(accountId, region), messageId);
|
|
159
188
|
}
|
|
160
189
|
|
|
161
190
|
if (rabbitmqConf.getConfig().schedulerMode) {
|
|
@@ -276,18 +305,14 @@ async function clear(cacheConfig) {
|
|
|
276
305
|
|
|
277
306
|
/**
|
|
278
307
|
* Send message to processHooks API
|
|
279
|
-
* @param {String}
|
|
308
|
+
* @param {String} configs as String
|
|
280
309
|
*/
|
|
281
|
-
async function sendWebhook(
|
|
282
|
-
const parsedConfig = JSON.parse(
|
|
310
|
+
async function sendWebhook(configs) {
|
|
311
|
+
const parsedConfig = JSON.parse(configs);
|
|
312
|
+
const { webhookConfig, token } = parsedConfig;
|
|
283
313
|
const apiUri = ecosystem.api;
|
|
284
|
-
const token = executor.tokenGen({
|
|
285
|
-
service: 'queue',
|
|
286
|
-
scope: ['webhook_worker']
|
|
287
|
-
});
|
|
288
|
-
const retryFn = executor.requestRetryStrategyPostEvent;
|
|
289
314
|
|
|
290
|
-
await helper.processHooks(apiUri, token,
|
|
315
|
+
await helper.processHooks(apiUri, token, webhookConfig, helper.requestRetryStrategyPostEvent);
|
|
291
316
|
|
|
292
317
|
return null;
|
|
293
318
|
}
|