@sqlane/core 0.1.0 → 0.1.2
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 +10 -0
- package/package.json +20 -5
- package/src/create_sqlane.js +1 -0
- package/src/runner.js +137 -22
- package/src/store/mysql_final.js +23 -9
- package/src/store/postgres_final.js +27 -17
- package/src/store/store.js +7 -2
- package/types/adapters/mysql2.d.ts +13 -0
- package/types/adapters/pg.d.ts +16 -0
- package/types/backoff.d.ts +8 -0
- package/types/create_sqlane.d.ts +8 -0
- package/types/defaults.d.ts +18 -0
- package/types/define_job.d.ts +6 -0
- package/types/duration.d.ts +7 -0
- package/types/enqueue.d.ts +50 -0
- package/types/error_json.d.ts +21 -0
- package/types/errors.d.ts +129 -0
- package/types/hint_channel.d.ts +31 -0
- package/types/index.d.ts +72 -0
- package/types/migrations.d.ts +22 -0
- package/types/mutex_keys.d.ts +9 -0
- package/types/new_job.d.ts +40 -0
- package/types/payload.d.ts +10 -0
- package/types/registry.d.ts +72 -0
- package/types/runner.d.ts +92 -0
- package/types/schema/mysql.d.ts +10 -0
- package/types/schema/postgres.d.ts +10 -0
- package/types/store/mysql_enqueue.d.ts +9 -0
- package/types/store/mysql_final.d.ts +135 -0
- package/types/store/mysql_worker.d.ts +51 -0
- package/types/store/postgres_enqueue.d.ts +9 -0
- package/types/store/postgres_final.d.ts +135 -0
- package/types/store/postgres_worker.d.ts +45 -0
- package/types/store/store.d.ts +221 -0
- package/types/transient_error.d.ts +6 -0
- package/types/types.d.ts +651 -0
- package/types/validate.d.ts +76 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The base of the errors of sqlane.
|
|
3
|
+
*/
|
|
4
|
+
export declare class SqlaneError extends Error {
|
|
5
|
+
/** @readonly */
|
|
6
|
+
code: string;
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} code A stable code, e.g. `CONFIG`.
|
|
9
|
+
* @param {string} message
|
|
10
|
+
* @param {ErrorOptions} [options]
|
|
11
|
+
*/
|
|
12
|
+
constructor(code: string, message: string, options?: ErrorOptions);
|
|
13
|
+
}
|
|
14
|
+
/** Bad `createSqlane`, `defineJob` or `handle()` options. */
|
|
15
|
+
export declare class ConfigError extends SqlaneError {
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} message
|
|
18
|
+
* @param {ErrorOptions} [options]
|
|
19
|
+
*/
|
|
20
|
+
constructor(message: string, options?: ErrorOptions);
|
|
21
|
+
}
|
|
22
|
+
/** Bad enqueue options: a bad name or `jobId`, `delay` with `runAt`. */
|
|
23
|
+
export declare class InvalidOptionsError extends SqlaneError {
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} message
|
|
26
|
+
* @param {ErrorOptions} [options]
|
|
27
|
+
*/
|
|
28
|
+
constructor(message: string, options?: ErrorOptions);
|
|
29
|
+
}
|
|
30
|
+
/** The payload is above `maxPayloadBytes`. */
|
|
31
|
+
export declare class PayloadTooLargeError extends SqlaneError {
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} message
|
|
34
|
+
* @param {ErrorOptions} [options]
|
|
35
|
+
*/
|
|
36
|
+
constructor(message: string, options?: ErrorOptions);
|
|
37
|
+
}
|
|
38
|
+
/** More than 10 mutex keys, or a key that breaks the rules. */
|
|
39
|
+
export declare class InvalidMutexKeyError extends SqlaneError {
|
|
40
|
+
/**
|
|
41
|
+
* @param {string} message
|
|
42
|
+
* @param {ErrorOptions} [options]
|
|
43
|
+
*/
|
|
44
|
+
constructor(message: string, options?: ErrorOptions);
|
|
45
|
+
}
|
|
46
|
+
/** Enqueue of an unknown name with `unknownJobs: 'reject'`. */
|
|
47
|
+
export declare class UnknownJobError extends SqlaneError {
|
|
48
|
+
/**
|
|
49
|
+
* @param {string} message
|
|
50
|
+
* @param {ErrorOptions} [options]
|
|
51
|
+
*/
|
|
52
|
+
constructor(message: string, options?: ErrorOptions);
|
|
53
|
+
}
|
|
54
|
+
/** `start`, `handle` or `drain` after `close()`. */
|
|
55
|
+
export declare class ClosedError extends SqlaneError {
|
|
56
|
+
/**
|
|
57
|
+
* @param {string} message
|
|
58
|
+
* @param {ErrorOptions} [options]
|
|
59
|
+
*/
|
|
60
|
+
constructor(message: string, options?: ErrorOptions);
|
|
61
|
+
}
|
|
62
|
+
/** `drain()` did not finish in its `timeout`. */
|
|
63
|
+
export declare class DrainTimeoutError extends SqlaneError {
|
|
64
|
+
/**
|
|
65
|
+
* @param {string} message
|
|
66
|
+
* @param {ErrorOptions} [options]
|
|
67
|
+
*/
|
|
68
|
+
constructor(message: string, options?: ErrorOptions);
|
|
69
|
+
}
|
|
70
|
+
/** The `signal.reason` on a timeout; the error of the attempt. */
|
|
71
|
+
export declare class JobTimeoutError extends SqlaneError {
|
|
72
|
+
/**
|
|
73
|
+
* @param {string} message
|
|
74
|
+
* @param {ErrorOptions} [options]
|
|
75
|
+
*/
|
|
76
|
+
constructor(message: string, options?: ErrorOptions);
|
|
77
|
+
}
|
|
78
|
+
/** The `signal.reason` at the close deadline. */
|
|
79
|
+
export declare class ShutdownError extends SqlaneError {
|
|
80
|
+
/**
|
|
81
|
+
* @param {string} message
|
|
82
|
+
* @param {ErrorOptions} [options]
|
|
83
|
+
*/
|
|
84
|
+
constructor(message: string, options?: ErrorOptions);
|
|
85
|
+
}
|
|
86
|
+
/** The `signal.reason` when the lease could not be renewed in time. */
|
|
87
|
+
export declare class LeaseLostError extends SqlaneError {
|
|
88
|
+
/**
|
|
89
|
+
* @param {string} message
|
|
90
|
+
* @param {ErrorOptions} [options]
|
|
91
|
+
*/
|
|
92
|
+
constructor(message: string, options?: ErrorOptions);
|
|
93
|
+
}
|
|
94
|
+
/** The error of a job without its payload. */
|
|
95
|
+
export declare class MissingPayloadError extends SqlaneError {
|
|
96
|
+
/**
|
|
97
|
+
* @param {string} message
|
|
98
|
+
* @param {ErrorOptions} [options]
|
|
99
|
+
*/
|
|
100
|
+
constructor(message: string, options?: ErrorOptions);
|
|
101
|
+
}
|
|
102
|
+
/** Thrown by a handler: the job fails at once, without retries; its failure job runs. */
|
|
103
|
+
export declare class FatalJobError extends SqlaneError {
|
|
104
|
+
/**
|
|
105
|
+
* @param {string} message
|
|
106
|
+
* @param {ErrorOptions} [options]
|
|
107
|
+
*/
|
|
108
|
+
constructor(message: string, options?: ErrorOptions);
|
|
109
|
+
}
|
|
110
|
+
/** Thrown by a handler: the job is retried after `delay` instead of the backoff. It still uses an attempt. */
|
|
111
|
+
export declare class RetryJobError extends SqlaneError {
|
|
112
|
+
/** @readonly */
|
|
113
|
+
delay: import("./types.js").Duration;
|
|
114
|
+
/**
|
|
115
|
+
* @param {string} message
|
|
116
|
+
* @param {ErrorOptions & { delay: import('./types.js').Duration }} options
|
|
117
|
+
*/
|
|
118
|
+
constructor(message: string, options: ErrorOptions & {
|
|
119
|
+
delay: import('./types.js').Duration;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/** `migrate()` did not get the migration lock in its `lockTimeout`. */
|
|
123
|
+
export declare class MigrationLockTimeoutError extends SqlaneError {
|
|
124
|
+
/**
|
|
125
|
+
* @param {string} message
|
|
126
|
+
* @param {ErrorOptions} [options]
|
|
127
|
+
*/
|
|
128
|
+
constructor(message: string, options?: ErrorOptions);
|
|
129
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** The message after a release of mutex keys: every process probes all its names */
|
|
2
|
+
export declare const ANY_NAME = "*";
|
|
3
|
+
export type HintChannel = {
|
|
4
|
+
/**
|
|
5
|
+
* Fire-and-forget: never throws, never waits.
|
|
6
|
+
*/
|
|
7
|
+
publish: (name: string) => void;
|
|
8
|
+
listen: (onMessage: (name: string) => void) => Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Stops listening; drops the pending messages.
|
|
11
|
+
*/
|
|
12
|
+
stop: () => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {object} HintChannel
|
|
16
|
+
* @property {(name: string) => void} publish Fire-and-forget: never throws, never waits.
|
|
17
|
+
* @property {(onMessage: (name: string) => void) => Promise<void>} listen
|
|
18
|
+
* @property {() => Promise<void>} stop Stops listening; drops the pending messages.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* @param {object} params
|
|
22
|
+
* @param {import('./types.js').Hint | null} params.hint
|
|
23
|
+
* @param {string} params.channel
|
|
24
|
+
* @param {(operation: string, error: unknown) => void} params.reportError
|
|
25
|
+
* @returns {HintChannel}
|
|
26
|
+
*/
|
|
27
|
+
export declare function createHintChannel({ hint, channel, reportError }: {
|
|
28
|
+
hint: import('./types.js').Hint | null;
|
|
29
|
+
channel: string;
|
|
30
|
+
reportError: (operation: string, error: unknown) => void;
|
|
31
|
+
}): HintChannel;
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export { createSqlane } from './create_sqlane.js';
|
|
2
|
+
export { defineJob } from './define_job.js';
|
|
3
|
+
export { ClosedError, ConfigError, DrainTimeoutError, FatalJobError, InvalidMutexKeyError, InvalidOptionsError, JobTimeoutError, LeaseLostError, MigrationLockTimeoutError, MissingPayloadError, PayloadTooLargeError, RetryJobError, ShutdownError, SqlaneError, UnknownJobError, } from './errors.js';
|
|
4
|
+
export { getMigrations } from './migrations.js';
|
|
5
|
+
export type Adapter<C> = import('./types.js').Adapter<C>;
|
|
6
|
+
export type Sqlane<C, L extends string> = import('./types.js').Sqlane<C, L>;
|
|
7
|
+
export type SqlaneOptions<C, L extends string> = import('./types.js').SqlaneOptions<C, L>;
|
|
8
|
+
export type Jsonable<T> = import('./types.js').Jsonable<T>;
|
|
9
|
+
export type Backoff = import('./types.js').Backoff;
|
|
10
|
+
export type CloseOptions = import('./types.js').CloseOptions;
|
|
11
|
+
export type DrainOptions = import('./types.js').DrainOptions;
|
|
12
|
+
export type DrainResult = import('./types.js').DrainResult;
|
|
13
|
+
export type Duration = import('./types.js').Duration;
|
|
14
|
+
export type EnqueueOptions = import('./types.js').EnqueueOptions;
|
|
15
|
+
export type EnqueueResult = import('./types.js').EnqueueResult;
|
|
16
|
+
export type Executor = import('./types.js').Executor;
|
|
17
|
+
export type FailedJobPayload = import('./types.js').FailedJobPayload;
|
|
18
|
+
export type Handler = import('./types.js').Handler;
|
|
19
|
+
export type HandlerContext = import('./types.js').HandlerContext;
|
|
20
|
+
export type Hint = import('./types.js').Hint;
|
|
21
|
+
export type JobDefaults = import('./types.js').JobDefaults;
|
|
22
|
+
export type JobDefinition = import('./types.js').JobDefinition;
|
|
23
|
+
export type JobInfo = import('./types.js').JobInfo;
|
|
24
|
+
export type JobOptions = import('./types.js').JobOptions;
|
|
25
|
+
export type JobStats = import('./types.js').JobStats;
|
|
26
|
+
export type LaneOptions = import('./types.js').LaneOptions;
|
|
27
|
+
export type Logger = import('./types.js').Logger;
|
|
28
|
+
export type MigrateOptions = import('./types.js').MigrateOptions;
|
|
29
|
+
export type Migration = import('./types.js').Migration;
|
|
30
|
+
export type Retention = import('./types.js').Retention;
|
|
31
|
+
export type SqlaneEvent = import('./types.js').SqlaneEvent;
|
|
32
|
+
/**
|
|
33
|
+
* @typedef {import('./types.js').Adapter<C>} Adapter
|
|
34
|
+
* @template C
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* @typedef {import('./types.js').Sqlane<C, L>} Sqlane
|
|
38
|
+
* @template C
|
|
39
|
+
* @template {string} L
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* @typedef {import('./types.js').SqlaneOptions<C, L>} SqlaneOptions
|
|
43
|
+
* @template C
|
|
44
|
+
* @template {string} L
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* @typedef {import('./types.js').Jsonable<T>} Jsonable
|
|
48
|
+
* @template T
|
|
49
|
+
*/
|
|
50
|
+
/** @typedef {import('./types.js').Backoff} Backoff */
|
|
51
|
+
/** @typedef {import('./types.js').CloseOptions} CloseOptions */
|
|
52
|
+
/** @typedef {import('./types.js').DrainOptions} DrainOptions */
|
|
53
|
+
/** @typedef {import('./types.js').DrainResult} DrainResult */
|
|
54
|
+
/** @typedef {import('./types.js').Duration} Duration */
|
|
55
|
+
/** @typedef {import('./types.js').EnqueueOptions} EnqueueOptions */
|
|
56
|
+
/** @typedef {import('./types.js').EnqueueResult} EnqueueResult */
|
|
57
|
+
/** @typedef {import('./types.js').Executor} Executor */
|
|
58
|
+
/** @typedef {import('./types.js').FailedJobPayload} FailedJobPayload */
|
|
59
|
+
/** @typedef {import('./types.js').Handler} Handler */
|
|
60
|
+
/** @typedef {import('./types.js').HandlerContext} HandlerContext */
|
|
61
|
+
/** @typedef {import('./types.js').Hint} Hint */
|
|
62
|
+
/** @typedef {import('./types.js').JobDefaults} JobDefaults */
|
|
63
|
+
/** @typedef {import('./types.js').JobDefinition} JobDefinition */
|
|
64
|
+
/** @typedef {import('./types.js').JobInfo} JobInfo */
|
|
65
|
+
/** @typedef {import('./types.js').JobOptions} JobOptions */
|
|
66
|
+
/** @typedef {import('./types.js').JobStats} JobStats */
|
|
67
|
+
/** @typedef {import('./types.js').LaneOptions} LaneOptions */
|
|
68
|
+
/** @typedef {import('./types.js').Logger} Logger */
|
|
69
|
+
/** @typedef {import('./types.js').MigrateOptions} MigrateOptions */
|
|
70
|
+
/** @typedef {import('./types.js').Migration} Migration */
|
|
71
|
+
/** @typedef {import('./types.js').Retention} Retention */
|
|
72
|
+
/** @typedef {import('./types.js').SqlaneEvent} SqlaneEvent */
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type Executor = import('./types.js').Executor;
|
|
2
|
+
/** @typedef {import('./types.js').Executor} Executor */
|
|
3
|
+
/**
|
|
4
|
+
* The schema of sqlane as versioned SQL, for the app's own migration tool.
|
|
5
|
+
* @param {object} options
|
|
6
|
+
* @param {'mysql' | 'postgres'} options.dialect
|
|
7
|
+
* @param {string} [options.tablePrefix] Default: `'sqlane_'`.
|
|
8
|
+
* @returns {import('./types.js').Migration[]}
|
|
9
|
+
*/
|
|
10
|
+
export declare function getMigrations({ dialect, tablePrefix }: {
|
|
11
|
+
dialect: 'mysql' | 'postgres';
|
|
12
|
+
tablePrefix?: string;
|
|
13
|
+
}): import('./types.js').Migration[];
|
|
14
|
+
/**
|
|
15
|
+
* Applies the missing migrations under a DB lock, on a connection of its own, without a statement timeout.
|
|
16
|
+
* @template C
|
|
17
|
+
* @param {import('./types.js').Adapter<C>} adapter
|
|
18
|
+
* @param {string} tablePrefix Checked.
|
|
19
|
+
* @param {import('./types.js').MigrateOptions} [options]
|
|
20
|
+
* @returns {Promise<string[]>} The ids of the applied migrations.
|
|
21
|
+
*/
|
|
22
|
+
export declare function runMigrations<C>(adapter: import('./types.js').Adapter<C>, tablePrefix: string, options?: import('./types.js').MigrateOptions): Promise<string[]>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const MAX_MUTEX_KEYS = 10;
|
|
2
|
+
export declare const MAX_MUTEX_KEY_LENGTH = 255;
|
|
3
|
+
/**
|
|
4
|
+
* Checks the mutex keys of a job.
|
|
5
|
+
* @param {unknown} keys
|
|
6
|
+
* @param {string} where For the error message.
|
|
7
|
+
* @returns {string[]} The keys without duplicates, sorted (the lock order).
|
|
8
|
+
*/
|
|
9
|
+
export declare function normalizeMutexKeys(keys: unknown, where: string): string[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type NewJob = {
|
|
2
|
+
/**
|
|
3
|
+
* `<name>:<jobId>`, or a ULID.
|
|
4
|
+
*/
|
|
5
|
+
id: string;
|
|
6
|
+
hasJobId: boolean;
|
|
7
|
+
name: string;
|
|
8
|
+
payloadJson: string;
|
|
9
|
+
/**
|
|
10
|
+
* Sorted, without duplicates.
|
|
11
|
+
*/
|
|
12
|
+
mutexKeys: readonly string[];
|
|
13
|
+
maxAttempts: number;
|
|
14
|
+
maxStalls: number;
|
|
15
|
+
completedRetentionMs: number;
|
|
16
|
+
failedRetentionMs: number;
|
|
17
|
+
failureJob: string | null;
|
|
18
|
+
/**
|
|
19
|
+
* From the DB clock at insert. 0 with `runAt`.
|
|
20
|
+
*/
|
|
21
|
+
delayMs: number;
|
|
22
|
+
runAt: Date | null;
|
|
23
|
+
};
|
|
24
|
+
export type NewJobParams = {
|
|
25
|
+
name: string;
|
|
26
|
+
/**
|
|
27
|
+
* Null: an unknown name, the defaults only.
|
|
28
|
+
*/
|
|
29
|
+
definition: import('./types.js').JobDefinition | null;
|
|
30
|
+
defaults: import('./defaults.js').ResolvedDefaults;
|
|
31
|
+
payload: unknown;
|
|
32
|
+
options: import('./types.js').EnqueueOptions | undefined;
|
|
33
|
+
maxPayloadBytes: number;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Checks an enqueue and computes the job to insert: options, then the definition, then the defaults.
|
|
37
|
+
* @param {NewJobParams} params
|
|
38
|
+
* @returns {NewJob}
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildNewJob({ name, definition, defaults, payload, options, maxPayloadBytes }: NewJobParams): NewJob;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const DEFAULT_MAX_PAYLOAD_BYTES: number;
|
|
2
|
+
/**
|
|
3
|
+
* Serializes a payload: JSON, well-formed strings (MySQL refuses a lone surrogate), no NUL character (PostgreSQL
|
|
4
|
+
* refuses it), at most maxBytes.
|
|
5
|
+
* @param {unknown} payload
|
|
6
|
+
* @param {number} maxBytes
|
|
7
|
+
* @param {string} where For the error message.
|
|
8
|
+
* @returns {string} The JSON.
|
|
9
|
+
*/
|
|
10
|
+
export declare function serializePayload(payload: unknown, maxBytes: number, where: string): string;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export type JobDefinition = import('./types.js').JobDefinition;
|
|
2
|
+
export type Lane = {
|
|
3
|
+
name: string;
|
|
4
|
+
concurrency: number;
|
|
5
|
+
running: number;
|
|
6
|
+
};
|
|
7
|
+
export type HandlerEntry = {
|
|
8
|
+
name: string;
|
|
9
|
+
definition: JobDefinition | null;
|
|
10
|
+
handler: import('./types.js').Handler;
|
|
11
|
+
lane: Lane;
|
|
12
|
+
/**
|
|
13
|
+
* Resolved: the handle() options, else the definition, else the defaults.
|
|
14
|
+
*/
|
|
15
|
+
timeoutMs: number | null;
|
|
16
|
+
};
|
|
17
|
+
export type Registry = {
|
|
18
|
+
handle: (job: JobDefinition | string, handler: import('./types.js').Handler, options?: object) => void;
|
|
19
|
+
getEntry: (name: string) => HandlerEntry | undefined;
|
|
20
|
+
entries: () => HandlerEntry[];
|
|
21
|
+
/**
|
|
22
|
+
* In `jobs`, else handled.
|
|
23
|
+
*/
|
|
24
|
+
findDefinition: (name: string) => JobDefinition | null;
|
|
25
|
+
/**
|
|
26
|
+
* The handled names whose definition has mutex keys.
|
|
27
|
+
*/
|
|
28
|
+
keyedNames: () => string[];
|
|
29
|
+
/**
|
|
30
|
+
* Checks the handlers together: each failure job resolves and has none of its own.
|
|
31
|
+
*/
|
|
32
|
+
validate: () => void;
|
|
33
|
+
};
|
|
34
|
+
/** @typedef {import('./types.js').JobDefinition} JobDefinition */
|
|
35
|
+
/**
|
|
36
|
+
* A concurrency limit in this process.
|
|
37
|
+
* @typedef {object} Lane
|
|
38
|
+
* @property {string} name
|
|
39
|
+
* @property {number} concurrency
|
|
40
|
+
* @property {number} running
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* @typedef {object} HandlerEntry
|
|
44
|
+
* @property {string} name
|
|
45
|
+
* @property {JobDefinition | null} definition
|
|
46
|
+
* @property {import('./types.js').Handler} handler
|
|
47
|
+
* @property {Lane} lane
|
|
48
|
+
* @property {number | null} timeoutMs Resolved: the handle() options, else the definition, else the defaults.
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* @typedef {object} Registry
|
|
52
|
+
* @property {(job: JobDefinition | string, handler: import('./types.js').Handler, options?: object) => void} handle
|
|
53
|
+
* @property {(name: string) => HandlerEntry | undefined} getEntry
|
|
54
|
+
* @property {() => HandlerEntry[]} entries
|
|
55
|
+
* @property {(name: string) => JobDefinition | null} findDefinition In `jobs`, else handled.
|
|
56
|
+
* @property {() => string[]} keyedNames The handled names whose definition has mutex keys.
|
|
57
|
+
* @property {() => void} validate Checks the handlers together: each failure job resolves and has none of its own.
|
|
58
|
+
*/
|
|
59
|
+
/**
|
|
60
|
+
* @param {object} params
|
|
61
|
+
* @param {Map<string, JobDefinition>} params.jobsByName
|
|
62
|
+
* @param {unknown} params.lanes The `lanes` option.
|
|
63
|
+
* @param {number} params.concurrency The process concurrency.
|
|
64
|
+
* @param {number | null} params.defaultTimeoutMs
|
|
65
|
+
* @returns {Registry}
|
|
66
|
+
*/
|
|
67
|
+
export declare function createRegistry({ jobsByName, lanes, concurrency, defaultTimeoutMs }: {
|
|
68
|
+
jobsByName: Map<string, JobDefinition>;
|
|
69
|
+
lanes: unknown;
|
|
70
|
+
concurrency: number;
|
|
71
|
+
defaultTimeoutMs: number | null;
|
|
72
|
+
}): Registry;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export type ClaimedJob = import('./store/store.js').ClaimedJob;
|
|
2
|
+
export type HandlerEntry = import('./registry.js').HandlerEntry;
|
|
3
|
+
export type Lane = import('./registry.js').Lane;
|
|
4
|
+
export type Timings = {
|
|
5
|
+
leaseMs: number;
|
|
6
|
+
renewIntervalMs: number;
|
|
7
|
+
recoveryIntervalMs: number;
|
|
8
|
+
cleanupIntervalMs: number;
|
|
9
|
+
pollIntervalMs: number;
|
|
10
|
+
/**
|
|
11
|
+
* How long a failed write of a result is retried.
|
|
12
|
+
*/
|
|
13
|
+
maxFinalizingMs: number;
|
|
14
|
+
/**
|
|
15
|
+
* A job without its payload waits this long for it.
|
|
16
|
+
*/
|
|
17
|
+
missingPayloadGraceMs: number;
|
|
18
|
+
};
|
|
19
|
+
/** @typedef {import('./store/store.js').ClaimedJob} ClaimedJob */
|
|
20
|
+
/** @typedef {import('./registry.js').HandlerEntry} HandlerEntry */
|
|
21
|
+
/** @typedef {import('./registry.js').Lane} Lane */
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {object} Timings
|
|
24
|
+
* @property {number} leaseMs
|
|
25
|
+
* @property {number} renewIntervalMs
|
|
26
|
+
* @property {number} recoveryIntervalMs
|
|
27
|
+
* @property {number} cleanupIntervalMs
|
|
28
|
+
* @property {number} pollIntervalMs
|
|
29
|
+
* @property {number} maxFinalizingMs How long a failed write of a result is retried.
|
|
30
|
+
* @property {number} missingPayloadGraceMs A job without its payload waits this long for it.
|
|
31
|
+
*/
|
|
32
|
+
/** @type {Timings} */
|
|
33
|
+
export declare const DEFAULT_TIMINGS: Timings;
|
|
34
|
+
export type RunningJob = {
|
|
35
|
+
key: string;
|
|
36
|
+
claimed: ClaimedJob;
|
|
37
|
+
entry: HandlerEntry;
|
|
38
|
+
controller: AbortController;
|
|
39
|
+
/**
|
|
40
|
+
* Resolves when the result is written (or given up).
|
|
41
|
+
*/
|
|
42
|
+
done: Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* The handler settled.
|
|
45
|
+
*/
|
|
46
|
+
settled: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Released or abandoned on close: the result is not written.
|
|
49
|
+
*/
|
|
50
|
+
released: boolean;
|
|
51
|
+
timedOut: boolean;
|
|
52
|
+
leaseLost: boolean;
|
|
53
|
+
leaseEndsAt: number;
|
|
54
|
+
startedAt: number;
|
|
55
|
+
};
|
|
56
|
+
export type RunnerParams = {
|
|
57
|
+
store: import('./store/store.js').Store;
|
|
58
|
+
registry: import('./registry.js').Registry;
|
|
59
|
+
concurrency: number;
|
|
60
|
+
defaults: import('./defaults.js').ResolvedDefaults;
|
|
61
|
+
cleanup: boolean;
|
|
62
|
+
logger: import('./types.js').Logger | undefined;
|
|
63
|
+
onEvent: ((event: import('./types.js').SqlaneEvent) => void) | undefined;
|
|
64
|
+
hintChannel: import('./hint_channel.js').HintChannel;
|
|
65
|
+
/**
|
|
66
|
+
* The hints come after the commit of their enqueue (PostgreSQL NOTIFY): they wake
|
|
67
|
+
* at once, with no re-probes.
|
|
68
|
+
*/
|
|
69
|
+
hintsAfterCommit: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* For tests.
|
|
72
|
+
*/
|
|
73
|
+
timings?: Partial<Timings>;
|
|
74
|
+
};
|
|
75
|
+
export type Runner = {
|
|
76
|
+
start: () => Promise<void>;
|
|
77
|
+
drain: (options?: import('./types.js').DrainOptions) => Promise<import('./types.js').DrainResult>;
|
|
78
|
+
close: (options?: import('./types.js').CloseOptions) => Promise<void>;
|
|
79
|
+
wake: (name: string) => void;
|
|
80
|
+
onEnqueued: (names: string[]) => void;
|
|
81
|
+
isClosed: () => boolean;
|
|
82
|
+
isStarted: () => boolean;
|
|
83
|
+
/**
|
|
84
|
+
* This process handles the name and has a free slot for it.
|
|
85
|
+
*/
|
|
86
|
+
canStartNow: (name: string) => boolean;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* @param {RunnerParams} params
|
|
90
|
+
* @returns {Runner}
|
|
91
|
+
*/
|
|
92
|
+
export declare function createRunner({ store, registry, concurrency, defaults, cleanup, logger, onEvent, hintChannel, hintsAfterCommit, timings, }: RunnerParams): Runner;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} p The table prefix.
|
|
3
|
+
* @returns {import('../types.js').Migration[]}
|
|
4
|
+
*/
|
|
5
|
+
export declare function mysqlMigrations(p: string): import('../types.js').Migration[];
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} p
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
10
|
+
export declare function mysqlMigrationsTable(p: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} p The table prefix.
|
|
3
|
+
* @returns {import('../types.js').Migration[]}
|
|
4
|
+
*/
|
|
5
|
+
export declare function postgresMigrations(p: string): import('../types.js').Migration[];
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} p
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
10
|
+
export declare function postgresMigrationsTable(p: string): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inserts the jobs and their payloads. Call it in a transaction.
|
|
3
|
+
* @param {import('../types.js').Executor} executor
|
|
4
|
+
* @param {string} p The table prefix.
|
|
5
|
+
* @param {import('../new_job.js').NewJob[]} jobs Their ids are distinct.
|
|
6
|
+
* @param {string} enqueueToken
|
|
7
|
+
* @returns {Promise<Set<string>>} The ids that this call created.
|
|
8
|
+
*/
|
|
9
|
+
export declare function insertJobsMysql(executor: import('../types.js').Executor, p: string, jobs: import('../new_job.js').NewJob[], enqueueToken: string): Promise<Set<string>>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
export type Executor = import('../types.js').Executor;
|
|
2
|
+
export type OwnedJob = import('./store.js').OwnedJob;
|
|
3
|
+
export type FailureJobBuilder = import('./store.js').FailureJobBuilder;
|
|
4
|
+
export type FailureJobResult = import('./store.js').FailureJobResult;
|
|
5
|
+
/**
|
|
6
|
+
* Renews the leases of the jobs that the process runs. A row locked by another transaction is skipped: it does not
|
|
7
|
+
* block the others.
|
|
8
|
+
* @param {Executor} executor
|
|
9
|
+
* @param {string} p
|
|
10
|
+
* @param {OwnedJob[]} jobs
|
|
11
|
+
* @param {number} leaseMs
|
|
12
|
+
* @returns {Promise<Set<string>>} The ids whose lease was renewed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function renewLeases(executor: Executor, p: string, jobs: OwnedJob[], leaseMs: number): Promise<Set<string>>;
|
|
15
|
+
/**
|
|
16
|
+
* Marks a timeout: the job stays running until its handler settles (`stuck` in the stats).
|
|
17
|
+
* @param {Executor} executor
|
|
18
|
+
* @param {string} p
|
|
19
|
+
* @param {OwnedJob} job
|
|
20
|
+
* @returns {Promise<boolean>} False: the lease was lost.
|
|
21
|
+
*/
|
|
22
|
+
export declare function markTimedOut(executor: Executor, p: string, job: OwnedJob): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* The jobs are done: completed until their retention ends, without their payloads; their keys are freed. One
|
|
25
|
+
* transaction for many jobs: one commit.
|
|
26
|
+
* @param {Executor} executor
|
|
27
|
+
* @param {string} p
|
|
28
|
+
* @param {import('./store.js').FinishedJob[]} jobs
|
|
29
|
+
* @returns {Promise<number>} The jobs that this call completed: the others lost their lease, or an earlier try
|
|
30
|
+
* committed.
|
|
31
|
+
*/
|
|
32
|
+
export declare function completeJobs(executor: Executor, p: string, jobs: import('./store.js').FinishedJob[]): Promise<number>;
|
|
33
|
+
/**
|
|
34
|
+
* The attempt failed: pending again after the delay, one more attempt used; its keys are freed.
|
|
35
|
+
* @param {Executor} executor
|
|
36
|
+
* @param {string} p
|
|
37
|
+
* @param {OwnedJob} job
|
|
38
|
+
* @param {{ delayMs: number, error: import('../error_json.js').ErrorJson }} params
|
|
39
|
+
* @returns {Promise<boolean>} False: no change.
|
|
40
|
+
*/
|
|
41
|
+
export declare function retryJob(executor: Executor, p: string, job: OwnedJob, { delayMs, error }: {
|
|
42
|
+
delayMs: number;
|
|
43
|
+
error: import('../error_json.js').ErrorJson;
|
|
44
|
+
}): Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* The job fails for good: failed until its retention ends, with its payload; its keys are freed; its failure job is
|
|
47
|
+
* added in the same transaction.
|
|
48
|
+
* @param {Executor} executor
|
|
49
|
+
* @param {string} p
|
|
50
|
+
* @param {OwnedJob} job
|
|
51
|
+
* @param {{ error: import('../error_json.js').ErrorJson, buildFailureJob: FailureJobBuilder }} params
|
|
52
|
+
* @returns {Promise<{ changed: boolean, failureJob: FailureJobResult | null }>}
|
|
53
|
+
*/
|
|
54
|
+
export declare function failJob(executor: Executor, p: string, job: OwnedJob, { error, buildFailureJob }: {
|
|
55
|
+
error: import('../error_json.js').ErrorJson;
|
|
56
|
+
buildFailureJob: FailureJobBuilder;
|
|
57
|
+
}): Promise<{
|
|
58
|
+
changed: boolean;
|
|
59
|
+
failureJob: FailureJobResult | null;
|
|
60
|
+
}>;
|
|
61
|
+
/**
|
|
62
|
+
* The job is released, without an attempt used: pending again after the delay.
|
|
63
|
+
* @param {Executor} executor
|
|
64
|
+
* @param {string} p
|
|
65
|
+
* @param {OwnedJob} job
|
|
66
|
+
* @param {{ delayMs: number, lingerMs: number }} params lingerMs: its keys stay held this long (its handler still
|
|
67
|
+
* runs); 0: they are freed.
|
|
68
|
+
* @returns {Promise<boolean>} False: no change.
|
|
69
|
+
*/
|
|
70
|
+
export declare function releaseJob(executor: Executor, p: string, job: OwnedJob, { delayMs, lingerMs }: {
|
|
71
|
+
delayMs: number;
|
|
72
|
+
lingerMs: number;
|
|
73
|
+
}): Promise<boolean>;
|
|
74
|
+
/**
|
|
75
|
+
* @param {Executor} executor
|
|
76
|
+
* @param {string} p
|
|
77
|
+
* @param {number} limit
|
|
78
|
+
* @returns {Promise<{ id: string, name: string }[]>} The running jobs whose lease ended, the oldest first.
|
|
79
|
+
*/
|
|
80
|
+
export declare function findStaleJobs(executor: Executor, p: string, limit: number): Promise<{
|
|
81
|
+
id: string;
|
|
82
|
+
name: string;
|
|
83
|
+
}[]>;
|
|
84
|
+
/**
|
|
85
|
+
* A running job whose lease ended: one more stall, pending again after 30 s × 2^stalls (at most 1 h); after maxStalls,
|
|
86
|
+
* it fails for good. Its keys linger for one lease: its old handler may still run.
|
|
87
|
+
* @param {Executor} executor
|
|
88
|
+
* @param {string} p
|
|
89
|
+
* @param {string} id
|
|
90
|
+
* @param {{ leaseMs: number, buildFailureJob: FailureJobBuilder }} params
|
|
91
|
+
* @returns {Promise<{ result: 'released' | 'failed' | null, failureJob: FailureJobResult | null }>} null: not stale
|
|
92
|
+
* (any more).
|
|
93
|
+
*/
|
|
94
|
+
export declare function recoverStaleJob(executor: Executor, p: string, id: string, { leaseMs, buildFailureJob }: {
|
|
95
|
+
leaseMs: number;
|
|
96
|
+
buildFailureJob: FailureJobBuilder;
|
|
97
|
+
}): Promise<{
|
|
98
|
+
result: 'released' | 'failed' | null;
|
|
99
|
+
failureJob: FailureJobResult | null;
|
|
100
|
+
}>;
|
|
101
|
+
/**
|
|
102
|
+
* Deletes the ended lingers, and the holds without their running job (from a manual change, or old code).
|
|
103
|
+
* @param {Executor} executor
|
|
104
|
+
* @param {string} p
|
|
105
|
+
* @param {number} limit
|
|
106
|
+
* @returns {Promise<{ lingers: number, orphans: number }>}
|
|
107
|
+
*/
|
|
108
|
+
export declare function sweepMutexes(executor: Executor, p: string, limit: number): Promise<{
|
|
109
|
+
lingers: number;
|
|
110
|
+
orphans: number;
|
|
111
|
+
}>;
|
|
112
|
+
/**
|
|
113
|
+
* Deletes a batch of completed and failed jobs whose retention ended, with their payloads. SKIP LOCKED: processes
|
|
114
|
+
* share the work.
|
|
115
|
+
* @param {Executor} executor
|
|
116
|
+
* @param {string} p
|
|
117
|
+
* @param {number} limit
|
|
118
|
+
* @returns {Promise<number>} The deleted jobs.
|
|
119
|
+
*/
|
|
120
|
+
export declare function deleteExpiredJobs(executor: Executor, p: string, limit: number): Promise<number>;
|
|
121
|
+
/**
|
|
122
|
+
* For drain({ includeDelayed }): the pending jobs of the names are due now.
|
|
123
|
+
* @param {Executor} executor
|
|
124
|
+
* @param {string} p
|
|
125
|
+
* @param {string[]} names
|
|
126
|
+
* @returns {Promise<void>}
|
|
127
|
+
*/
|
|
128
|
+
export declare function makeDue(executor: Executor, p: string, names: string[]): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* The counts per job name, for alerts such as "queue stuck". Reads the status index only.
|
|
131
|
+
* @param {Executor} executor
|
|
132
|
+
* @param {string} p
|
|
133
|
+
* @returns {Promise<import('../types.js').JobStats[]>}
|
|
134
|
+
*/
|
|
135
|
+
export declare function getStats(executor: Executor, p: string): Promise<import('../types.js').JobStats[]>;
|