@joystick.js/node-canary 0.0.0-canary.446 → 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,4 +1,4 @@
1
- import s from"node-cron";import a from"../../postgresql/handle_cleanup_queues.js";import n from"../../../../lib/timestamps.js";import i 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 i(1),t?.query(`
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
- 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 * * * * *",()=>{a({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 * * * * *",()=>{a({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(`
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@joystick.js/node-canary",
3
3
  "type": "module",
4
- "version": "0.0.0-canary.446",
4
+ "version": "0.0.0-canary.447",
5
5
  "description": "The Node.js framework for Joystick.",
6
6
  "main": "./dist/index.js",
7
7
  "scripts": {
@@ -147,56 +147,62 @@ const queues = {
147
147
  } : {};
148
148
  },
149
149
  initialize_database: async function () {
150
- const db = this?.db;
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
- await db?.query(`
153
- CREATE TABLE IF NOT EXISTS queue_${this.queue.name} (
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
- // NOTE: Add additional attempts field as a standalone column to support existing queue_ tables.
170
- await db?.query(`ALTER TABLE queue_${this.queue.name} ADD COLUMN IF NOT EXISTS environment text`);
171
- await db?.query(`ALTER TABLE queue_${this.queue.name} ADD COLUMN IF NOT EXISTS attempts smallint`);
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
- await db?.query(`CREATE INDEX IF NOT EXISTS status_index ON queue_${this.queue.name} (status)`);
174
- await db?.query(`CREATE INDEX IF NOT EXISTS status_next_run_at_index ON queue_${this.queue.name} (status, next_run_at)`);
175
- await db?.query(`CREATE INDEX IF NOT EXISTS next_job_index ON queue_${this.queue.name} (status, environment, next_run_at, locked_by)`);
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
- await db?.query(`CREATE INDEX IF NOT EXISTS completed_at_index ON queue_${this.queue.name} (completed_at)`);
178
- await db?.query(`CREATE INDEX IF NOT EXISTS failed_at_index ON queue_${this.queue.name} (failed_at)`);
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
- // NOTE: PostgreSQL does NOT have a TTL index or event-based row expiration feature,
181
- // so we "polyfill" here with 30 second cron jobs to do the cleanup for us.
182
- if (this.queue.options?.cleanup?.completedAfterSeconds || this.queue.options?.cleanup?.completed_after_seconds) {
183
- cron.schedule('*/30 * * * * *', () => {
184
- handle_cleanup_queues({
185
- database: db,
186
- table: `queue_${this.queue.name}`,
187
- seconds: this.queue.options?.cleanup?.completedAfterSeconds || this.queue.options?.cleanup?.completed_after_seconds,
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
- if (this.queue.options?.cleanup?.failedAfterSeconds || this.queue.options?.cleanup?.failed_after_seconds) {
193
- cron.schedule('*/30 * * * * *', () => {
194
- handle_cleanup_queues({
195
- database: db,
196
- table: `queue_${this.queue.name}`,
197
- seconds: this.queue.options?.cleanup?.failedAfterSeconds || this.queue.options?.cleanup?.failed_after_seconds,
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 = '') {