qdone 2.1.0 → 2.1.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/LICENSE +2 -2
- package/README.md +1 -4
- package/commonjs/index.js +11 -0
- package/commonjs/src/cache.js +72 -0
- package/commonjs/src/cloudWatch.js +102 -0
- package/commonjs/src/consumer.js +173 -0
- package/commonjs/src/dedup.js +266 -0
- package/commonjs/src/defaults.js +182 -0
- package/commonjs/src/enqueue.js +521 -0
- package/commonjs/src/exponentialBackoff.js +101 -0
- package/commonjs/src/idleQueues.js +333 -0
- package/commonjs/src/monitor.js +80 -0
- package/commonjs/src/qrlCache.js +172 -0
- package/commonjs/src/scheduler/jobExecutor.js +383 -0
- package/commonjs/src/scheduler/queueManager.js +161 -0
- package/commonjs/src/scheduler/systemMonitor.js +94 -0
- package/commonjs/src/sqs.js +97 -0
- package/package.json +7 -3
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setupVerbose = exports.setupAWS = exports.getOptionsWithDefaults = exports.validateMessageOptions = exports.validateQueueName = exports.validateInteger = exports.defaults = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Default options for qdone. Accepts a command line options object and
|
|
6
|
+
* returns nicely-named options.
|
|
7
|
+
*/
|
|
8
|
+
const uuid_1 = require("uuid");
|
|
9
|
+
exports.defaults = Object.freeze({
|
|
10
|
+
// Shared
|
|
11
|
+
prefix: 'qdone_',
|
|
12
|
+
failSuffix: '_failed',
|
|
13
|
+
region: 'us-east-1',
|
|
14
|
+
quiet: false,
|
|
15
|
+
verbose: false,
|
|
16
|
+
cache: false,
|
|
17
|
+
cacheUri: undefined,
|
|
18
|
+
cachePrefix: 'qdone:',
|
|
19
|
+
cacheTtlSeconds: 10,
|
|
20
|
+
fifo: false,
|
|
21
|
+
disableLog: false,
|
|
22
|
+
includeFailed: false,
|
|
23
|
+
includeDead: false,
|
|
24
|
+
externalDedup: false,
|
|
25
|
+
dedupPeriod: 60 * 5,
|
|
26
|
+
dedupStats: false,
|
|
27
|
+
// Enqueue
|
|
28
|
+
groupId: (0, uuid_1.v1)(),
|
|
29
|
+
groupIdPerMessage: false,
|
|
30
|
+
deduplicationId: undefined,
|
|
31
|
+
dedupIdPerMessage: false,
|
|
32
|
+
messageRetentionPeriod: 1209600,
|
|
33
|
+
delay: 0,
|
|
34
|
+
sendRetries: 6,
|
|
35
|
+
failDelay: 120,
|
|
36
|
+
dlq: true,
|
|
37
|
+
dlqSuffix: '_dead',
|
|
38
|
+
dlqAfter: 3,
|
|
39
|
+
// Worker
|
|
40
|
+
waitTime: 20,
|
|
41
|
+
killAfter: 30,
|
|
42
|
+
archive: false,
|
|
43
|
+
activeOnly: false,
|
|
44
|
+
maxConcurrentJobs: 100,
|
|
45
|
+
maxMemoryPercent: 70,
|
|
46
|
+
// Idle Queues
|
|
47
|
+
idleFor: 60,
|
|
48
|
+
delete: false,
|
|
49
|
+
// Check
|
|
50
|
+
create: false,
|
|
51
|
+
overwrite: false
|
|
52
|
+
});
|
|
53
|
+
function validateInteger(opt, name) {
|
|
54
|
+
const parsed = parseInt(opt[name], 10);
|
|
55
|
+
if (isNaN(parsed))
|
|
56
|
+
throw new Error(`${name} needs to be an integer.`);
|
|
57
|
+
return parsed;
|
|
58
|
+
}
|
|
59
|
+
exports.validateInteger = validateInteger;
|
|
60
|
+
function validateQueueName(opt, name) {
|
|
61
|
+
if (typeof name !== 'string')
|
|
62
|
+
throw new Error(`${name} must be a string.`);
|
|
63
|
+
if (!name.match(/^[a-z0-9-_]+$/i))
|
|
64
|
+
throw new Error(`${name} can contain only numbers, letters, hypens and underscores.`);
|
|
65
|
+
return name;
|
|
66
|
+
}
|
|
67
|
+
exports.validateQueueName = validateQueueName;
|
|
68
|
+
function validateMessageOptions(messageOptions) {
|
|
69
|
+
const validKeys = ['deduplicationId', 'groupId'];
|
|
70
|
+
if (typeof messageOptions === 'object' &&
|
|
71
|
+
!Array.isArray(messageOptions) &&
|
|
72
|
+
messageOptions !== null) {
|
|
73
|
+
for (const key in messageOptions) {
|
|
74
|
+
if (!validKeys.includes(key))
|
|
75
|
+
throw new Error(`Invalid message option ${key}`);
|
|
76
|
+
}
|
|
77
|
+
return messageOptions;
|
|
78
|
+
}
|
|
79
|
+
return {};
|
|
80
|
+
}
|
|
81
|
+
exports.validateMessageOptions = validateMessageOptions;
|
|
82
|
+
/**
|
|
83
|
+
* This function should be called by each exposed API entry point on the
|
|
84
|
+
* options passed in from the caller. It supports options named in camelCase
|
|
85
|
+
* and also in command-line-style returned by our parsers.
|
|
86
|
+
*
|
|
87
|
+
* By convention, we name the variable "options" if it comes from the user
|
|
88
|
+
* and "opt" if it has already passed through this function.
|
|
89
|
+
*/
|
|
90
|
+
function getOptionsWithDefaults(options) {
|
|
91
|
+
// For API invocations don't force caller to supply default options
|
|
92
|
+
if (!options)
|
|
93
|
+
options = {};
|
|
94
|
+
// Activate DLQ if any option is set
|
|
95
|
+
const dlq = options.dlq || !!(options['dlq-suffix'] || options['dlq-after'] || options['dlq-name'] || options.dlqSuffix || options.dlqAfter || options.dlqName);
|
|
96
|
+
const opt = {
|
|
97
|
+
// Shared
|
|
98
|
+
prefix: options.prefix === '' ? options.prefix : (options.prefix || process.env.QDONE_PREFIX || exports.defaults.prefix),
|
|
99
|
+
failSuffix: options.failSuffix || options['fail-suffix'] || process.env.QDONE_FAIL_SUFFIX || exports.defaults.failSuffix,
|
|
100
|
+
region: options.region || process.env.QDONE_REGION || process.env.AWS_REGION || exports.defaults.region,
|
|
101
|
+
quiet: options.quiet || process.env.QDONE_QUIET === 'true' || exports.defaults.quiet,
|
|
102
|
+
verbose: options.verbose || process.env.QDONE_VERBOSE === 'true' || exports.defaults.verbose,
|
|
103
|
+
fifo: options.fifo || process.env.QDONE_FIFO === 'true' || exports.defaults.fifo,
|
|
104
|
+
sentryDsn: options.sentryDsn || options['sentry-dsn'] || process.env.QDONE_SENTRY_DSN,
|
|
105
|
+
disableLog: options.disableLog || options['disable-log'] || process.env.QDONE_DISABLE_LOG === 'true' || exports.defaults.disableLog,
|
|
106
|
+
includeFailed: options.includeFailed || options['include-failed'] || process.env.QDONE_INCLUDE_FAILED === 'true' || exports.defaults.includeFailed,
|
|
107
|
+
includeDead: options.includeDead || options['include-dead'] || process.env.QDONE_INCLUDE_DEAD === 'true' || exports.defaults.includeDead,
|
|
108
|
+
externalDedup: options.externalDedup || options['external-dedup'] || process.env.QDONE_EXTERNAL_DEDUP === 'true' || exports.defaults.externalDedup,
|
|
109
|
+
dedupPeriod: options.dedupPeriod || options['dedup-period'] || process.env.QDONE_DEDUP_PERIOD || exports.defaults.dedupPeriod,
|
|
110
|
+
dedupStats: options.dedupStats || options['dedup-stats'] || process.env.QDONE_DEDUP_STATS === 'true' || exports.defaults.dedupStats,
|
|
111
|
+
// Cache
|
|
112
|
+
cacheUri: options.cacheUri || options['cache-uri'] || process.env.QDONE_CACHE_URI || exports.defaults.cacheUri,
|
|
113
|
+
cachePrefix: options.cachePrefix || options['cache-prefix'] || process.env.QDONE_CACHE_PREFIX || exports.defaults.cachePrefix,
|
|
114
|
+
cacheTtlSeconds: options.cacheTtlSeconds || options['cache-ttl-seconds'] || process.env.QDONE_CACHE_TTL_SECONDS || exports.defaults.cacheTtlSeconds,
|
|
115
|
+
// Enqueue
|
|
116
|
+
groupId: options.groupId || options['group-id'] || process.env.QDONE_GROUP_ID || exports.defaults.groupId,
|
|
117
|
+
groupIdPerMessage: false,
|
|
118
|
+
deduplicationId: options.deduplicationId || options['deduplication-id'] || process.env.QDONE_DEDUPLICATION_ID || exports.defaults.deduplicationId,
|
|
119
|
+
dedupIdPerMessage: options.dedupIdPerMessage || options['dedup-id-per-message'] || process.env.QDONE_DEDUP_ID_PER_MESSAGE === 'true' || exports.defaults.dedupIdPerMessage,
|
|
120
|
+
messageRetentionPeriod: options.messageRetentionPeriod || options['message-retention-period'] || process.env.QDONE_MESSAGE_RETENTION_PERIOD || exports.defaults.messageRetentionPeriod,
|
|
121
|
+
delay: options.delay || process.env.QDONE_DELAY || exports.defaults.delay,
|
|
122
|
+
sendRetries: options.sendRetries || options['send-retries'] || process.env.QDONE_SEND_RETRIES || exports.defaults.sendRetries,
|
|
123
|
+
failDelay: options.failDelay || options['fail-delay'] || process.env.QDONE_FAIL_DELAY || exports.defaults.failDelay,
|
|
124
|
+
dlq: dlq === false ? false : exports.defaults.dlq,
|
|
125
|
+
dlqSuffix: options.dlqSuffix || options['dlq-suffix'] || process.env.QDONE_DLQ_SUFFIX || exports.defaults.dlqSuffix,
|
|
126
|
+
dlqAfter: options.dlqAfter || options['dlq-after'] || process.env.QDONE_DLQ_AFTER || exports.defaults.dlqAfter,
|
|
127
|
+
tags: options.tags || undefined,
|
|
128
|
+
// Worker
|
|
129
|
+
waitTime: options.waitTime || options['wait-time'] || process.env.QDONE_WAIT_TIME || exports.defaults.waitTime,
|
|
130
|
+
killAfter: options.killAfter || options['kill-after'] || process.env.QDONE_KILL_AFTER || exports.defaults.killAfter,
|
|
131
|
+
archive: options.archive || process.env.QDONE_ARCHIVE === 'true' || exports.defaults.archive,
|
|
132
|
+
activeOnly: options.activeOnly || options['active-only'] || process.env.QDONE_ACTIVE_ONLY === 'true' || exports.defaults.activeOnly,
|
|
133
|
+
maxConcurrentJobs: options.maxConcurrentJobs || process.env.QDONE_MAX_CONCURRENT_JOBS || exports.defaults.maxConcurrentJobs,
|
|
134
|
+
maxMemoryPercent: options.maxMemoryPercent || process.env.QDONE_MAX_MEMORY_PERCENT || exports.defaults.maxMemoryPercent,
|
|
135
|
+
// Idle Queues
|
|
136
|
+
idleFor: options.idleFor || options['idle-for'] || process.env.QDONE_IDLE_FOR || exports.defaults.idleFor,
|
|
137
|
+
delete: options.delete || process.env.QDONE_DELETE === 'true' || exports.defaults.delete,
|
|
138
|
+
// Check
|
|
139
|
+
create: options.create || process.env.QDONE_CREATE === 'true' || exports.defaults.create,
|
|
140
|
+
overwrite: options.overwrite || process.env.QDONE_OVERWRITE === 'true' || exports.defaults.overwrite
|
|
141
|
+
};
|
|
142
|
+
// Setting this env here means we don't have to in AWS SDK constructors
|
|
143
|
+
process.env.AWS_REGION = opt.region;
|
|
144
|
+
// Validation
|
|
145
|
+
opt.cacheTtlSeconds = validateInteger(opt, 'cacheTtlSeconds');
|
|
146
|
+
opt.messageRetentionPeriod = validateInteger(opt, 'messageRetentionPeriod');
|
|
147
|
+
opt.delay = validateInteger(opt, 'delay');
|
|
148
|
+
opt.sendRetries = validateInteger(opt, 'sendRetries');
|
|
149
|
+
opt.dedupPeriod = validateInteger(opt, 'dedupPeriod');
|
|
150
|
+
opt.failDelay = validateInteger(opt, 'failDelay');
|
|
151
|
+
opt.dlqAfter = validateInteger(opt, 'dlqAfter');
|
|
152
|
+
opt.waitTime = validateInteger(opt, 'waitTime');
|
|
153
|
+
opt.killAfter = validateInteger(opt, 'killAfter');
|
|
154
|
+
opt.maxConcurrentJobs = validateInteger(opt, 'maxConcurrentJobs');
|
|
155
|
+
opt.maxMemoryPercent = validateInteger(opt, 'maxMemoryPercent');
|
|
156
|
+
opt.idleFor = validateInteger(opt, 'idleFor');
|
|
157
|
+
validateQueueName(opt, 'region');
|
|
158
|
+
validateQueueName(opt, 'prefix');
|
|
159
|
+
validateQueueName(opt, 'failSuffix');
|
|
160
|
+
validateQueueName(opt, 'dlqSuffix');
|
|
161
|
+
// Validate dedup args
|
|
162
|
+
if (opt.externalDedup && !opt.cacheUri)
|
|
163
|
+
throw new Error('--external-dedup requires the --cache-uri argument');
|
|
164
|
+
if (opt.externalDedup && (opt.dedupPeriod < 1))
|
|
165
|
+
throw new Error('--external-dedup of redis requires a --dedup-period > 1 second');
|
|
166
|
+
if (opt.dedupIdPerMessage && opt.deduplicationId)
|
|
167
|
+
throw new Error('Use either --deduplication-id or --dedup-id-per-message but not both');
|
|
168
|
+
return opt;
|
|
169
|
+
}
|
|
170
|
+
exports.getOptionsWithDefaults = getOptionsWithDefaults;
|
|
171
|
+
function setupAWS(options) {
|
|
172
|
+
const opt = getOptionsWithDefaults(options);
|
|
173
|
+
process.env.AWS_REGION = opt.region;
|
|
174
|
+
}
|
|
175
|
+
exports.setupAWS = setupAWS;
|
|
176
|
+
function setupVerbose(options) {
|
|
177
|
+
const verbose = options.verbose || (process.stderr.isTTY && !options.quiet);
|
|
178
|
+
const quiet = options.quiet || (!process.stderr.isTTY && !options.verbose);
|
|
179
|
+
options.verbose = verbose;
|
|
180
|
+
options.quiet = quiet;
|
|
181
|
+
}
|
|
182
|
+
exports.setupVerbose = setupVerbose;
|