@opengis/fastify-table 1.3.18 → 1.3.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengis/fastify-table",
3
- "version": "1.3.18",
3
+ "version": "1.3.19",
4
4
  "type": "module",
5
5
  "description": "core-plugins",
6
6
  "keywords": [
@@ -1,89 +1,11 @@
1
- import { createHash } from 'crypto';
2
-
3
1
  import config from '../../../../config.js';
4
- import getRedis from '../../redis/funcs/getRedis.js';
5
- import getPG from '../../pg/funcs/getPG.js';
6
- import logger from '../../logger/getLogger.js';
7
- import cronList from '../cronList.js';
8
-
9
- const md5 = (string) => createHash('md5').update(string).digest('hex');
10
-
11
- const rclient = getRedis();
12
- async function verifyUnique(name) {
13
- const cronId = config.port || 3000 + md5(name);
14
- // one per node check
15
- const key = `cron:unique:${cronId}`;
16
- const unique = await rclient.setnx(key, 1);
17
- const ttl = await rclient.ttl(key);
18
- if (!unique && ttl !== -1) {
19
- return false;
20
- }
21
- await rclient.expire(key, 20);
22
- return true;
23
- }
24
-
25
- const intervalStringMs = {
26
- everyMin: 1000 * 60,
27
- tenMin: 1000 * 60 * 10,
28
- everyHour: 1000 * 60 * 60,
29
- isHalfday: 1000 * 60 * 60 * 12,
30
- dailyHour: 1000 * 60 * 60 * 24,
31
- };
32
2
 
33
- const interval2ms = {
34
- string: (interval) => {
35
- const date = new Date();
36
- const intervarSplit = interval.match(/^(\*{2}|(\*)?(\d{1,2})):(\*(\d)|(\d{2}))/);
37
- if (!intervarSplit) {
38
- throw new Error(`interval ${interval} not suported`);
39
- }
40
- const [, , isHalfday, dailyHour, , tenMin, HourlyMin] = intervarSplit;
41
- const intervalMs = (isHalfday && intervalStringMs.isHalfday)
42
- || (dailyHour && intervalStringMs.dailyHour)
43
- || (tenMin && intervalStringMs.tenMin)
44
- || intervalStringMs.everyHour;
45
- const offsetDay = ((+dailyHour || 0) * 60 + (+tenMin || +HourlyMin)) * 60 * 1000;
46
- const offsetCur = (date - date.getTimezoneOffset() * 1000 * 60) % intervalMs;
47
- const waitMs = (offsetDay - offsetCur + intervalMs) % intervalMs;
48
- return [waitMs, intervalMs];
49
- },
50
- number: (interval) => {
51
- const date = new Date();
52
- const intervalMs = interval * 1000;
53
- const dateWithTZ = date - date.getTimezoneOffset() * 1000 * 60;
54
- const offsetCur = dateWithTZ % intervalMs;
55
- // start every cron within 1 hour
56
- const sixtyMinutesStartMs = 3600000;
57
- const waitMs = (intervalMs - offsetCur) % sixtyMinutesStartMs;
58
- return [waitMs, intervalMs];
59
- },
60
- };
61
-
62
- async function runCron({
63
- func, name,
64
- }) {
65
- const pg = getPG();
66
-
67
- const unique = await verifyUnique(name);
68
-
69
- if (!unique) return;
70
- const db = pg.options.database;
3
+ import logger from '../../logger/getLogger.js';
4
+ import pgClients from '../../pg/pgClients.js';
71
5
 
72
- try {
73
- // console.log(`cron:${name}`);
74
- const data = await func({ pg });
75
- const subdir = !!data ? 'cron' : 'cron/null';
76
- logger.file(subdir, {
77
- db, name, result: data,
78
- });
79
- }
80
- catch (err) {
81
- logger.file('cron', {
82
- db, name, error: err.toString(),
83
- });
84
- logger.error(err);
85
- }
86
- }
6
+ import cronList from '../cronList.js';
7
+ import runCron from './runCron.js';
8
+ import interval2ms from './interval2ms.js';
87
9
 
88
10
  /**
89
11
  * interval:
@@ -97,7 +19,7 @@ async function runCron({
97
19
  * - 10 * 60 - every 10 minutes
98
20
  */
99
21
 
100
- export default async function addCron(func, interval) {
22
+ export default async function addCron(func, interval, pg = pgClients.client) {
101
23
  const { time = {}, disabled = [] } = config.cron || {};
102
24
 
103
25
  const name = func.name || func.toString().split('/').at(-1).split('\'')[0];
@@ -115,16 +37,16 @@ export default async function addCron(func, interval) {
115
37
  const [waitMs, intervalMs] = interval2ms[typeof interval](userInterval);
116
38
 
117
39
  if (intervalMs < 1000) {
118
- logger.file('cron', { name, error: `interval ${interval} to small` });
40
+ logger.file('cron', { name, error: `interval ${interval} too small` });
119
41
  return;
120
42
  }
121
43
 
122
44
  // setTimeout to w8 for the time to start
123
45
  setTimeout(() => {
124
- runCron({ func, name });
46
+ runCron({ pg, func, name });
125
47
  // interval
126
48
  setInterval(() => {
127
- runCron({ func, name });
49
+ runCron({ pg, func, name });
128
50
  }, intervalMs);
129
51
  }, waitMs);
130
52
  }
@@ -0,0 +1,40 @@
1
+ const intervalStringMs = {
2
+ everyMin: 1000 * 60,
3
+ tenMin: 1000 * 60 * 10,
4
+ everyHour: 1000 * 60 * 60,
5
+ isHalfday: 1000 * 60 * 60 * 12,
6
+ dailyHour: 1000 * 60 * 60 * 24,
7
+ };
8
+
9
+ const interval2ms = {
10
+ string: (interval) => {
11
+ const date = new Date();
12
+ const intervarSplit = interval.match(/^(\*{2}|(\*)?(\d{1,2})):(\*(\d)|(\d{2}))/);
13
+
14
+ if (!intervarSplit) {
15
+ throw new Error(`interval ${interval} not suported`);
16
+ }
17
+
18
+ const [, , isHalfday, dailyHour, , tenMin, HourlyMin] = intervarSplit;
19
+ const intervalMs = (isHalfday && intervalStringMs.isHalfday)
20
+ || (dailyHour && intervalStringMs.dailyHour)
21
+ || (tenMin && intervalStringMs.tenMin)
22
+ || intervalStringMs.everyHour;
23
+ const offsetDay = ((+dailyHour || 0) * 60 + (+tenMin || +HourlyMin)) * 60 * 1000;
24
+ const offsetCur = (date - date.getTimezoneOffset() * 1000 * 60) % intervalMs;
25
+ const waitMs = (offsetDay - offsetCur + intervalMs) % intervalMs;
26
+ return [waitMs, intervalMs];
27
+ },
28
+ number: (interval) => {
29
+ const date = new Date();
30
+ const intervalMs = interval * 1000;
31
+ const dateWithTZ = date - date.getTimezoneOffset() * 1000 * 60;
32
+ const offsetCur = dateWithTZ % intervalMs;
33
+ // start every cron within 1 hour
34
+ const sixtyMinutesStartMs = 3600000;
35
+ const waitMs = (intervalMs - offsetCur) % sixtyMinutesStartMs;
36
+ return [waitMs, intervalMs];
37
+ },
38
+ };
39
+
40
+ export default interval2ms;
@@ -0,0 +1,23 @@
1
+ import logger from '../../logger/getLogger.js';
2
+ import pgClients from '../../pg/pgClients.js';
3
+
4
+ import verifyUnique from './verifyUnique.js';
5
+
6
+ export default async function runCron({
7
+ pg = pgClients.client, func, name,
8
+ }) {
9
+ const unique = await verifyUnique(name);
10
+ if (!unique) return;
11
+
12
+ const db = pg.options.database;
13
+
14
+ try {
15
+ const data = await func({ pg });
16
+ const subdir = !!data ? 'cron' : 'cron/null';
17
+ logger.file(subdir, { db, name, result: data });
18
+ }
19
+ catch (err) {
20
+ logger.file('cron', { db, name, error: err.toString() });
21
+ logger.error(err);
22
+ }
23
+ }
@@ -0,0 +1,22 @@
1
+ import { createHash } from 'node:crypto';
2
+
3
+ import config from '../../../../config.js';
4
+
5
+ import getRedis from '../../redis/funcs/getRedis.js';
6
+
7
+ const md5 = (string) => createHash('md5').update(string).digest('hex');
8
+
9
+ const rclient = getRedis();
10
+
11
+ export default async function verifyUnique(name) {
12
+ const cronId = config.port || 3000 + md5(name);
13
+ // one per node check
14
+ const key = `cron:unique:${cronId}`;
15
+ const unique = await rclient.setnx(key, 1);
16
+ const ttl = await rclient.ttl(key);
17
+ if (!unique && ttl !== -1) {
18
+ return false;
19
+ }
20
+ await rclient.expire(key, 20);
21
+ return true;
22
+ }
@@ -1,6 +1,74 @@
1
- import addCron from './funcs/addCron.js';
1
+ import { createHash } from 'node:crypto';
2
+
3
+ import config from "../../../config.js";
4
+
5
+ import getPG from "../pg/funcs/getPG.js";
6
+ import pgClients from "../pg/pgClients.js";
7
+ import getRedis from '../redis/funcs/getRedis.js';
8
+ import logger from "../logger/getLogger.js";
9
+ import interval2ms from "./funcs/interval2ms.js";
10
+
11
+ const rclient = getRedis();
12
+
13
+ async function runCron({
14
+ pg = pgClients.client, query, name,
15
+ }) {
16
+ const db = pg.options.database;
17
+
18
+ // verifyUnique
19
+ const key = `cron:unique:${name}`;
20
+ const unique = await rclient.setnx(key, 1);
21
+ const ttl = await rclient.ttl(key);
22
+
23
+ if (!unique && ttl !== -1) {
24
+ // if (config.trace) console.log(name, db, query, 'skip unique');
25
+ return;
26
+ }
27
+
28
+ await rclient.expire(key, 20);
29
+
30
+ try {
31
+ if (!pg.pk) await pg.init();
32
+
33
+ if (config.trace) console.time(`${db}:${query}`);
34
+ const { command, rows = [], rowCount } = await pg.query(query);
35
+ if (config.trace) console.timeEnd(`${db}:${query}`);
36
+
37
+ logger.file('cron', { db, name, result: { command, rows, rowCount } });
38
+ }
39
+ catch (err) {
40
+ if (config.trace) console.error(name, err.toString());
41
+ logger.file('cron/error', { db, name, error: err.toString() });
42
+ logger.error(err);
43
+ }
44
+ }
2
45
 
3
46
  async function plugin(fastify) {
4
- // fastify.decorate('addCron', addCron);
47
+ if (config.cronList?.length) {
48
+ config.cronList?.filter(el => el.query && !el.disabled)?.forEach?.((el, idx) => {
49
+ const { interval, db, query } = el;
50
+ const name = createHash('md5').update(`${config.port || 3000}:${db}:${query}`).digest('hex');
51
+ const pg = getPG(db);
52
+
53
+ if (config.trace) console.log('cron-list: init', db, idx);
54
+
55
+ const [waitMs, intervalMs] = interval2ms[typeof interval](interval);
56
+
57
+ if (intervalMs < 1000) {
58
+ if (config.trace) console.error('cron-list: skip too small interval', db, idx);
59
+ logger.file('cron', { name, error: `interval ${interval} too small` });
60
+ return;
61
+ }
62
+
63
+ // setTimeout to w8 for the time to start
64
+ setTimeout(() => {
65
+ runCron({ pg, query, name });
66
+ // interval
67
+ setInterval(() => {
68
+ runCron({ pg, query, name });
69
+ }, intervalMs);
70
+ }, waitMs);
71
+ });
72
+ }
5
73
  }
6
74
  export default plugin;