@navios/schedule 0.3.0 → 0.5.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 +7 -0
- package/README.md +221 -311
- package/dist/src/decorators/cron.decorator.d.mts.map +1 -1
- package/dist/src/scheduler.service.d.mts +1 -0
- package/dist/src/scheduler.service.d.mts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/lib/_tsup-dts-rollup.d.mts +1 -0
- package/lib/_tsup-dts-rollup.d.ts +1 -0
- package/lib/index.js +3 -3
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +4 -4
- package/lib/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/__tests__/schedule.spec.mts +5 -3
- package/src/decorators/cron.decorator.mts +0 -1
- package/src/scheduler.service.mts +4 -10
- package/dist/tsdown.config.d.mts +0 -3
- package/dist/tsdown.config.d.mts.map +0 -1
- package/dist/tsup.config.d.mts +0 -3
- package/dist/tsup.config.d.mts.map +0 -1
- package/dist/vitest.config.d.mts +0 -3
- package/dist/vitest.config.d.mts.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2025 Oleksandr Hanzha
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,370 +1,280 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @navios/schedule
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A powerful and type-safe job scheduling library for Navios applications, built on top of the popular `cron` package. Schedule and manage recurring tasks with decorator-based configuration and dependency injection support.
|
|
4
4
|
|
|
5
|
-
## Why?
|
|
5
|
+
## Why @navios/schedule?
|
|
6
6
|
|
|
7
|
-
- **Type Safety**:
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **Error Handling**: The package provides built-in error handling capabilities, allowing you to handle API errors gracefully and provide meaningful feedback to users.
|
|
7
|
+
- **Type Safety**: Full TypeScript support with strict typing for cron expressions and job methods
|
|
8
|
+
- **Decorator-Based**: Clean, declarative API using decorators for defining schedulable services and cron jobs
|
|
9
|
+
- **Dependency Injection**: Seamless integration with Navios's dependency injection container
|
|
10
|
+
- **Error Handling**: Built-in error handling that logs errors without crashing the scheduler
|
|
11
|
+
- **Flexible Configuration**: Support for custom cron expressions and job-specific options
|
|
12
|
+
- **Runtime Control**: Start, stop, and manage individual jobs or all jobs at once
|
|
13
|
+
- **Pre-defined Schedules**: Common scheduling patterns available as constants
|
|
15
14
|
|
|
16
15
|
## Installation
|
|
17
16
|
|
|
18
17
|
```bash
|
|
19
|
-
npm install --save @navios/
|
|
18
|
+
npm install --save @navios/schedule @navios/core cron
|
|
20
19
|
```
|
|
21
20
|
|
|
22
21
|
or
|
|
23
22
|
|
|
24
23
|
```bash
|
|
25
|
-
yarn add @navios/
|
|
24
|
+
yarn add @navios/schedule @navios/core cron
|
|
26
25
|
```
|
|
27
26
|
|
|
28
|
-
## Usage
|
|
29
|
-
|
|
30
|
-
```tsx
|
|
31
|
-
import { createAPI } from '@navios/navios-zod'
|
|
32
|
-
import { declareClient } from '@navios/navios-zod-react'
|
|
33
|
-
|
|
34
|
-
import { z } from 'zod'
|
|
35
|
-
|
|
36
|
-
const publicApi = createAPI({
|
|
37
|
-
baseURL: 'https://example.com/api/',
|
|
38
|
-
useDiscriminatorResponse: true,
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
const publicClient = declareClient({
|
|
42
|
-
api: publicApi,
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
const RequestSchema = z.object({
|
|
46
|
-
email: z.string().email(),
|
|
47
|
-
password: z.string().min(8).max(32),
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
const loginMutation = publicClient.mutation({
|
|
51
|
-
url: 'auth/login',
|
|
52
|
-
method: 'post',
|
|
53
|
-
// Navios Zod also validates the request body
|
|
54
|
-
requestSchema: RequestSchema,
|
|
55
|
-
responseSchema: z.discriminatedUnion('success', [
|
|
56
|
-
z.object({
|
|
57
|
-
success: z.literal(true),
|
|
58
|
-
data: z.object({
|
|
59
|
-
accessToken: z.string(),
|
|
60
|
-
refreshToken: z.string(),
|
|
61
|
-
}),
|
|
62
|
-
}),
|
|
63
|
-
z.object({
|
|
64
|
-
success: z.literal(false),
|
|
65
|
-
error: z.object({
|
|
66
|
-
message: z.string(),
|
|
67
|
-
}),
|
|
68
|
-
}),
|
|
69
|
-
]),
|
|
70
|
-
processResponse: (response) => {
|
|
71
|
-
if (response.success) {
|
|
72
|
-
return response.data
|
|
73
|
-
} else {
|
|
74
|
-
throw new Error(response.error.message)
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
export function Login() {
|
|
80
|
-
const { mutateAsync: login, data, isSuccess, error } = loginMutation()
|
|
81
|
-
|
|
82
|
-
const form = useForm({
|
|
83
|
-
resolver: zodResolver(RequestSchema),
|
|
84
|
-
defaultValues: {
|
|
85
|
-
email: '',
|
|
86
|
-
password: '',
|
|
87
|
-
},
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
useEffect(() => {
|
|
91
|
-
if (isSuccess) {
|
|
92
|
-
console.log('Login successful:', data)
|
|
93
|
-
}
|
|
94
|
-
}, [isSuccess, data])
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<form onSubmit={form.handleSubmit(login)}>
|
|
98
|
-
{error && <p>{error.message}</p>}
|
|
99
|
-
<input {...form.register('email')} placeholder="Email" />
|
|
100
|
-
<input
|
|
101
|
-
{...form.register('password')}
|
|
102
|
-
type="password"
|
|
103
|
-
placeholder="Password"
|
|
104
|
-
/>
|
|
105
|
-
<button type="submit">Login</button>
|
|
106
|
-
</form>
|
|
107
|
-
)
|
|
108
|
-
}
|
|
109
|
-
```
|
|
27
|
+
## Basic Usage
|
|
110
28
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
```
|
|
114
|
-
import {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
const publicClient = declareClient({
|
|
125
|
-
api: publicApi,
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
const usersList = publicClient.query({
|
|
129
|
-
url: 'users',
|
|
130
|
-
method: 'GET',
|
|
131
|
-
querySchema: z.object({
|
|
132
|
-
page: z.number().optional().default(1),
|
|
133
|
-
limit: z.number().optional().default(10),
|
|
134
|
-
}),
|
|
135
|
-
responseSchema: z.discriminatedUnion('success', [
|
|
136
|
-
z.object({
|
|
137
|
-
success: z.literal(true),
|
|
138
|
-
data: z.array(
|
|
139
|
-
z.object({
|
|
140
|
-
id: z.string(),
|
|
141
|
-
name: z.string(),
|
|
142
|
-
email: z.string().email(),
|
|
143
|
-
}),
|
|
144
|
-
),
|
|
145
|
-
}),
|
|
146
|
-
z.object({
|
|
147
|
-
success: z.literal(false),
|
|
148
|
-
error: z.object({
|
|
149
|
-
message: z.string(),
|
|
150
|
-
}),
|
|
151
|
-
}),
|
|
152
|
-
]),
|
|
153
|
-
processResponse: (response) => {
|
|
154
|
-
if (response.success) {
|
|
155
|
-
return response.data
|
|
156
|
-
} else {
|
|
157
|
-
throw new Error(response.error.message)
|
|
158
|
-
}
|
|
159
|
-
},
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
export function UsersList() {
|
|
163
|
-
const { page, limit } = routeApi.useSearch()
|
|
164
|
-
const navigate = routeApi.useNavigate()
|
|
165
|
-
const { data, isLoading, error } = usersList.use({
|
|
166
|
-
params: {
|
|
167
|
-
page,
|
|
168
|
-
limit,
|
|
169
|
-
},
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
if (isLoading) {
|
|
173
|
-
return <p>Loading...</p>
|
|
29
|
+
### 1. Create a Schedulable Service
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { Cron, Schedulable, Schedule } from '@navios/schedule'
|
|
33
|
+
|
|
34
|
+
@Schedulable()
|
|
35
|
+
class TaskService {
|
|
36
|
+
@Cron('0 0 * * *') // Run daily at midnight
|
|
37
|
+
async dailyCleanup() {
|
|
38
|
+
console.log('Running daily cleanup...')
|
|
39
|
+
// Your cleanup logic here
|
|
174
40
|
}
|
|
175
41
|
|
|
176
|
-
|
|
177
|
-
|
|
42
|
+
@Cron(Schedule.EveryFiveMinutes)
|
|
43
|
+
async healthCheck() {
|
|
44
|
+
console.log('Performing health check...')
|
|
45
|
+
// Your health check logic here
|
|
178
46
|
}
|
|
179
47
|
|
|
180
|
-
|
|
48
|
+
@Cron('*/30 * * * * *', { disabled: true })
|
|
49
|
+
async disabledJob() {
|
|
50
|
+
// This job won't run automatically
|
|
51
|
+
console.log('This job is disabled')
|
|
52
|
+
}
|
|
181
53
|
}
|
|
182
54
|
```
|
|
183
55
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
```tsx
|
|
187
|
-
import { createAPI } from '@navios/navios-zod'
|
|
188
|
-
import { declareClient } from '@navios/navios-zod-react'
|
|
189
|
-
|
|
190
|
-
import { z } from 'zod'
|
|
191
|
-
|
|
192
|
-
const publicApi = createAPI({
|
|
193
|
-
baseURL: 'https://example.com/api/',
|
|
194
|
-
useDiscriminatorResponse: true,
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
const publicClient = declareClient({
|
|
198
|
-
api: publicApi,
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
const usersList = publicClient.infiniteQuery({
|
|
202
|
-
url: 'users',
|
|
203
|
-
method: 'GET',
|
|
204
|
-
querySchema: z.object({
|
|
205
|
-
page: z.number().optional().default(1),
|
|
206
|
-
limit: z.number().optional().default(10),
|
|
207
|
-
}),
|
|
208
|
-
responseSchema: z.discriminatedUnion('success', [
|
|
209
|
-
z.object({
|
|
210
|
-
success: z.literal(true),
|
|
211
|
-
data: z.array(
|
|
212
|
-
z.object({
|
|
213
|
-
id: z.string(),
|
|
214
|
-
name: z.string(),
|
|
215
|
-
email: z.string().email(),
|
|
216
|
-
}),
|
|
217
|
-
),
|
|
218
|
-
meta: z.object({
|
|
219
|
-
total: z.number(),
|
|
220
|
-
totalPages: z.number(),
|
|
221
|
-
page: z.number(),
|
|
222
|
-
}),
|
|
223
|
-
}),
|
|
224
|
-
z.object({
|
|
225
|
-
success: z.literal(false),
|
|
226
|
-
error: z.object({
|
|
227
|
-
message: z.string(),
|
|
228
|
-
}),
|
|
229
|
-
}),
|
|
230
|
-
]),
|
|
231
|
-
processResponse: (response) => {
|
|
232
|
-
if (response.success) {
|
|
233
|
-
return response.data
|
|
234
|
-
} else {
|
|
235
|
-
throw new Error(response.error.message)
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
getNextPageParam: (lastPage, pages) => {
|
|
239
|
-
if (lastPage.meta.page < lastPage.meta.totalPages) {
|
|
240
|
-
return lastPage.meta.page + 1
|
|
241
|
-
}
|
|
242
|
-
return undefined
|
|
243
|
-
},
|
|
244
|
-
select: (data) => {
|
|
245
|
-
return data.pages.flatMap((page) => page.data)
|
|
246
|
-
},
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
export function UsersList() {
|
|
250
|
-
const { page, limit } = routeApi.useSearch()
|
|
251
|
-
const { data, isLoading, error, fetchNextPage, hasNextPage } = usersList.use({
|
|
252
|
-
params: {
|
|
253
|
-
page,
|
|
254
|
-
limit,
|
|
255
|
-
},
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
if (isLoading) {
|
|
259
|
-
return <p>Loading...</p>
|
|
260
|
-
}
|
|
56
|
+
### 2. Register Schedulable Services
|
|
261
57
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
58
|
+
Register your schedulable services in a module's `onModuleInit` method (recommended approach):
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { inject, Injectable, Module, OnModuleInit } from '@navios/core'
|
|
62
|
+
import { SchedulerService } from '@navios/schedule'
|
|
265
63
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
Load more
|
|
275
|
-
</button>
|
|
276
|
-
</div>
|
|
277
|
-
)
|
|
64
|
+
@Module({})
|
|
65
|
+
export class AppModule implements OnModuleInit {
|
|
66
|
+
private readonly schedulerService = inject(SchedulerService)
|
|
67
|
+
|
|
68
|
+
async onModuleInit() {
|
|
69
|
+
// Register schedulable services
|
|
70
|
+
this.schedulerService.register(TaskService)
|
|
71
|
+
}
|
|
278
72
|
}
|
|
279
73
|
```
|
|
280
74
|
|
|
281
|
-
|
|
75
|
+
Alternatively, you can register services manually:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { Container } from '@navios/core'
|
|
79
|
+
import { SchedulerService } from '@navios/schedule'
|
|
80
|
+
|
|
81
|
+
const container = new Container()
|
|
82
|
+
const schedulerService = await container.get(SchedulerService)
|
|
83
|
+
|
|
84
|
+
// Register the schedulable service
|
|
85
|
+
schedulerService.register(TaskService)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Cron Expression Format
|
|
89
|
+
|
|
90
|
+
Cron expressions follow the standard 5 or 6 field format:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
# ┌────────────── second (optional, 0-59)
|
|
94
|
+
# │ ┌──────────── minute (0-59)
|
|
95
|
+
# │ │ ┌────────── hour (0-23)
|
|
96
|
+
# │ │ │ ┌──────── day of month (1-31)
|
|
97
|
+
# │ │ │ │ ┌────── month (1-12)
|
|
98
|
+
# │ │ │ │ │ ┌──── day of week (0-6, Sunday to Saturday)
|
|
99
|
+
# │ │ │ │ │ │
|
|
100
|
+
# │ │ │ │ │ │
|
|
101
|
+
# * * * * * *
|
|
102
|
+
```
|
|
282
103
|
|
|
283
|
-
###
|
|
104
|
+
### Examples:
|
|
284
105
|
|
|
285
|
-
|
|
106
|
+
- `'0 0 * * *'` - Daily at midnight
|
|
107
|
+
- `'*/5 * * * *'` - Every 5 minutes
|
|
108
|
+
- `'0 9 * * 1-5'` - Every weekday at 9 AM
|
|
109
|
+
- `'0 0 1 * *'` - First day of every month at midnight
|
|
110
|
+
- `'*/30 * * * * *'` - Every 30 seconds (6-field format)
|
|
286
111
|
|
|
287
|
-
-
|
|
112
|
+
## Pre-defined Schedule Constants
|
|
288
113
|
|
|
289
|
-
|
|
114
|
+
For common scheduling patterns, use the `Schedule` enum:
|
|
290
115
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
- `infiniteQuery`: A function that takes a configuration object and returns an infinite query object.
|
|
116
|
+
```typescript
|
|
117
|
+
import { Schedule } from '@navios/schedule'
|
|
294
118
|
|
|
295
|
-
|
|
119
|
+
@Schedulable()
|
|
120
|
+
class ExampleService {
|
|
121
|
+
@Cron(Schedule.EveryMinute)
|
|
122
|
+
async everyMinute() {}
|
|
296
123
|
|
|
297
|
-
|
|
124
|
+
@Cron(Schedule.EveryFiveMinutes)
|
|
125
|
+
async everyFiveMinutes() {}
|
|
298
126
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
- `querySchema`: A Zod schema for validating the query parameters. (optional)
|
|
302
|
-
- `responseSchema`: A Zod schema for validating the response data.
|
|
303
|
-
- `processResponse`: A function that takes the response data and returns the processed data. (optional, but recommended)
|
|
127
|
+
@Cron(Schedule.EveryHour)
|
|
128
|
+
async hourly() {}
|
|
304
129
|
|
|
305
|
-
|
|
130
|
+
@Cron(Schedule.EveryDay)
|
|
131
|
+
async daily() {}
|
|
306
132
|
|
|
307
|
-
|
|
308
|
-
|
|
133
|
+
@Cron(Schedule.EveryWeek)
|
|
134
|
+
async weekly() {}
|
|
309
135
|
|
|
310
|
-
|
|
136
|
+
@Cron(Schedule.EveryMonth)
|
|
137
|
+
async monthly() {}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Available constants:
|
|
142
|
+
|
|
143
|
+
- `EveryMinute` - `'*/1 * * * *'`
|
|
144
|
+
- `EveryFiveMinutes` - `'*/5 * * * *'`
|
|
145
|
+
- `EveryTenMinutes` - `'*/10 * * * *'`
|
|
146
|
+
- `EveryFifteenMinutes` - `'*/15 * * * *'`
|
|
147
|
+
- `EveryThirtyMinutes` - `'*/30 * * * *'`
|
|
148
|
+
- `EveryHour` - `'0 * * * *'`
|
|
149
|
+
- `EveryTwoHours` - `'0 */2 * * *'`
|
|
150
|
+
- `EveryThreeHours` - `'0 */3 * * *'`
|
|
151
|
+
- `EveryFourHours` - `'0 */4 * * *'`
|
|
152
|
+
- `EverySixHours` - `'0 */6 * * *'`
|
|
153
|
+
- `EveryTwelveHours` - `'0 */12 * * *'`
|
|
154
|
+
- `EveryDay` - `'0 0 * * *'`
|
|
155
|
+
- `EveryWeek` - `'0 0 * * 0'`
|
|
156
|
+
- `EveryMonth` - `'0 0 1 * *'`
|
|
157
|
+
|
|
158
|
+
## Advanced Usage
|
|
159
|
+
|
|
160
|
+
### Cron Options
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
@Schedulable()
|
|
164
|
+
class ConfigurableService {
|
|
165
|
+
@Cron('0 2 * * *', { disabled: true })
|
|
166
|
+
async maintenanceJob() {
|
|
167
|
+
// This job is disabled by default
|
|
168
|
+
console.log('Running maintenance...')
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Runtime Job Management
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
// Get a specific job
|
|
177
|
+
const job = schedulerService.getJob(TaskService, 'dailyCleanup')
|
|
178
|
+
console.log('Job is active:', job?.isActive)
|
|
179
|
+
|
|
180
|
+
// Start all jobs
|
|
181
|
+
schedulerService.startAll()
|
|
182
|
+
|
|
183
|
+
// Stop all jobs
|
|
184
|
+
schedulerService.stopAll()
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Multiple Jobs in One Service
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
@Schedulable()
|
|
191
|
+
class DataProcessingService {
|
|
192
|
+
@Cron('0 1 * * *') // 1 AM daily
|
|
193
|
+
async processUserData() {
|
|
194
|
+
console.log('Processing user data...')
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
@Cron('0 3 * * *') // 3 AM daily
|
|
198
|
+
async generateReports() {
|
|
199
|
+
console.log('Generating reports...')
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@Cron(Schedule.EveryFifteenMinutes)
|
|
203
|
+
async syncExternalData() {
|
|
204
|
+
console.log('Syncing external data...')
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Error Handling
|
|
210
|
+
|
|
211
|
+
The scheduler automatically handles errors in job execution:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
@Schedulable()
|
|
215
|
+
class RobustService {
|
|
216
|
+
@Cron(Schedule.EveryMinute)
|
|
217
|
+
async riskyJob() {
|
|
218
|
+
try {
|
|
219
|
+
// Your job logic here
|
|
220
|
+
await someRiskyOperation()
|
|
221
|
+
} catch (error) {
|
|
222
|
+
// Handle specific errors if needed
|
|
223
|
+
console.error('Job failed:', error)
|
|
224
|
+
throw error // Re-throw to let scheduler log it
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
311
229
|
|
|
312
|
-
|
|
230
|
+
Jobs that throw errors will:
|
|
313
231
|
|
|
314
|
-
|
|
232
|
+
- Be logged automatically by the scheduler
|
|
233
|
+
- Continue running on their schedule (errors don't stop the job)
|
|
234
|
+
- Not affect other jobs in the same or different services
|
|
315
235
|
|
|
316
|
-
|
|
236
|
+
## API Reference
|
|
317
237
|
|
|
318
|
-
|
|
238
|
+
### Decorators
|
|
319
239
|
|
|
320
|
-
|
|
240
|
+
#### `@Schedulable()`
|
|
321
241
|
|
|
322
|
-
|
|
242
|
+
Marks a class as schedulable and makes it injectable. Required for any class that contains `@Cron` decorated methods.
|
|
323
243
|
|
|
324
|
-
|
|
325
|
-
- `params`: An object with `urlParams` and `params` to invalidate the query. (required if `url` contains URL parameters or `querySchema` is defined)
|
|
244
|
+
#### `@Cron(cronTime, options?)`
|
|
326
245
|
|
|
327
|
-
|
|
246
|
+
Decorates a method to run on a cron schedule.
|
|
328
247
|
|
|
329
|
-
|
|
248
|
+
**Parameters:**
|
|
330
249
|
|
|
331
|
-
|
|
250
|
+
- `cronTime: string` - Cron expression (5 or 6 fields)
|
|
251
|
+
- `options?: CronOptions` - Optional configuration
|
|
252
|
+
- `disabled?: boolean` - Whether the job should be disabled by default
|
|
332
253
|
|
|
333
|
-
|
|
334
|
-
- `params`: An object with `urlParams` to invalidate the query. (required if `url` contains URL parameters)
|
|
254
|
+
### SchedulerService
|
|
335
255
|
|
|
336
|
-
|
|
256
|
+
#### Methods
|
|
337
257
|
|
|
338
|
-
|
|
258
|
+
- `register(service: ClassType)` - Register a schedulable service
|
|
259
|
+
- `getJob<T>(service: T, method: keyof InstanceType<T>): CronJob | undefined` - Get a specific job instance
|
|
260
|
+
- `startAll()` - Start all registered jobs
|
|
261
|
+
- `stopAll()` - Stop all registered jobs
|
|
339
262
|
|
|
340
|
-
|
|
263
|
+
## Best Practices
|
|
341
264
|
|
|
342
|
-
|
|
343
|
-
- `method`: The HTTP method to use (PATCH, POST, PUT, DELETE, etc.).
|
|
344
|
-
- `requestSchema`: A Zod schema for validating the request body.
|
|
345
|
-
- `responseSchema`: A Zod schema for validating the response data.
|
|
346
|
-
- `processResponse`: A function that takes the response data and returns the processed data. (optional, but recommended)
|
|
347
|
-
- `useContext`: A function that is called before the mutation is executed. It can be used to set the context for the onSuccess and onError. (optional)
|
|
348
|
-
- `onSuccess`: A function that is called when the mutation is successful. (optional)
|
|
349
|
-
- `onError`: A function that is called when the mutation fails. (optional)
|
|
350
|
-
- `useKey`: If true, the mutation will have a mutation key which can be used to get the mutation status, limit parallel requests, etc. (optional, defaults to false)
|
|
265
|
+
1. **Module Registration**: Always register schedulable services in a module's `onModuleInit` method for proper lifecycle management
|
|
351
266
|
|
|
352
|
-
|
|
267
|
+
2. **Error Handling**: Implement proper error handling within your job methods, but let the scheduler handle logging
|
|
353
268
|
|
|
354
|
-
|
|
269
|
+
3. **Resource Management**: Be mindful of long-running jobs that might overlap with subsequent executions
|
|
355
270
|
|
|
356
|
-
|
|
271
|
+
4. **Testing**: Use dependency injection to mock schedulable services in tests
|
|
357
272
|
|
|
358
|
-
|
|
273
|
+
5. **Monitoring**: Consider adding logging or monitoring to track job execution and failures
|
|
359
274
|
|
|
360
|
-
|
|
361
|
-
- `method`: The HTTP method to use (GET, POST, PUT, DELETE, etc.).
|
|
362
|
-
- `querySchema`: A Zod schema for validating the query parameters. (required)
|
|
363
|
-
- `responseSchema`: A Zod schema for validating the response data.
|
|
364
|
-
- `processResponse`: A function that takes the response data and returns the processed data. (optional, but recommended)
|
|
365
|
-
- `getNextPageParam`: A function that takes the last page and all pages and returns the next page param. (required)
|
|
366
|
-
- `initialPageData`: The initial data to use for the first page. (optional)
|
|
367
|
-
- `getPreviousPageParam`: A function that takes the first page and all pages and returns the previous page param. (optional)
|
|
368
|
-
- `select`: A function that takes the data and returns the selected data. (optional)
|
|
275
|
+
## Requirements
|
|
369
276
|
|
|
370
|
-
|
|
277
|
+
- Node.js 18+
|
|
278
|
+
- TypeScript 5.0+
|
|
279
|
+
- `@navios/core` for dependency injection
|
|
280
|
+
- `cron` package for job scheduling
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cron.decorator.d.mts","sourceRoot":"","sources":["../../../src/decorators/cron.decorator.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cron.decorator.d.mts","sourceRoot":"","sources":["../../../src/decorators/cron.decorator.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAIzC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,wBAAgB,IAAI,CAClB,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,EACnC,OAAO,CAAC,EAAE,WAAW,IAGnB,QAAQ,MAAM,OAAO,CAAC,IAAI,CAAC,EAC3B,SAAS,2BAA2B,WADtB,OAAO,CAAC,IAAI,CAAC,CAe9B"}
|
|
@@ -2,6 +2,7 @@ import type { ClassType } from '@navios/core';
|
|
|
2
2
|
import { CronJob } from 'cron';
|
|
3
3
|
export declare class SchedulerService {
|
|
4
4
|
private readonly logger;
|
|
5
|
+
private readonly container;
|
|
5
6
|
private readonly jobs;
|
|
6
7
|
register(service: ClassType): void;
|
|
7
8
|
getJob<T extends ClassType>(service: T, method: keyof InstanceType<T>): CronJob | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.service.d.mts","sourceRoot":"","sources":["../../src/scheduler.service.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"scheduler.service.d.mts","sourceRoot":"","sources":["../../src/scheduler.service.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAI7C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAS9B,qBACa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAErB;IACF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkC;IAEvD,QAAQ,CAAC,OAAO,EAAE,SAAS;IAW3B,MAAM,CAAC,CAAC,SAAS,SAAS,EACxB,OAAO,EAAE,CAAC,EACV,MAAM,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,GAC5B,OAAO,GAAG,SAAS;IAMtB,OAAO,CAAC,YAAY;IA4BpB,QAAQ;IASR,OAAO;CAQR"}
|