ti2 1.0.124 → 1.0.126
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/README.md +16 -0
- package/api.yml +108 -1
- package/auth/authHandler.js +3 -0
- package/controllers/__tests__/app.js +48 -3
- package/controllers/__tests__/user.js +87 -1
- package/controllers/app.js +90 -18
- package/controllers/user.js +35 -7
- package/migrations/20260914180000-create-integration-lifecycles.js +67 -0
- package/models/integrationlifecycle.js +44 -0
- package/package.json +1 -1
- package/services/__tests__/integrationLifecycle.db.js +251 -0
- package/services/__tests__/integrationLifecycle.js +563 -0
- package/services/integrationLifecycle.js +496 -0
- package/worker/__tests__/queue-remove.js +89 -0
- package/worker/queue.js +44 -50
package/worker/queue.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
const Queue = require('bull');
|
|
2
|
+
const crypto = require('crypto');
|
|
2
3
|
const R = require('ramda');
|
|
3
4
|
const Redis = require('ioredis');
|
|
4
|
-
|
|
5
|
-
const { env: { redisHost, redisPort } } = process;
|
|
5
|
+
|
|
6
6
|
const REDIS_URL = process.env.REDIS_URL || 'redis://redis:6379';
|
|
7
7
|
const itemsTTL = 3 * 60 * 60; // 3 hours
|
|
8
8
|
|
|
9
|
-
const queue = new Queue('work', `${REDIS_URL}/0
|
|
9
|
+
const queue = new Queue('work', `${REDIS_URL}/0`, {
|
|
10
|
+
settings: {
|
|
11
|
+
lockDuration: 120e3,
|
|
12
|
+
lockRenewTime: 15e3,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
10
15
|
const redisResults = new Redis(`${REDIS_URL}/1`);
|
|
11
16
|
|
|
12
17
|
const getPending = async () => {
|
|
@@ -40,71 +45,60 @@ const addJob = async (payload, paramsParam) => {
|
|
|
40
45
|
removeOnComplete: true,
|
|
41
46
|
...params,
|
|
42
47
|
});
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
return id;
|
|
48
|
+
// Repeat jobs use an occurrence ID containing Bull's repeat-definition hash.
|
|
49
|
+
// Persisting it lets removeJob identify one exact definition without matching by cron.
|
|
50
|
+
return job.id;
|
|
46
51
|
};
|
|
47
52
|
|
|
48
53
|
const saveResult = async ({ id, resultValue }) => {
|
|
49
54
|
await redisResults.set(id, JSON.stringify(resultValue), 'EX', itemsTTL);
|
|
50
55
|
};
|
|
51
56
|
|
|
52
|
-
const removeJob = async
|
|
53
|
-
|
|
57
|
+
const removeJob = async jobId => {
|
|
58
|
+
if (!jobId) return;
|
|
59
|
+
// Bull occurrence IDs use the format 'repeat:<repeat-definition-hash>:<timestamp>'.
|
|
54
60
|
const jobIdParts = jobId.split(':');
|
|
55
61
|
const isRepeatJob = jobIdParts[0] === 'repeat';
|
|
56
62
|
|
|
57
63
|
if (isRepeatJob) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Wait for the queue to process the removals
|
|
85
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
86
|
-
|
|
87
|
-
// Clean up any remaining jobs
|
|
88
|
-
const remainingJobs = await queue.getJobs(['active', 'wait', 'delayed']);
|
|
89
|
-
for (const job of remainingJobs) {
|
|
90
|
-
if (job.opts.repeat && job.opts.jobId === jobId) {
|
|
91
|
-
await job.remove();
|
|
92
|
-
}
|
|
64
|
+
const job = await queue.getJob(jobId);
|
|
65
|
+
let repeatKey = R.path(['opts', 'repeat', 'key'], job);
|
|
66
|
+
if (!repeatKey) {
|
|
67
|
+
// Bull v4 does not expose occurrence-to-definition lookup. Recreate its
|
|
68
|
+
// internal hash only for legacy rows whose scheduled occurrence has expired.
|
|
69
|
+
const repeatHash = jobIdParts[1];
|
|
70
|
+
const repeatableJobs = await queue.getRepeatableJobs();
|
|
71
|
+
const repeatable = repeatableJobs.find(candidate => {
|
|
72
|
+
const candidateJobId = candidate.id ? `${candidate.id}:` : ':';
|
|
73
|
+
const namespace = crypto.createHash('md5').update(candidate.key).digest('hex');
|
|
74
|
+
const candidateHash = crypto.createHash('md5')
|
|
75
|
+
.update(`${candidate.name}${candidateJobId}${namespace}`)
|
|
76
|
+
.digest('hex');
|
|
77
|
+
return candidateHash === repeatHash;
|
|
78
|
+
});
|
|
79
|
+
repeatKey = repeatable && repeatable.key;
|
|
80
|
+
}
|
|
81
|
+
if (repeatKey) await queue.removeRepeatableByKey(repeatKey);
|
|
82
|
+
if (job) {
|
|
83
|
+
try {
|
|
84
|
+
await job.remove();
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (error.message && !error.message.includes('not found')) throw error;
|
|
93
87
|
}
|
|
94
|
-
|
|
95
|
-
await redisResults.del(jobId);
|
|
96
|
-
return;
|
|
97
88
|
}
|
|
98
|
-
|
|
99
|
-
// If we couldn't find the repeatable job, just delete from the database
|
|
100
|
-
// This can happen if the job was already removed from Bull but still exists in our database
|
|
89
|
+
await redisResults.del(jobId);
|
|
101
90
|
return;
|
|
102
91
|
}
|
|
103
92
|
|
|
104
93
|
// If not a repeatable job, try to remove as a regular job
|
|
105
94
|
const job = await queue.getJob(jobId);
|
|
106
95
|
if (!job) {
|
|
107
|
-
|
|
96
|
+
// Older CronJobs rows stored opts.jobId instead of the repeat occurrence ID.
|
|
97
|
+
const repeatableJobs = await queue.getRepeatableJobs() || [];
|
|
98
|
+
const repeatable = repeatableJobs.find(candidate => candidate.id === jobId);
|
|
99
|
+
if (repeatable) await queue.removeRepeatableByKey(repeatable.key);
|
|
100
|
+
await redisResults.del(jobId);
|
|
101
|
+
return;
|
|
108
102
|
}
|
|
109
103
|
await job.remove();
|
|
110
104
|
await redisResults.del(jobId);
|