@codenameryuu/adonis-scheduler 1.0.0
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/LICENSE.md +9 -0
- package/README.md +166 -0
- package/build/bin/test.d.ts +1 -0
- package/build/bin/test.js +8 -0
- package/build/commands/commands.json +1 -0
- package/build/commands/inspire_command.d.ts +8 -0
- package/build/commands/inspire_command.js +52 -0
- package/build/commands/main.d.ts +4 -0
- package/build/commands/main.js +36 -0
- package/build/commands/scheduler_command.d.ts +15 -0
- package/build/commands/scheduler_command.js +74 -0
- package/build/commands/scheduler_list_command.d.ts +9 -0
- package/build/commands/scheduler_list_command.js +75 -0
- package/build/configure.d.ts +2 -0
- package/build/configure.js +23 -0
- package/build/index.d.ts +5 -0
- package/build/index.js +13 -0
- package/build/providers/scheduler_provider.d.ts +12 -0
- package/build/providers/scheduler_provider.js +12 -0
- package/build/services/main.d.ts +3 -0
- package/build/services/main.js +6 -0
- package/build/src/decorator.d.ts +3 -0
- package/build/src/decorator.js +13 -0
- package/build/src/scheduler.d.ts +130 -0
- package/build/src/scheduler.js +308 -0
- package/build/src/utils.d.ts +1 -0
- package/build/src/utils.js +3 -0
- package/build/src/worker.d.ts +14 -0
- package/build/src/worker.js +112 -0
- package/build/stubs/main.d.ts +5 -0
- package/build/stubs/main.js +7 -0
- package/build/stubs/start/scheduler.stub +11 -0
- package/build/tests/expression.spec.d.ts +1 -0
- package/build/tests/expression.spec.js +143 -0
- package/package.json +72 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { BaseCommand } from "@adonisjs/core/ace";
|
|
2
|
+
import type { ApplicationService } from "@adonisjs/core/types";
|
|
3
|
+
type Range<START extends number, END extends number, ARR extends unknown[] = [], ACC extends number = never> = ARR["length"] extends END ? ACC | START | END : Range<START, END, [...ARR, 1], ARR[START] extends undefined ? ACC : ACC | ARR["length"]>;
|
|
4
|
+
type DAYS = 0 | 1 | 2 | 3 | 4 | 5 | 6 | "0" | "1" | "2" | "3" | "4" | "5" | "6";
|
|
5
|
+
export declare abstract class BaseSchedule {
|
|
6
|
+
SUNDAY: 0;
|
|
7
|
+
MONDAY: 1;
|
|
8
|
+
TUESDAY: 2;
|
|
9
|
+
WEDNESDAY: 3;
|
|
10
|
+
THURSDAY: 4;
|
|
11
|
+
FRIDAY: 5;
|
|
12
|
+
SATURDAY: 6;
|
|
13
|
+
abstract type: string;
|
|
14
|
+
expression: string;
|
|
15
|
+
config: {
|
|
16
|
+
tag: string;
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
immediate: boolean;
|
|
19
|
+
withoutOverlapping: boolean;
|
|
20
|
+
expiresAt: number;
|
|
21
|
+
timezone: string | undefined;
|
|
22
|
+
};
|
|
23
|
+
beforeCallbacks: (() => Promise<void>)[];
|
|
24
|
+
afterCallbacks: (() => Promise<void>)[];
|
|
25
|
+
before(callback: () => Promise<void>): this;
|
|
26
|
+
after(callback: () => Promise<void>): this;
|
|
27
|
+
timezone(timezone: string): this;
|
|
28
|
+
skip(state?: boolean): this;
|
|
29
|
+
tag(tag: string): this;
|
|
30
|
+
immediate(state?: boolean): this;
|
|
31
|
+
withoutOverlapping(expiresAt?: number): this;
|
|
32
|
+
everyMinutes(minutes: number): this;
|
|
33
|
+
everyMinute(): this;
|
|
34
|
+
everyTwoMinutes(): this;
|
|
35
|
+
everyThreeMinutes(): this;
|
|
36
|
+
everyFourMinutes(): this;
|
|
37
|
+
everyFiveMinutes(): this;
|
|
38
|
+
everyTenMinutes(): this;
|
|
39
|
+
everyFifteenMinutes(): this;
|
|
40
|
+
everyThirtyMinutes(): this;
|
|
41
|
+
hourly(): this;
|
|
42
|
+
hourlyAt(offset: string | number | Range<0, 59> | Range<0, 59>[]): this;
|
|
43
|
+
everyHours(hours: number, offset?: any[] | string | number): this;
|
|
44
|
+
everyOddHour(offset?: any[] | string | number): this;
|
|
45
|
+
everyTwoHours(offset?: any[] | string | number): this;
|
|
46
|
+
everyThreeHours(offset?: any[] | string | number): this;
|
|
47
|
+
everyFourHours(offset?: any[] | string | number): this;
|
|
48
|
+
everyFiveHours(offset?: any[] | string | number): this;
|
|
49
|
+
everySixHours(offset?: any[] | string | number): this;
|
|
50
|
+
daily(): this;
|
|
51
|
+
weekdays(): this;
|
|
52
|
+
weekends(): this;
|
|
53
|
+
mondays(): this;
|
|
54
|
+
tuesdays(): this;
|
|
55
|
+
wednesdays(): this;
|
|
56
|
+
thursdays(): this;
|
|
57
|
+
fridays(): this;
|
|
58
|
+
saturdays(): this;
|
|
59
|
+
sundays(): this;
|
|
60
|
+
weekly(): this;
|
|
61
|
+
weeklyOn(dayOfWeek?: Range<0, 7>, time?: string): this;
|
|
62
|
+
monthly(): this;
|
|
63
|
+
quarterly(): this;
|
|
64
|
+
yearly(): this;
|
|
65
|
+
yearlyOn(month?: number, dayOfMonth?: string | Range<1, 31>, time?: string): this;
|
|
66
|
+
everySecond(): this;
|
|
67
|
+
everySeconds(second: Range<1, 59>): this;
|
|
68
|
+
everyFiveSeconds(): this;
|
|
69
|
+
everyTenSeconds(): this;
|
|
70
|
+
everyFifteenSeconds(): this;
|
|
71
|
+
everyThirtySeconds(): this;
|
|
72
|
+
cron(expression: string): this;
|
|
73
|
+
protected spliceIntoPosition(position: number, value: string | number): this;
|
|
74
|
+
protected hourBasedSchedule(minutes: string | number | Range<0, 59>[], hours: string | number | Range<0, 59>[]): this;
|
|
75
|
+
days(days: DAYS | DAYS[]): this;
|
|
76
|
+
at(time: string): this;
|
|
77
|
+
dailyAt(time: string): this;
|
|
78
|
+
twiceDailyAt(first?: Range<0, 23>, second?: Range<0, 23>, offset?: number): this;
|
|
79
|
+
twiceDaily(first?: Range<0, 23>, second?: Range<0, 23>): this;
|
|
80
|
+
twiceMonthly(first?: Range<1, 31>, second?: Range<1, 31>, time?: string): this;
|
|
81
|
+
lastDayOfMonth(time?: string): this;
|
|
82
|
+
monthlyOn(dayOfMonth?: Range<1, 31>, time?: string): this;
|
|
83
|
+
getExpression(): string;
|
|
84
|
+
}
|
|
85
|
+
export declare class ScheduleCommand extends BaseSchedule {
|
|
86
|
+
type: "command";
|
|
87
|
+
commandName: string;
|
|
88
|
+
commandArgs: string[];
|
|
89
|
+
constructor(commandName: string, commandArgs?: string[]);
|
|
90
|
+
}
|
|
91
|
+
export declare class ScheduleCallback extends BaseSchedule {
|
|
92
|
+
type: "callback";
|
|
93
|
+
callback: Function;
|
|
94
|
+
constructor(callback: Function);
|
|
95
|
+
}
|
|
96
|
+
export declare class Scheduler {
|
|
97
|
+
protected app: ApplicationService;
|
|
98
|
+
SUNDAY: 0;
|
|
99
|
+
MONDAY: 1;
|
|
100
|
+
TUESDAY: 2;
|
|
101
|
+
WEDNESDAY: 3;
|
|
102
|
+
THURSDAY: 4;
|
|
103
|
+
FRIDAY: 5;
|
|
104
|
+
SATURDAY: 6;
|
|
105
|
+
constructor(app: ApplicationService);
|
|
106
|
+
static __decorator_schedules: (ScheduleCallback | ScheduleCommand)[];
|
|
107
|
+
items: (ScheduleCallback | ScheduleCommand)[];
|
|
108
|
+
onStartingCallback?: ({ tag }: {
|
|
109
|
+
tag: string;
|
|
110
|
+
}) => void | Promise<void>;
|
|
111
|
+
onStartedCallback?: ({ tag }: {
|
|
112
|
+
tag: string;
|
|
113
|
+
}) => void | Promise<void>;
|
|
114
|
+
onBootCallback?: () => void | Promise<void>;
|
|
115
|
+
boot(): Promise<void>;
|
|
116
|
+
command(name: string | typeof BaseCommand, args?: string | string[]): ScheduleCommand;
|
|
117
|
+
call(callback: Function): ScheduleCallback;
|
|
118
|
+
withoutOverlapping(callback: () => void, config?: {
|
|
119
|
+
expiresAt: number;
|
|
120
|
+
}): void;
|
|
121
|
+
withTag(callback: () => void, tag: string): void;
|
|
122
|
+
onStarting(callback: ({ tag }: {
|
|
123
|
+
tag: string;
|
|
124
|
+
}) => void | Promise<void>): void;
|
|
125
|
+
onStarted(callback: ({ tag }: {
|
|
126
|
+
tag: string;
|
|
127
|
+
}) => void | Promise<void>): void;
|
|
128
|
+
onBoot(callback: () => void | Promise<void>): void;
|
|
129
|
+
}
|
|
130
|
+
export {};
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { FsLoader } from "@adonisjs/core/ace";
|
|
2
|
+
import { DateTime } from "luxon";
|
|
3
|
+
import { arrayWrap } from "./utils.js";
|
|
4
|
+
export class BaseSchedule {
|
|
5
|
+
SUNDAY = 0;
|
|
6
|
+
MONDAY = 1;
|
|
7
|
+
TUESDAY = 2;
|
|
8
|
+
WEDNESDAY = 3;
|
|
9
|
+
THURSDAY = 4;
|
|
10
|
+
FRIDAY = 5;
|
|
11
|
+
SATURDAY = 6;
|
|
12
|
+
expression = "0 * * * * *"; // seconds minutes hours dayOfMonth month dayOfWeek
|
|
13
|
+
config = {
|
|
14
|
+
tag: "default",
|
|
15
|
+
enabled: true,
|
|
16
|
+
immediate: false,
|
|
17
|
+
withoutOverlapping: false,
|
|
18
|
+
expiresAt: 3600000,
|
|
19
|
+
timezone: undefined,
|
|
20
|
+
};
|
|
21
|
+
beforeCallbacks = [];
|
|
22
|
+
afterCallbacks = [];
|
|
23
|
+
before(callback) {
|
|
24
|
+
this.beforeCallbacks.push(callback);
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
after(callback) {
|
|
28
|
+
this.afterCallbacks.push(callback);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
timezone(timezone) {
|
|
32
|
+
this.config.timezone = timezone;
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
skip(state = true) {
|
|
36
|
+
this.config.enabled = !state;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
tag(tag) {
|
|
40
|
+
this.config.tag = tag;
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
immediate(state = true) {
|
|
44
|
+
this.config.immediate = state;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
withoutOverlapping(expiresAt = 3600000) {
|
|
48
|
+
this.config.withoutOverlapping = true;
|
|
49
|
+
this.config.expiresAt = expiresAt;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
everyMinutes(minutes) {
|
|
53
|
+
return this.spliceIntoPosition(1, `*/${minutes}`);
|
|
54
|
+
}
|
|
55
|
+
everyMinute() {
|
|
56
|
+
return this.spliceIntoPosition(1, "*");
|
|
57
|
+
}
|
|
58
|
+
everyTwoMinutes() {
|
|
59
|
+
return this.everyMinutes(2);
|
|
60
|
+
}
|
|
61
|
+
everyThreeMinutes() {
|
|
62
|
+
return this.everyMinutes(3);
|
|
63
|
+
}
|
|
64
|
+
everyFourMinutes() {
|
|
65
|
+
return this.everyMinutes(4);
|
|
66
|
+
}
|
|
67
|
+
everyFiveMinutes() {
|
|
68
|
+
return this.everyMinutes(5);
|
|
69
|
+
}
|
|
70
|
+
everyTenMinutes() {
|
|
71
|
+
return this.everyMinutes(10);
|
|
72
|
+
}
|
|
73
|
+
everyFifteenMinutes() {
|
|
74
|
+
return this.everyMinutes(15);
|
|
75
|
+
}
|
|
76
|
+
everyThirtyMinutes() {
|
|
77
|
+
return this.everyMinutes(30);
|
|
78
|
+
}
|
|
79
|
+
hourly() {
|
|
80
|
+
return this.spliceIntoPosition(1, 0);
|
|
81
|
+
}
|
|
82
|
+
hourlyAt(offset) {
|
|
83
|
+
return this.hourBasedSchedule(offset, "*");
|
|
84
|
+
}
|
|
85
|
+
everyHours(hours, offset = 0) {
|
|
86
|
+
return this.hourBasedSchedule(offset, `*/${hours}`);
|
|
87
|
+
}
|
|
88
|
+
everyOddHour(offset = 0) {
|
|
89
|
+
return this.hourBasedSchedule(offset, "1-23/2");
|
|
90
|
+
}
|
|
91
|
+
everyTwoHours(offset = 0) {
|
|
92
|
+
return this.everyHours(2, offset);
|
|
93
|
+
}
|
|
94
|
+
everyThreeHours(offset = 0) {
|
|
95
|
+
return this.everyHours(3, offset);
|
|
96
|
+
}
|
|
97
|
+
everyFourHours(offset = 0) {
|
|
98
|
+
return this.everyHours(4, offset);
|
|
99
|
+
}
|
|
100
|
+
everyFiveHours(offset = 0) {
|
|
101
|
+
return this.everyHours(5, offset);
|
|
102
|
+
}
|
|
103
|
+
everySixHours(offset = 0) {
|
|
104
|
+
return this.everyHours(6, offset);
|
|
105
|
+
}
|
|
106
|
+
daily() {
|
|
107
|
+
return this.hourBasedSchedule(0, 0);
|
|
108
|
+
}
|
|
109
|
+
weekdays() {
|
|
110
|
+
return this.spliceIntoPosition(5, "1-5");
|
|
111
|
+
}
|
|
112
|
+
weekends() {
|
|
113
|
+
return this.spliceIntoPosition(5, "6,0");
|
|
114
|
+
}
|
|
115
|
+
mondays() {
|
|
116
|
+
return this.days(1);
|
|
117
|
+
}
|
|
118
|
+
tuesdays() {
|
|
119
|
+
return this.days(2);
|
|
120
|
+
}
|
|
121
|
+
wednesdays() {
|
|
122
|
+
return this.days(3);
|
|
123
|
+
}
|
|
124
|
+
thursdays() {
|
|
125
|
+
return this.days(4);
|
|
126
|
+
}
|
|
127
|
+
fridays() {
|
|
128
|
+
return this.days(5);
|
|
129
|
+
}
|
|
130
|
+
saturdays() {
|
|
131
|
+
return this.days(6);
|
|
132
|
+
}
|
|
133
|
+
sundays() {
|
|
134
|
+
return this.days(0);
|
|
135
|
+
}
|
|
136
|
+
weekly() {
|
|
137
|
+
return this.spliceIntoPosition(1, 0).spliceIntoPosition(2, 0).spliceIntoPosition(5, 0);
|
|
138
|
+
}
|
|
139
|
+
weeklyOn(dayOfWeek = 1, time = "0:0") {
|
|
140
|
+
this.dailyAt(time);
|
|
141
|
+
return this.days(dayOfWeek);
|
|
142
|
+
}
|
|
143
|
+
monthly() {
|
|
144
|
+
return this.spliceIntoPosition(1, 0).spliceIntoPosition(2, 0).spliceIntoPosition(3, 1);
|
|
145
|
+
}
|
|
146
|
+
quarterly() {
|
|
147
|
+
return this.spliceIntoPosition(1, 0).spliceIntoPosition(2, 0).spliceIntoPosition(3, 1).spliceIntoPosition(4, "1-12/3");
|
|
148
|
+
}
|
|
149
|
+
yearly() {
|
|
150
|
+
return this.spliceIntoPosition(1, 0).spliceIntoPosition(2, 0).spliceIntoPosition(3, 1).spliceIntoPosition(4, 1);
|
|
151
|
+
}
|
|
152
|
+
yearlyOn(month = 1, dayOfMonth = 1, time = "0:0") {
|
|
153
|
+
this.dailyAt(time);
|
|
154
|
+
return this.spliceIntoPosition(3, dayOfMonth).spliceIntoPosition(4, month);
|
|
155
|
+
}
|
|
156
|
+
everySecond() {
|
|
157
|
+
return this.spliceIntoPosition(0, "*");
|
|
158
|
+
}
|
|
159
|
+
everySeconds(second) {
|
|
160
|
+
return this.spliceIntoPosition(0, `*/${second}`);
|
|
161
|
+
}
|
|
162
|
+
everyFiveSeconds() {
|
|
163
|
+
return this.everySeconds(5);
|
|
164
|
+
}
|
|
165
|
+
everyTenSeconds() {
|
|
166
|
+
return this.everySeconds(10);
|
|
167
|
+
}
|
|
168
|
+
everyFifteenSeconds() {
|
|
169
|
+
return this.everySeconds(15);
|
|
170
|
+
}
|
|
171
|
+
everyThirtySeconds() {
|
|
172
|
+
return this.everySeconds(30);
|
|
173
|
+
}
|
|
174
|
+
cron(expression) {
|
|
175
|
+
this.expression = expression;
|
|
176
|
+
return this;
|
|
177
|
+
}
|
|
178
|
+
spliceIntoPosition(position, value) {
|
|
179
|
+
const segements = this.expression.split(" ");
|
|
180
|
+
segements[position] = String(value);
|
|
181
|
+
this.cron(segements.join(" "));
|
|
182
|
+
return this;
|
|
183
|
+
}
|
|
184
|
+
hourBasedSchedule(minutes, hours) {
|
|
185
|
+
minutes = Array.isArray(minutes) ? minutes.join(",") : minutes;
|
|
186
|
+
hours = Array.isArray(hours) ? hours.join(",") : hours;
|
|
187
|
+
return this.spliceIntoPosition(1, minutes).spliceIntoPosition(2, hours);
|
|
188
|
+
}
|
|
189
|
+
days(days) {
|
|
190
|
+
return this.spliceIntoPosition(5, Array.isArray(days) ? days.join(",") : days);
|
|
191
|
+
}
|
|
192
|
+
at(time) {
|
|
193
|
+
return this.dailyAt(time);
|
|
194
|
+
}
|
|
195
|
+
dailyAt(time) {
|
|
196
|
+
let segments = time.split(":");
|
|
197
|
+
return this.hourBasedSchedule(segments.length === 2 ? Number(segments[1]) : "0", Number(segments[0]));
|
|
198
|
+
}
|
|
199
|
+
twiceDailyAt(first = 1, second = 13, offset = 0) {
|
|
200
|
+
const hours = first + "," + second;
|
|
201
|
+
return this.hourBasedSchedule(offset, hours);
|
|
202
|
+
}
|
|
203
|
+
twiceDaily(first = 1, second = 13) {
|
|
204
|
+
return this.twiceDailyAt(first, second, 0);
|
|
205
|
+
}
|
|
206
|
+
twiceMonthly(first = 1, second = 13, time = "0:0") {
|
|
207
|
+
const dayOfMonth = first + "," + second;
|
|
208
|
+
this.dailyAt(time);
|
|
209
|
+
return this.spliceIntoPosition(3, dayOfMonth);
|
|
210
|
+
}
|
|
211
|
+
lastDayOfMonth(time = "0:0") {
|
|
212
|
+
this.dailyAt(time);
|
|
213
|
+
return this.spliceIntoPosition(3, DateTime.now().endOf("month").day);
|
|
214
|
+
}
|
|
215
|
+
monthlyOn(dayOfMonth = 1, time = "0:0") {
|
|
216
|
+
this.dailyAt(time);
|
|
217
|
+
return this.spliceIntoPosition(3, dayOfMonth);
|
|
218
|
+
}
|
|
219
|
+
getExpression() {
|
|
220
|
+
return this.expression;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
export class ScheduleCommand extends BaseSchedule {
|
|
224
|
+
type = "command";
|
|
225
|
+
commandName;
|
|
226
|
+
commandArgs;
|
|
227
|
+
constructor(commandName, commandArgs = []) {
|
|
228
|
+
super();
|
|
229
|
+
this.commandName = commandName;
|
|
230
|
+
this.commandArgs = commandArgs;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
export class ScheduleCallback extends BaseSchedule {
|
|
234
|
+
type = "callback";
|
|
235
|
+
callback;
|
|
236
|
+
constructor(callback) {
|
|
237
|
+
super();
|
|
238
|
+
this.callback = callback;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
export class Scheduler {
|
|
242
|
+
app;
|
|
243
|
+
SUNDAY = 0;
|
|
244
|
+
MONDAY = 1;
|
|
245
|
+
TUESDAY = 2;
|
|
246
|
+
WEDNESDAY = 3;
|
|
247
|
+
THURSDAY = 4;
|
|
248
|
+
FRIDAY = 5;
|
|
249
|
+
SATURDAY = 6;
|
|
250
|
+
constructor(app) {
|
|
251
|
+
this.app = app;
|
|
252
|
+
this.app = app;
|
|
253
|
+
}
|
|
254
|
+
static __decorator_schedules = [];
|
|
255
|
+
items = [];
|
|
256
|
+
onStartingCallback;
|
|
257
|
+
onStartedCallback;
|
|
258
|
+
onBootCallback;
|
|
259
|
+
async boot() {
|
|
260
|
+
await this.onBootCallback?.();
|
|
261
|
+
const fsLoader = new FsLoader(this.app.commandsPath());
|
|
262
|
+
await fsLoader.getMetaData();
|
|
263
|
+
for (const command of this.app.rcFile.commands) {
|
|
264
|
+
const loader = await (typeof command === "function" ? command() : command);
|
|
265
|
+
await loader.getMetaData();
|
|
266
|
+
}
|
|
267
|
+
if (!Scheduler.__decorator_schedules || Scheduler.__decorator_schedules.length === 0)
|
|
268
|
+
return;
|
|
269
|
+
this.items.push(...Scheduler.__decorator_schedules);
|
|
270
|
+
}
|
|
271
|
+
command(name, args = []) {
|
|
272
|
+
let newCommand = new ScheduleCommand(typeof name === "string" ? name : name.commandName, arrayWrap(args));
|
|
273
|
+
this.items.push(newCommand);
|
|
274
|
+
return newCommand;
|
|
275
|
+
}
|
|
276
|
+
call(callback) {
|
|
277
|
+
let newCommand = new ScheduleCallback(callback);
|
|
278
|
+
this.items.push(newCommand);
|
|
279
|
+
return newCommand;
|
|
280
|
+
}
|
|
281
|
+
withoutOverlapping(callback, config = { expiresAt: 3600000 }) {
|
|
282
|
+
const lastLength = this.items.length;
|
|
283
|
+
callback();
|
|
284
|
+
const currentLength = this.items.length;
|
|
285
|
+
const newItems = this.items.slice(lastLength, currentLength);
|
|
286
|
+
for (const item of newItems) {
|
|
287
|
+
item.withoutOverlapping(config.expiresAt);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
withTag(callback, tag) {
|
|
291
|
+
const lastLength = this.items.length;
|
|
292
|
+
callback();
|
|
293
|
+
const currentLength = this.items.length;
|
|
294
|
+
const newItems = this.items.slice(lastLength, currentLength);
|
|
295
|
+
for (const item of newItems) {
|
|
296
|
+
item.tag(tag);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
onStarting(callback) {
|
|
300
|
+
this.onStartingCallback = callback;
|
|
301
|
+
}
|
|
302
|
+
onStarted(callback) {
|
|
303
|
+
this.onStartedCallback = callback;
|
|
304
|
+
}
|
|
305
|
+
onBoot(callback) {
|
|
306
|
+
this.onBootCallback = callback;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const arrayWrap: <T extends any>(value: T | T[]) => T[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ApplicationService } from "@adonisjs/core/types";
|
|
2
|
+
import cron from "node-cron";
|
|
3
|
+
import { Kernel } from "@adonisjs/core/ace";
|
|
4
|
+
export declare class Worker {
|
|
5
|
+
app: ApplicationService;
|
|
6
|
+
tasks: cron.ScheduledTask[];
|
|
7
|
+
loaders: any[];
|
|
8
|
+
booted: boolean;
|
|
9
|
+
kernel: Kernel;
|
|
10
|
+
constructor(app: ApplicationService);
|
|
11
|
+
boot(): Promise<void>;
|
|
12
|
+
start(tag?: string): Promise<void>;
|
|
13
|
+
stop(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import cron from "node-cron";
|
|
2
|
+
import AsyncLock from "async-lock";
|
|
3
|
+
import { FsLoader, Kernel } from "@adonisjs/core/ace";
|
|
4
|
+
const lock = new AsyncLock();
|
|
5
|
+
const run = async (cb, options) => {
|
|
6
|
+
if (!options.enabled)
|
|
7
|
+
return await cb();
|
|
8
|
+
if (lock.isBusy(options.key)) {
|
|
9
|
+
if (options.onBusy) {
|
|
10
|
+
await options.onBusy();
|
|
11
|
+
}
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
await lock.acquire(options.key, cb, { maxPending: 1, timeout: options.timeout });
|
|
15
|
+
};
|
|
16
|
+
export class Worker {
|
|
17
|
+
app;
|
|
18
|
+
tasks = [];
|
|
19
|
+
loaders = [];
|
|
20
|
+
booted = false;
|
|
21
|
+
constructor(app) {
|
|
22
|
+
this.app = app;
|
|
23
|
+
}
|
|
24
|
+
async boot() {
|
|
25
|
+
if (this.booted)
|
|
26
|
+
return;
|
|
27
|
+
const schedule = await this.app.container.make("scheduler");
|
|
28
|
+
await schedule.boot();
|
|
29
|
+
const fsLoader = new FsLoader(this.app.commandsPath());
|
|
30
|
+
this.loaders = [fsLoader];
|
|
31
|
+
this.app.rcFile.commands.forEach((commandModule) => {
|
|
32
|
+
this.loaders.push(() => (typeof commandModule === "function" ? commandModule() : this.app.import(commandModule)));
|
|
33
|
+
});
|
|
34
|
+
this.kernel = new Kernel(this.app);
|
|
35
|
+
for (const loader of this.loaders) {
|
|
36
|
+
this.kernel.addLoader(loader);
|
|
37
|
+
}
|
|
38
|
+
await this.kernel.boot();
|
|
39
|
+
this.booted = true;
|
|
40
|
+
}
|
|
41
|
+
async start(tag = "default") {
|
|
42
|
+
await this.boot();
|
|
43
|
+
const schedule = await this.app.container.make("scheduler");
|
|
44
|
+
const logger = await this.app.container.make("logger");
|
|
45
|
+
if (schedule.onStartingCallback) {
|
|
46
|
+
await schedule.onStartingCallback({
|
|
47
|
+
tag,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
for (let index = 0; index < schedule.items.length; index++) {
|
|
51
|
+
const command = schedule.items[index];
|
|
52
|
+
if (command.config.tag !== tag) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
this.tasks.push(cron.schedule(command.expression, async () => {
|
|
56
|
+
try {
|
|
57
|
+
switch (command.type) {
|
|
58
|
+
case "command":
|
|
59
|
+
for (const callback of command.beforeCallbacks) {
|
|
60
|
+
await callback();
|
|
61
|
+
}
|
|
62
|
+
await run(() => this.kernel.exec(command.commandName, command.commandArgs), {
|
|
63
|
+
enabled: command.config.withoutOverlapping,
|
|
64
|
+
timeout: command.config.expiresAt,
|
|
65
|
+
key: `${index}-${command.commandName}-${command.commandArgs}`,
|
|
66
|
+
onBusy: () => {
|
|
67
|
+
logger.warn(`Command ${index}-${command.commandName}-${command.commandArgs} is busy`);
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
for (const callback of command.afterCallbacks) {
|
|
71
|
+
await callback();
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
case "callback":
|
|
75
|
+
for (const callback of command.beforeCallbacks) {
|
|
76
|
+
await callback();
|
|
77
|
+
}
|
|
78
|
+
await run(() => command.callback(), {
|
|
79
|
+
enabled: command.config.withoutOverlapping,
|
|
80
|
+
timeout: command.config.expiresAt,
|
|
81
|
+
key: `${index}-callback`,
|
|
82
|
+
onBusy: () => {
|
|
83
|
+
logger.warn(`Callback ${index} is busy`);
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
for (const callback of command.afterCallbacks) {
|
|
87
|
+
await callback();
|
|
88
|
+
}
|
|
89
|
+
default:
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
logger.error(error);
|
|
95
|
+
}
|
|
96
|
+
}, {
|
|
97
|
+
scheduled: command.config.enabled,
|
|
98
|
+
timezone: command.config.timezone,
|
|
99
|
+
runOnInit: command.config.enabled && command.config.immediate,
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
logger.info(`[${tag}] Schedule worker started successfully.`);
|
|
103
|
+
if (schedule.onStartedCallback) {
|
|
104
|
+
await schedule.onStartedCallback({
|
|
105
|
+
tag,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async stop() {
|
|
110
|
+
await Promise.all(this.tasks.map((task) => task.stop()));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { dirname } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
/**
|
|
4
|
+
* Path to the root directory where the stubs are stored. We use
|
|
5
|
+
* this path within commands and the configure hook
|
|
6
|
+
*/
|
|
7
|
+
export const stubsRoot = dirname(fileURLToPath(import.meta.url));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|