@joystick.js/node-canary 0.0.0-canary.445 → 0.0.0-canary.447
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import u from"cluster";import i from"../../../../lib/timestamps.js";const o={add_job:function(e={}){return(this.db?.collection(`queue_${this.queue.name}`)).insertOne({...e,attempts:0})},count_jobs:function(e=""){return(this.db?.collection(`queue_${this.queue.name}`)).countDocuments({status:e,locked_by:this.machine_id})},delete_job:function(e=""){return(this.db?.collection(`queue_${this.queue.name}`)).deleteOne({_id:e})},delete_incomplete_jobs_for_machine:function(){return(this.db?.collection(`queue_${this.queue.name}`)).deleteMany({status:{$in:["incomplete","running"]},locked_by:this.machine_id})},get_jobs:function(e={}){return(this.db?.collection(`queue_${this.queue.name}`)).find({...e,environment:process.env.NODE_ENV}).toArray()},get_next_job_to_run:async function(){return await(this.db?.collection(`queue_${this.queue.name}`)).findOneAndUpdate({$or:[{status:"pending",environment:process.env.NODE_ENV,next_run_at:{$lte:i.get_current_time()},locked_by:{$exists:!1}},{status:"pending",environment:process.env.NODE_ENV,next_run_at:{$lte:i.get_current_time()},locked_by:null}]},{$set:{status:"running",started_at:i.get_current_time(),locked_by:this.machine_id}},{sort:{next_run_at:1}})},initialize_database:async function(){if(u.isPrimary||u.isWorker&&u.worker.id===1){try{await this.db.createCollection(`queue_${this.queue.name}`)}catch{}const e=this.db?.collection(`queue_${this.queue.name}`),t=await e?.indexes();await e.createIndex({status:1}),await e.createIndex({status:1,next_run_at:1}),await e.createIndex({status:1,environment:1,next_run_at:1,locked_by:1}),(this.queue.options?.cleanup?.completedAfterSeconds||this.queue.options?.cleanup?.completed_after_seconds)&&(t?.find(n=>n?.name==="completed_at_1")&&await e.dropIndex({completed_at:1}),await e.createIndex({completed_at:1},{expireAfterSeconds:this?.queue?.options?.cleanup?.completedAfterSeconds||this.queue.options?.cleanup?.completed_after_seconds})),(this.queue.options?.cleanup?.failedAfterSeconds||this.queue.options?.cleanup?.failed_after_seconds)&&(t?.find(n=>n?.name==="failed_at_1")&&await e.dropIndex({failed_at:1}),await e.createIndex({failed_at:1},{expireAfterSeconds:this?.queue?.options?.cleanup?.failedAfterSeconds||this.queue.options?.cleanup?.failed_after_seconds}))}},log_attempt:function(e=""){return(this.db?.collection(`queue_${this.queue.name}`)).updateOne({_id:e},{$inc:{attempts:1}})},requeue_job:function(e="",t=null){return(this.db?.collection(`queue_${this.queue.name}`)).updateOne({_id:e},{$set:{status:"pending",next_run_at:t},$unset:{locked_by:""}})},set_job_completed:function(e=""){return(this.db?.collection(`queue_${this.queue.name}`)).updateOne({_id:e},{$set:{status:"completed",completed_at:i.get_current_time({mongodb_ttl:!0})}})},set_job_failed:function(e="",t=""){return(this.db?.collection(`queue_${this.queue.name}`)).updateOne({_id:e},{$set:{status:"failed",failed_at:i.get_current_time({mongodb_ttl:!0}),error:t}})},set_jobs_for_machine_pending:function(){return(this.db?.collection(`queue_${this.queue.name}`)).updateMany({status:{$in:["pending","running"]},locked_by:this.machine_id},{$set:{status:"pending"},$unset:{locked_by:""}})}};var a=o;export{a as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import s from"node-cron";import
|
|
1
|
+
import s from"node-cron";import i from"../../postgresql/handle_cleanup_queues.js";import n from"../../../../lib/timestamps.js";import a from"../../../../lib/wait.js";const o={add_job:async function(e={}){const t=this?.db,[u]=await t?.query("SELECT * FROM information_schema.tables WHERE table_name = $1",[`queue_${this.queue.name}`]);return u||await a(1),t?.query(`
|
|
2
2
|
INSERT INTO queue_${this.queue.name} (
|
|
3
3
|
_id,
|
|
4
4
|
status,
|
|
@@ -62,22 +62,22 @@ import s from"node-cron";import a from"../../postgresql/handle_cleanup_queues.js
|
|
|
62
62
|
locked_by = $3
|
|
63
63
|
WHERE
|
|
64
64
|
_id = $4
|
|
65
|
-
`,["running",n.get_current_time(),this.machine_id,t?._id]),t?{...t,payload:t?.payload?JSON.parse(t?.payload||""):{}}:{}},initialize_database:async function(){const e=this?.db;await e?.query(`
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
65
|
+
`,["running",n.get_current_time(),this.machine_id,t?._id]),t?{...t,payload:t?.payload?JSON.parse(t?.payload||""):{}}:{}},initialize_database:async function(){if(cluster.isPrimary||cluster.isWorker&&cluster.worker.id===1){const e=this?.db;await e?.query(`
|
|
66
|
+
CREATE TABLE IF NOT EXISTS queue_${this.queue.name} (
|
|
67
|
+
_id text PRIMARY KEY,
|
|
68
|
+
status text,
|
|
69
|
+
job text,
|
|
70
|
+
payload text,
|
|
71
|
+
next_run_at text,
|
|
72
|
+
locked_by text,
|
|
73
|
+
started_at text,
|
|
74
|
+
completed_at text,
|
|
75
|
+
failed_at text,
|
|
76
|
+
error text,
|
|
77
|
+
environment text,
|
|
78
|
+
attempts smallint
|
|
79
|
+
)
|
|
80
|
+
`),await e?.query(`ALTER TABLE queue_${this.queue.name} ADD COLUMN IF NOT EXISTS environment text`),await e?.query(`ALTER TABLE queue_${this.queue.name} ADD COLUMN IF NOT EXISTS attempts smallint`),await e?.query(`CREATE INDEX IF NOT EXISTS status_index ON queue_${this.queue.name} (status)`),await e?.query(`CREATE INDEX IF NOT EXISTS status_next_run_at_index ON queue_${this.queue.name} (status, next_run_at)`),await e?.query(`CREATE INDEX IF NOT EXISTS next_job_index ON queue_${this.queue.name} (status, environment, next_run_at, locked_by)`),await e?.query(`CREATE INDEX IF NOT EXISTS completed_at_index ON queue_${this.queue.name} (completed_at)`),await e?.query(`CREATE INDEX IF NOT EXISTS failed_at_index ON queue_${this.queue.name} (failed_at)`),(this.queue.options?.cleanup?.completedAfterSeconds||this.queue.options?.cleanup?.completed_after_seconds)&&s.schedule("*/30 * * * * *",()=>{i({database:e,table:`queue_${this.queue.name}`,seconds:this.queue.options?.cleanup?.completedAfterSeconds||this.queue.options?.cleanup?.completed_after_seconds})}),(this.queue.options?.cleanup?.failedAfterSeconds||this.queue.options?.cleanup?.failed_after_seconds)&&s.schedule("*/30 * * * * *",()=>{i({database:e,table:`queue_${this.queue.name}`,seconds:this.queue.options?.cleanup?.failedAfterSeconds||this.queue.options?.cleanup?.failed_after_seconds})})}},log_attempt:function(e=""){return this?.db?.query(`
|
|
81
81
|
UPDATE
|
|
82
82
|
queue_${this.queue.name}
|
|
83
83
|
SET
|
package/package.json
CHANGED
|
@@ -68,7 +68,6 @@ const queues ={
|
|
|
68
68
|
// errors to be thrown). Only a primary or 1st worker should run this.
|
|
69
69
|
|
|
70
70
|
if (cluster.isPrimary || (cluster.isWorker && cluster.worker.id === 1)) {
|
|
71
|
-
console.log('RALPH WIGGUM');
|
|
72
71
|
try {
|
|
73
72
|
await this.db.createCollection(`queue_${this.queue.name}`);
|
|
74
73
|
} catch {
|
|
@@ -147,56 +147,62 @@ const queues = {
|
|
|
147
147
|
} : {};
|
|
148
148
|
},
|
|
149
149
|
initialize_database: async function () {
|
|
150
|
-
|
|
150
|
+
// NOTE: Add this check to avoid clustered apps from creating a race condition
|
|
151
|
+
// when initializing indexes below (they step on each other's toes and cause
|
|
152
|
+
// errors to be thrown). Only a primary or 1st worker should run this.
|
|
151
153
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
_id text PRIMARY KEY,
|
|
155
|
-
status text,
|
|
156
|
-
job text,
|
|
157
|
-
payload text,
|
|
158
|
-
next_run_at text,
|
|
159
|
-
locked_by text,
|
|
160
|
-
started_at text,
|
|
161
|
-
completed_at text,
|
|
162
|
-
failed_at text,
|
|
163
|
-
error text,
|
|
164
|
-
environment text,
|
|
165
|
-
attempts smallint
|
|
166
|
-
)
|
|
167
|
-
`);
|
|
154
|
+
if (cluster.isPrimary || (cluster.isWorker && cluster.worker.id === 1)) {
|
|
155
|
+
const db = this?.db;
|
|
168
156
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
157
|
+
await db?.query(`
|
|
158
|
+
CREATE TABLE IF NOT EXISTS queue_${this.queue.name} (
|
|
159
|
+
_id text PRIMARY KEY,
|
|
160
|
+
status text,
|
|
161
|
+
job text,
|
|
162
|
+
payload text,
|
|
163
|
+
next_run_at text,
|
|
164
|
+
locked_by text,
|
|
165
|
+
started_at text,
|
|
166
|
+
completed_at text,
|
|
167
|
+
failed_at text,
|
|
168
|
+
error text,
|
|
169
|
+
environment text,
|
|
170
|
+
attempts smallint
|
|
171
|
+
)
|
|
172
|
+
`);
|
|
172
173
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
// NOTE: Add additional attempts field as a standalone column to support existing queue_ tables.
|
|
175
|
+
await db?.query(`ALTER TABLE queue_${this.queue.name} ADD COLUMN IF NOT EXISTS environment text`);
|
|
176
|
+
await db?.query(`ALTER TABLE queue_${this.queue.name} ADD COLUMN IF NOT EXISTS attempts smallint`);
|
|
176
177
|
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
await db?.query(`CREATE INDEX IF NOT EXISTS status_index ON queue_${this.queue.name} (status)`);
|
|
179
|
+
await db?.query(`CREATE INDEX IF NOT EXISTS status_next_run_at_index ON queue_${this.queue.name} (status, next_run_at)`);
|
|
180
|
+
await db?.query(`CREATE INDEX IF NOT EXISTS next_job_index ON queue_${this.queue.name} (status, environment, next_run_at, locked_by)`);
|
|
179
181
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
182
|
+
await db?.query(`CREATE INDEX IF NOT EXISTS completed_at_index ON queue_${this.queue.name} (completed_at)`);
|
|
183
|
+
await db?.query(`CREATE INDEX IF NOT EXISTS failed_at_index ON queue_${this.queue.name} (failed_at)`);
|
|
184
|
+
|
|
185
|
+
// NOTE: PostgreSQL does NOT have a TTL index or event-based row expiration feature,
|
|
186
|
+
// so we "polyfill" here with 30 second cron jobs to do the cleanup for us.
|
|
187
|
+
if (this.queue.options?.cleanup?.completedAfterSeconds || this.queue.options?.cleanup?.completed_after_seconds) {
|
|
188
|
+
cron.schedule('*/30 * * * * *', () => {
|
|
189
|
+
handle_cleanup_queues({
|
|
190
|
+
database: db,
|
|
191
|
+
table: `queue_${this.queue.name}`,
|
|
192
|
+
seconds: this.queue.options?.cleanup?.completedAfterSeconds || this.queue.options?.cleanup?.completed_after_seconds,
|
|
193
|
+
});
|
|
188
194
|
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
195
|
+
}
|
|
191
196
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
if (this.queue.options?.cleanup?.failedAfterSeconds || this.queue.options?.cleanup?.failed_after_seconds) {
|
|
198
|
+
cron.schedule('*/30 * * * * *', () => {
|
|
199
|
+
handle_cleanup_queues({
|
|
200
|
+
database: db,
|
|
201
|
+
table: `queue_${this.queue.name}`,
|
|
202
|
+
seconds: this.queue.options?.cleanup?.failedAfterSeconds || this.queue.options?.cleanup?.failed_after_seconds,
|
|
203
|
+
});
|
|
198
204
|
});
|
|
199
|
-
}
|
|
205
|
+
}
|
|
200
206
|
}
|
|
201
207
|
},
|
|
202
208
|
log_attempt: function (job_id = '') {
|