@balena/pinejs 17.2.0-build-add-large-file-uploads-interfaces-971bf14a0a43ac87997af442136f384f224ba6d7-1 → 17.2.0-build-joshbwlng-tasks-b246a5244eeb1c020c533c54d6fb2f112a0ed972-1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. package/.pinejs-cache.json +1 -1
  2. package/.versionbot/CHANGELOG.yml +28 -4
  3. package/CHANGELOG.md +11 -1
  4. package/out/config-loader/env.d.ts +4 -0
  5. package/out/config-loader/env.js +5 -1
  6. package/out/config-loader/env.js.map +1 -1
  7. package/out/database-layer/db.d.ts +3 -0
  8. package/out/database-layer/db.js +17 -0
  9. package/out/database-layer/db.js.map +1 -1
  10. package/out/sbvr-api/sbvr-utils.d.ts +1 -0
  11. package/out/sbvr-api/sbvr-utils.js +3 -1
  12. package/out/sbvr-api/sbvr-utils.js.map +1 -1
  13. package/out/server-glue/module.d.ts +1 -0
  14. package/out/server-glue/module.js +4 -1
  15. package/out/server-glue/module.js.map +1 -1
  16. package/out/tasks/common.d.ts +4 -0
  17. package/out/tasks/common.js +11 -0
  18. package/out/tasks/common.js.map +1 -0
  19. package/out/tasks/index.d.ts +7 -0
  20. package/out/tasks/index.js +160 -0
  21. package/out/tasks/index.js.map +1 -0
  22. package/out/tasks/out.d.ts +40 -0
  23. package/out/tasks/out.js +3 -0
  24. package/out/tasks/out.js.map +1 -0
  25. package/out/tasks/tasks.sbvr +55 -0
  26. package/out/tasks/types.d.ts +40 -0
  27. package/out/tasks/types.js +3 -0
  28. package/out/tasks/types.js.map +1 -0
  29. package/out/tasks/worker.d.ts +32 -0
  30. package/out/tasks/worker.js +204 -0
  31. package/out/tasks/worker.js.map +1 -0
  32. package/out/webresource-handler/index.d.ts +0 -25
  33. package/out/webresource-handler/index.js +2 -3
  34. package/out/webresource-handler/index.js.map +1 -1
  35. package/package.json +9 -6
  36. package/src/config-loader/env.ts +6 -1
  37. package/src/database-layer/db.ts +25 -0
  38. package/src/sbvr-api/sbvr-utils.ts +2 -1
  39. package/src/server-glue/module.ts +3 -0
  40. package/src/tasks/common.ts +9 -0
  41. package/src/tasks/index.ts +176 -0
  42. package/src/tasks/out.ts +46 -0
  43. package/src/tasks/tasks.sbvr +55 -0
  44. package/src/tasks/types.ts +44 -0
  45. package/src/tasks/worker.ts +282 -0
  46. package/src/webresource-handler/index.ts +2 -38
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
26
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.config = void 0;
30
+ exports.setup = setup;
31
+ exports.addTaskHandler = addTaskHandler;
32
+ const cronParser = __importStar(require("cron-parser"));
33
+ const env_1 = require("../config-loader/env");
34
+ const errors_1 = require("../sbvr-api/errors");
35
+ const hooks_1 = require("../sbvr-api/hooks");
36
+ const sbvrUtils = __importStar(require("../sbvr-api/sbvr-utils"));
37
+ const common_1 = require("./common");
38
+ const worker_1 = require("./worker");
39
+ __exportStar(require("./types"), exports);
40
+ const modelText = require('./tasks.sbvr');
41
+ const initSql = `
42
+ CREATE OR REPLACE FUNCTION notify_task_insert()
43
+ RETURNS TRIGGER AS $$
44
+ BEGIN
45
+ PERFORM pg_notify('${common_1.channel}', NEW.id::text);
46
+ RETURN NEW;
47
+ END;
48
+ $$ LANGUAGE plpgsql;
49
+
50
+ CREATE OR REPLACE TRIGGER task_insert_trigger
51
+ AFTER INSERT ON task
52
+ FOR EACH ROW WHEN (NEW.status = 'queued' AND NEW."is scheduled to execute on-time" IS NULL)
53
+ EXECUTE FUNCTION notify_task_insert();
54
+
55
+ CREATE INDEX IF NOT EXISTS idx_task_poll ON task USING btree (
56
+ "is executed by-handler",
57
+ "is scheduled to execute on-time" ASC,
58
+ "id" ASC
59
+ ) WHERE status = 'queued';
60
+ `;
61
+ exports.config = {
62
+ models: [
63
+ {
64
+ modelName: common_1.apiRoot,
65
+ apiRoot: common_1.apiRoot,
66
+ modelText,
67
+ customServerCode: exports,
68
+ initSql,
69
+ },
70
+ ],
71
+ };
72
+ let worker = null;
73
+ async function setup() {
74
+ if (sbvrUtils.db.engine !== 'postgres') {
75
+ console.warn('Skipping task setup as database not supported');
76
+ return;
77
+ }
78
+ const client = sbvrUtils.api[common_1.apiRoot];
79
+ worker = new worker_1.Worker(client);
80
+ (0, hooks_1.addPureHook)('POST', common_1.apiRoot, 'task', {
81
+ POSTPARSE: async ({ req, request }) => {
82
+ request.values.is_created_by__actor =
83
+ req.user?.actor ?? req.apiKey?.actor;
84
+ if (request.values.is_created_by__actor == null) {
85
+ throw new errors_1.BadRequestError('Creating tasks with missing actor on req is not allowed');
86
+ }
87
+ request.values.status = 'queued';
88
+ request.values.attempt_count = 0;
89
+ request.values.attempt_limit ??= 1;
90
+ if (request.values.is_scheduled_with__cron_expression != null &&
91
+ request.values.is_scheduled_to_execute_on__time == null) {
92
+ try {
93
+ request.values.is_scheduled_to_execute_on__time = cronParser
94
+ .parseExpression(request.values.is_scheduled_with__cron_expression)
95
+ .next()
96
+ .toDate()
97
+ .toISOString();
98
+ }
99
+ catch {
100
+ throw new errors_1.BadRequestError(`Invalid cron expression: ${request.values.is_scheduled_with__cron_expression}`);
101
+ }
102
+ }
103
+ if (request.values.is_scheduled_to_execute_on__time != null) {
104
+ const now = new Date(Date.now() + env_1.tasks.queueIntervalMS);
105
+ const startTime = new Date(request.values.is_scheduled_to_execute_on__time);
106
+ if (startTime < now) {
107
+ throw new errors_1.BadRequestError(`Task scheduled start time must be greater than ${env_1.tasks.queueIntervalMS} milliseconds in the future`);
108
+ }
109
+ }
110
+ const handlerName = request.values.is_executed_by__handler;
111
+ if (handlerName == null) {
112
+ throw new errors_1.BadRequestError(`Must specify a task handler to execute`);
113
+ }
114
+ const handler = worker?.handlers[handlerName];
115
+ if (handler == null) {
116
+ throw new errors_1.BadRequestError(`No task handler with name '${handlerName}' registered`);
117
+ }
118
+ if (handler.validate != null) {
119
+ if (!handler.validate(request.values.is_executed_with__parameter_set)) {
120
+ throw new errors_1.BadRequestError(`Invalid parameter set: ${common_1.ajv.errorsText(handler.validate.errors)}`);
121
+ }
122
+ }
123
+ },
124
+ });
125
+ (0, hooks_1.addPureHook)('all', common_1.apiRoot, 'task', {
126
+ PRERESPOND: async ({ response }) => {
127
+ if (typeof response.body === 'object') {
128
+ convertBigIntsToStrings(response.body);
129
+ }
130
+ },
131
+ });
132
+ worker.start();
133
+ }
134
+ function convertBigIntsToStrings(obj) {
135
+ for (const [key, value] of Object.entries(obj)) {
136
+ if (value != null) {
137
+ const typeOfValue = typeof value;
138
+ if (typeOfValue === 'bigint') {
139
+ obj[key] = value.toString();
140
+ }
141
+ else if (typeOfValue === 'object') {
142
+ convertBigIntsToStrings(value);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ function addTaskHandler(name, fn, schema) {
148
+ if (worker == null) {
149
+ throw new Error('Database does not support tasks');
150
+ }
151
+ if (worker.handlers[name] != null) {
152
+ throw new Error(`Task handler with name '${name}' already registered`);
153
+ }
154
+ worker.handlers[name] = {
155
+ name,
156
+ fn,
157
+ validate: schema != null ? common_1.ajv.compile(schema) : undefined,
158
+ };
159
+ }
160
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tasks/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { Types } from '@balena/abstract-sql-to-typescript';
2
+ export interface Task {
3
+ Read: {
4
+ created_at: Types['Date Time']['Read'];
5
+ modified_at: Types['Date Time']['Read'];
6
+ id: Types['Big Serial']['Read'];
7
+ key: Types['Short Text']['Read'] | null;
8
+ is_created_by__actor: Types['Integer']['Read'];
9
+ is_executed_by__handler: Types['Short Text']['Read'];
10
+ is_executed_with__parameter_set: Types['JSON']['Read'] | null;
11
+ is_scheduled_with__cron_expression: Types['Short Text']['Read'] | null;
12
+ is_scheduled_to_execute_on__time: Types['Date Time']['Read'] | null;
13
+ status: 'queued' | 'cancelled' | 'succeeded' | 'failed';
14
+ started_on__time: Types['Date Time']['Read'] | null;
15
+ ended_on__time: Types['Date Time']['Read'] | null;
16
+ error_message: Types['Short Text']['Read'] | null;
17
+ attempt_count: Types['Integer']['Read'];
18
+ attempt_limit: Types['Integer']['Read'];
19
+ };
20
+ Write: {
21
+ created_at: Types['Date Time']['Write'];
22
+ modified_at: Types['Date Time']['Write'];
23
+ id: Types['Big Serial']['Write'];
24
+ key: Types['Short Text']['Write'] | null;
25
+ is_created_by__actor: Types['Integer']['Write'];
26
+ is_executed_by__handler: Types['Short Text']['Write'];
27
+ is_executed_with__parameter_set: Types['JSON']['Write'] | null;
28
+ is_scheduled_with__cron_expression: Types['Short Text']['Write'] | null;
29
+ is_scheduled_to_execute_on__time: Types['Date Time']['Write'] | null;
30
+ status: 'queued' | 'cancelled' | 'succeeded' | 'failed';
31
+ started_on__time: Types['Date Time']['Write'] | null;
32
+ ended_on__time: Types['Date Time']['Write'] | null;
33
+ error_message: Types['Short Text']['Write'] | null;
34
+ attempt_count: Types['Integer']['Write'];
35
+ attempt_limit: Types['Integer']['Write'];
36
+ };
37
+ }
38
+ export default interface $Model {
39
+ task: Task;
40
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=out.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"out.js","sourceRoot":"","sources":["../../src/tasks/out.ts"],"names":[],"mappings":""}
@@ -0,0 +1,55 @@
1
+ Vocabulary: tasks
2
+
3
+ Term: id
4
+ Concept Type: Big Serial (Type)
5
+ Term: actor
6
+ Concept Type: Integer (Type)
7
+ Term: attempt count
8
+ Concept Type: Integer (Type)
9
+ Term: attempt limit
10
+ Concept Type: Integer (Type)
11
+ Term: cron expression
12
+ Concept Type: Short Text (Type)
13
+ Term: error message
14
+ Concept Type: Short Text (Type)
15
+ Term: handler
16
+ Concept Type: Short Text (Type)
17
+ Term: key
18
+ Concept Type: Short Text (Type)
19
+ Term: parameter set
20
+ Concept Type: JSON (Type)
21
+ Term: status
22
+ Concept Type: Short Text (Type)
23
+ Term: time
24
+ Concept Type: Date Time (Type)
25
+
26
+ Term: task
27
+ Fact type: task has id
28
+ Necessity: each task has exactly one id
29
+ Fact type: task has key
30
+ Necessity: each task has at most one key
31
+ Fact type: task is created by actor
32
+ Necessity: each task is created by exactly one actor
33
+ Fact type: task is executed by handler
34
+ Necessity: each task is executed by exactly one handler
35
+ Fact type: task is executed with parameter set
36
+ Necessity: each task is executed with at most one parameter set
37
+ Fact type: task is scheduled with cron expression
38
+ Necessity: each task is scheduled with at most one cron expression
39
+ Fact type: task is scheduled to execute on time
40
+ Necessity: each task is scheduled to execute on at most one time
41
+ Fact type: task has status
42
+ Necessity: each task has exactly one status
43
+ Definition: "queued" or "cancelled" or "succeeded" or "failed"
44
+ Fact type: task started on time
45
+ Necessity: each task started on at most one time
46
+ Fact type: task ended on time
47
+ Necessity: each task ended on at most one time
48
+ Fact type: task has error message
49
+ Necessity: each task has at most one error message
50
+ Fact type: task has attempt count
51
+ Necessity: each task has exactly one attempt count
52
+ Fact type: task has attempt limit
53
+ Necessity: each task has exactly one attempt limit
54
+ Necessity: each task has an attempt limit that is greater than or equal to 1
55
+
@@ -0,0 +1,40 @@
1
+ import type { Types } from '@balena/abstract-sql-to-typescript';
2
+ export interface Task {
3
+ Read: {
4
+ created_at: Types['Date Time']['Read'];
5
+ modified_at: Types['Date Time']['Read'];
6
+ id: Types['Big Serial']['Read'];
7
+ key: Types['Short Text']['Read'] | null;
8
+ is_created_by__actor: Types['Integer']['Read'];
9
+ is_executed_by__handler: Types['Short Text']['Read'];
10
+ is_executed_with__parameter_set: Types['JSON']['Read'] | null;
11
+ is_scheduled_with__cron_expression: Types['Short Text']['Read'] | null;
12
+ is_scheduled_to_execute_on__time: Types['Date Time']['Read'] | null;
13
+ status: 'queued' | 'cancelled' | 'succeeded' | 'failed';
14
+ started_on__time: Types['Date Time']['Read'] | null;
15
+ ended_on__time: Types['Date Time']['Read'] | null;
16
+ error_message: Types['Short Text']['Read'] | null;
17
+ attempt_count: Types['Integer']['Read'];
18
+ attempt_limit: Types['Integer']['Read'];
19
+ };
20
+ Write: {
21
+ created_at: Types['Date Time']['Write'];
22
+ modified_at: Types['Date Time']['Write'];
23
+ id: Types['Big Serial']['Write'];
24
+ key: Types['Short Text']['Write'] | null;
25
+ is_created_by__actor: Types['Integer']['Write'];
26
+ is_executed_by__handler: Types['Short Text']['Write'];
27
+ is_executed_with__parameter_set: Types['JSON']['Write'] | null;
28
+ is_scheduled_with__cron_expression: Types['Short Text']['Write'] | null;
29
+ is_scheduled_to_execute_on__time: Types['Date Time']['Write'] | null;
30
+ status: 'queued' | 'cancelled' | 'succeeded' | 'failed';
31
+ started_on__time: Types['Date Time']['Write'] | null;
32
+ ended_on__time: Types['Date Time']['Write'] | null;
33
+ error_message: Types['Short Text']['Write'] | null;
34
+ attempt_count: Types['Integer']['Write'];
35
+ attempt_limit: Types['Integer']['Write'];
36
+ };
37
+ }
38
+ export default interface $Model {
39
+ task: Task;
40
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tasks/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,32 @@
1
+ import type { ValidateFunction } from 'ajv';
2
+ import type { AnyObject } from 'pinejs-client-core';
3
+ import { PinejsClient } from '../sbvr-api/sbvr-utils';
4
+ import type { Task } from './types';
5
+ interface TaskArgs {
6
+ api: PinejsClient;
7
+ params: AnyObject;
8
+ }
9
+ type TaskResponse = Promise<{
10
+ status: Task['Read']['status'];
11
+ error?: string;
12
+ }>;
13
+ export interface TaskHandler {
14
+ name: string;
15
+ fn: (options: TaskArgs) => TaskResponse;
16
+ validate?: ValidateFunction;
17
+ }
18
+ export declare class Worker {
19
+ private readonly client;
20
+ handlers: Record<string, TaskHandler>;
21
+ private readonly concurrency;
22
+ private readonly interval;
23
+ private executing;
24
+ constructor(client: PinejsClient);
25
+ private canExecute;
26
+ private execute;
27
+ private update;
28
+ private getNextAttemptTime;
29
+ private poll;
30
+ start(): void;
31
+ }
32
+ export {};
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.Worker = void 0;
27
+ const promises_1 = require("node:timers/promises");
28
+ const env_1 = require("../config-loader/env");
29
+ const permissions = __importStar(require("../sbvr-api/permissions"));
30
+ const sbvr_utils_1 = require("../sbvr-api/sbvr-utils");
31
+ const module_1 = require("../server-glue/module");
32
+ const common_1 = require("./common");
33
+ const selectColumns = Object.entries({
34
+ id: 'id',
35
+ 'is executed by-handler': 'is_executed_by__handler',
36
+ 'is executed with-parameter set': 'is_executed_with__parameter_set',
37
+ 'is scheduled with-cron expression': 'is_scheduled_with__cron_expression',
38
+ 'attempt count': 'attempt_count',
39
+ 'attempt limit': 'attempt_limit',
40
+ 'is created by-actor': 'is_created_by__actor',
41
+ })
42
+ .map(([key, value]) => `t."${key}" AS "${value}"`)
43
+ .join(', ');
44
+ class Worker {
45
+ client;
46
+ handlers = {};
47
+ concurrency;
48
+ interval;
49
+ executing = 0;
50
+ constructor(client) {
51
+ this.client = client;
52
+ this.concurrency = env_1.tasks.queueConcurrency;
53
+ this.interval = env_1.tasks.queueIntervalMS;
54
+ }
55
+ canExecute() {
56
+ return (this.executing < this.concurrency && Object.keys(this.handlers).length > 0);
57
+ }
58
+ async execute(task, tx) {
59
+ this.executing++;
60
+ try {
61
+ const handler = this.handlers[task.is_executed_by__handler];
62
+ const startedOnTime = new Date();
63
+ if (handler == null) {
64
+ await this.update(tx, task, startedOnTime, 'failed', 'Matching task handler not found');
65
+ return;
66
+ }
67
+ if (handler.validate != null &&
68
+ !handler.validate(task.is_executed_with__parameter_set)) {
69
+ await this.update(tx, task, startedOnTime, 'failed', `Invalid parameter set: ${common_1.ajv.errorsText(handler.validate.errors)}`);
70
+ return;
71
+ }
72
+ let status = 'queued';
73
+ let error;
74
+ try {
75
+ const results = await handler.fn({
76
+ api: new sbvr_utils_1.PinejsClient({}),
77
+ params: task.is_executed_with__parameter_set ?? {},
78
+ });
79
+ status = results.status;
80
+ error = results.error;
81
+ }
82
+ finally {
83
+ await this.update(tx, task, startedOnTime, status, error);
84
+ }
85
+ }
86
+ catch (err) {
87
+ console.error(`Failed to execute task ${task.id} with handler ${task.is_executed_by__handler}:`, err);
88
+ process.exit(1);
89
+ }
90
+ finally {
91
+ this.executing--;
92
+ }
93
+ }
94
+ async update(tx, task, startedOnTime, status, errorMessage) {
95
+ const attemptCount = task.attempt_count + 1;
96
+ const body = {
97
+ started_on__time: startedOnTime,
98
+ ended_on__time: new Date(),
99
+ status,
100
+ attempt_count: attemptCount,
101
+ ...(errorMessage != null && { error_message: errorMessage }),
102
+ };
103
+ if (status === 'failed' && attemptCount < task.attempt_limit) {
104
+ body.status = 'queued';
105
+ body.is_scheduled_to_execute_on__time =
106
+ this.getNextAttemptTime(attemptCount);
107
+ }
108
+ await this.client.patch({
109
+ resource: 'task',
110
+ passthrough: {
111
+ tx,
112
+ req: permissions.root,
113
+ },
114
+ id: task.id,
115
+ body,
116
+ });
117
+ if (['failed', 'succeeded'].includes(body.status) &&
118
+ task.is_scheduled_with__cron_expression != null) {
119
+ await this.client.post({
120
+ resource: 'task',
121
+ passthrough: {
122
+ tx,
123
+ req: permissions.root,
124
+ },
125
+ options: {
126
+ returnResource: false,
127
+ },
128
+ body: {
129
+ attempt_limit: task.attempt_limit,
130
+ is_created_by__actor: task.is_created_by__actor,
131
+ is_executed_by__handler: task.is_executed_by__handler,
132
+ is_executed_with__parameter_set: task.is_executed_with__parameter_set,
133
+ is_scheduled_with__cron_expression: task.is_scheduled_with__cron_expression,
134
+ },
135
+ });
136
+ }
137
+ }
138
+ getNextAttemptTime(attempt) {
139
+ const delay = Math.ceil(Math.exp(Math.min(10, attempt)));
140
+ return new Date(Date.now() + delay);
141
+ }
142
+ poll() {
143
+ let executed = false;
144
+ void (async () => {
145
+ try {
146
+ if (!this.canExecute()) {
147
+ return;
148
+ }
149
+ const handlerNames = Object.keys(this.handlers);
150
+ await module_1.sbvrUtils.db.transaction(async (tx) => {
151
+ const result = await module_1.sbvrUtils.db.executeSql(`SELECT ${selectColumns}
152
+ FROM task AS t
153
+ WHERE
154
+ t."is executed by-handler" IN (${handlerNames.map((_, index) => `$${index + 1}`).join(', ')}) AND
155
+ t."status" = 'queued' AND
156
+ t."attempt count" <= t."attempt limit" AND
157
+ (
158
+ t."is scheduled to execute on-time" IS NULL OR
159
+ t."is scheduled to execute on-time" <= CURRENT_TIMESTAMP + $${handlerNames.length + 1} * INTERVAL '1 SECOND'
160
+ )
161
+ ORDER BY
162
+ t."is scheduled to execute on-time" ASC,
163
+ t."id" ASC
164
+ LIMIT 1 FOR UPDATE SKIP LOCKED`, [...handlerNames, Math.ceil(this.interval / 1000)]);
165
+ if (result.rows.length > 0) {
166
+ await this.execute(result.rows[0], tx);
167
+ executed = true;
168
+ }
169
+ });
170
+ }
171
+ catch (err) {
172
+ console.error('Failed polling for tasks:', err);
173
+ }
174
+ finally {
175
+ if (!executed) {
176
+ await (0, promises_1.setTimeout)(this.interval);
177
+ }
178
+ this.poll();
179
+ }
180
+ })();
181
+ }
182
+ start() {
183
+ if (module_1.sbvrUtils.db.engine !== 'postgres' || module_1.sbvrUtils.db.on == null) {
184
+ throw new Error('Database does not support tasks, giving up on starting worker');
185
+ }
186
+ module_1.sbvrUtils.db.on('notification', async (msg) => {
187
+ if (this.canExecute()) {
188
+ await module_1.sbvrUtils.db.transaction(async (tx) => {
189
+ const result = await module_1.sbvrUtils.db.executeSql(`SELECT ${selectColumns} FROM task AS t WHERE id = $1 FOR UPDATE SKIP LOCKED`, [msg.payload]);
190
+ if (result.rows.length > 0) {
191
+ await this.execute(result.rows[0], tx);
192
+ }
193
+ });
194
+ }
195
+ }, {
196
+ channel: common_1.channel,
197
+ });
198
+ for (let i = 0; i < this.concurrency; i++) {
199
+ this.poll();
200
+ }
201
+ }
202
+ }
203
+ exports.Worker = Worker;
204
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/tasks/worker.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import type * as Express from 'express';
2
2
  import type * as stream from 'node:stream';
3
- import type { AnyObject } from '../sbvr-api/common-types';
4
3
  import type { WebResourceType as WebResource } from '@balena/sbvr-types';
5
4
  import { TypedError } from 'typed-error';
6
5
  export * from './handlers';
@@ -15,34 +14,10 @@ export interface UploadResponse {
15
14
  size: number;
16
15
  filename: string;
17
16
  }
18
- export interface BeginMultipartUploadPayload {
19
- filename: string;
20
- content_type: string;
21
- size: number;
22
- chunk_size: number;
23
- }
24
- export interface UploadPart {
25
- url: string;
26
- chunkSize: number;
27
- partNumber: number;
28
- }
29
- export interface BeginMultipartUploadHandlerResponse {
30
- uploadParts: UploadPart[];
31
- fileKey: string;
32
- uploadId: string;
33
- }
34
- export interface CommitMultipartUploadPayload {
35
- fileKey: string;
36
- uploadId: string;
37
- filename: string;
38
- providerCommitData?: AnyObject;
39
- }
40
17
  export interface WebResourceHandler {
41
18
  handleFile: (resource: IncomingFile) => Promise<UploadResponse>;
42
19
  removeFile: (fileReference: string) => Promise<void>;
43
20
  onPreRespond: (webResource: WebResource) => Promise<WebResource>;
44
- beginMultipartUpload?: (fieldName: string, payload: BeginMultipartUploadPayload) => Promise<BeginMultipartUploadHandlerResponse>;
45
- commitMultipartUpload?: (commitInfo: CommitMultipartUploadPayload) => Promise<WebResource>;
46
21
  }
47
22
  export declare class WebResourceError extends TypedError {
48
23
  }
@@ -211,10 +211,9 @@ const getCreateWebResourceHooks = (webResourceHandler) => {
211
211
  },
212
212
  };
213
213
  };
214
- const isDefined = (x) => x != null;
215
214
  const getWebResourcesHrefs = (webResources) => {
216
215
  const hrefs = (webResources ?? []).flatMap((resource) => Object.values(resource ?? {})
217
- .filter(isDefined)
216
+ .filter((resourceKey) => resourceKey != null)
218
217
  .map((resourceKey) => (0, exports.normalizeHref)(resourceKey.href)));
219
218
  return hrefs;
220
219
  };
@@ -225,7 +224,7 @@ exports.normalizeHref = normalizeHref;
225
224
  const getWebResourcesKeysFromRequest = (webResourceFields, { values }) => {
226
225
  return webResourceFields
227
226
  .map((field) => values[field]?.href)
228
- .filter(isDefined);
227
+ .filter((href) => href != null);
229
228
  };
230
229
  const getRemoveWebResourceHooks = (webResourceHandler) => {
231
230
  return {