exisjs 0.7.11 → 0.7.13
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 +195 -39
- package/dist/cli/commands/dev.d.ts +4 -0
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +136 -32
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/run.d.ts +7 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +99 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/index.js +29 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/manifest.d.ts.map +1 -1
- package/dist/cli/manifest.js +18 -3
- package/dist/cli/manifest.js.map +1 -1
- package/dist/cli/routes.d.ts +6 -0
- package/dist/cli/routes.d.ts.map +1 -1
- package/dist/cli/routes.js +224 -135
- package/dist/cli/routes.js.map +1 -1
- package/dist/config/config.d.ts +2 -1
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +30 -9
- package/dist/config/types.d.ts.map +1 -1
- package/dist/database/lifecycle.d.ts +6 -1
- package/dist/database/lifecycle.d.ts.map +1 -1
- package/dist/database/lifecycle.js +15 -4
- package/dist/database/lifecycle.js.map +1 -1
- package/dist/decorators/params.d.ts +21 -0
- package/dist/decorators/params.d.ts.map +1 -1
- package/dist/decorators/params.js +21 -1
- package/dist/decorators/params.js.map +1 -1
- package/dist/di/container.d.ts +15 -6
- package/dist/di/container.d.ts.map +1 -1
- package/dist/di/container.js +26 -3
- package/dist/di/container.js.map +1 -1
- package/dist/di/index.d.ts +1 -1
- package/dist/di/index.d.ts.map +1 -1
- package/dist/di/index.js.map +1 -1
- package/dist/di/inject.d.ts +2 -1
- package/dist/di/inject.d.ts.map +1 -1
- package/dist/di/inject.js +2 -1
- package/dist/di/inject.js.map +1 -1
- package/dist/docs/BENCHMARKS.md +4 -4
- package/dist/docs/content/README.md +43 -44
- package/dist/docs/content/boundaries.mdx +141 -48
- package/dist/docs/content/cli/commands.mdx +161 -107
- package/dist/docs/content/cli/overview.mdx +61 -46
- package/dist/docs/content/cli/usage.mdx +107 -30
- package/dist/docs/content/config.mdx +145 -147
- package/dist/docs/content/controllers.mdx +193 -464
- package/dist/docs/content/cron.mdx +183 -69
- package/dist/docs/content/decorators.mdx +449 -154
- package/dist/docs/content/errors.mdx +202 -305
- package/dist/docs/content/exisjs-mcp.mdx +59 -49
- package/dist/docs/content/installation.mdx +243 -157
- package/dist/docs/content/introduction.mdx +220 -48
- package/dist/docs/content/middleware.mdx +171 -497
- package/dist/docs/content/modules.mdx +141 -83
- package/dist/docs/content/providers.mdx +216 -180
- package/dist/docs/content/requests.mdx +168 -488
- package/dist/docs/content/responses.mdx +200 -533
- package/dist/docs/content/routing.mdx +239 -558
- package/dist/docs/content/security.mdx +233 -57
- package/dist/docs/content/structure.mdx +151 -240
- package/dist/docs/content/swagger.mdx +192 -91
- package/dist/docs/content/testing.mdx +205 -74
- package/dist/docs/content/validation.mdx +479 -341
- package/dist/docs/reference/README.md +34 -2
- package/dist/docs/reference/config.mdx +277 -73
- package/dist/docs/reference/context.mdx +197 -106
- package/dist/docs/reference/cron.mdx +266 -152
- package/dist/docs/reference/database.mdx +135 -53
- package/dist/docs/reference/decorators.mdx +234 -116
- package/dist/docs/reference/di.mdx +146 -112
- package/dist/docs/reference/error.mdx +155 -178
- package/dist/docs/reference/exis.mdx +141 -70
- package/dist/docs/reference/logger.mdx +110 -126
- package/dist/docs/reference/middleware.mdx +235 -158
- package/dist/docs/reference/plugin.mdx +136 -64
- package/dist/docs/reference/router.mdx +277 -251
- package/dist/docs/reference/sanitize.mdx +91 -87
- package/dist/docs/reference/swagger.mdx +280 -100
- package/dist/docs/reference/testing.mdx +223 -89
- package/dist/docs/reference/validator.mdx +194 -206
- package/dist/lib/inspect-routes.d.ts +2 -0
- package/dist/lib/inspect-routes.d.ts.map +1 -0
- package/dist/lib/inspect-routes.js +148 -0
- package/dist/lib/inspect-routes.js.map +1 -0
- package/dist/lib/start-server.js +13 -8
- package/dist/lib/start-server.js.map +1 -1
- package/dist/module/module.d.ts +6 -3
- package/dist/module/module.d.ts.map +1 -1
- package/dist/module/module.js +17 -3
- package/dist/module/module.js.map +1 -1
- package/dist/router/controller-registrar.d.ts.map +1 -1
- package/dist/router/controller-registrar.js +26 -4
- package/dist/router/controller-registrar.js.map +1 -1
- package/dist/router/scanner/cron-mounter.d.ts.map +1 -1
- package/dist/router/scanner/cron-mounter.js +9 -2
- package/dist/router/scanner/cron-mounter.js.map +1 -1
- package/dist/server/app.d.ts +3 -1
- package/dist/server/app.d.ts.map +1 -1
- package/dist/server/app.js +29 -8
- package/dist/server/app.js.map +1 -1
- package/dist/server/define.d.ts.map +1 -1
- package/dist/server/define.js +5 -0
- package/dist/server/define.js.map +1 -1
- package/dist/server/request.d.ts +2 -0
- package/dist/server/request.d.ts.map +1 -1
- package/dist/server/request.js +11 -0
- package/dist/server/request.js.map +1 -1
- package/dist/swagger/generator.d.ts.map +1 -1
- package/dist/swagger/generator.js +130 -10
- package/dist/swagger/generator.js.map +1 -1
- package/dist/telemetry/index.d.ts +12 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +121 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/testing/client.d.ts +1 -0
- package/dist/testing/client.d.ts.map +1 -1
- package/dist/testing/client.js +4 -1
- package/dist/testing/client.js.map +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +20 -4
- package/dist/testing/index.js.map +1 -1
- package/dist/validator/builder.d.ts +26 -1
- package/dist/validator/builder.d.ts.map +1 -1
- package/dist/validator/builder.js +31 -0
- package/dist/validator/builder.js.map +1 -1
- package/dist/validator/engine.d.ts +23 -0
- package/dist/validator/engine.d.ts.map +1 -1
- package/dist/validator/engine.js +228 -31
- package/dist/validator/engine.js.map +1 -1
- package/dist/validator/index.d.ts +8 -4
- package/dist/validator/index.d.ts.map +1 -1
- package/dist/validator/index.js +4 -1
- package/dist/validator/index.js.map +1 -1
- package/dist/validator/tex-types.d.ts +15 -0
- package/dist/validator/tex-types.d.ts.map +1 -1
- package/dist/validator/tex-types.js +102 -0
- package/dist/validator/tex-types.js.map +1 -1
- package/dist/validator/tex.d.ts +1 -1
- package/dist/validator/tex.d.ts.map +1 -1
- package/dist/validator/tex.js +3 -1
- package/dist/validator/tex.js.map +1 -1
- package/dist/validator/types.d.ts +1 -0
- package/dist/validator/types.d.ts.map +1 -1
- package/package.json +47 -14
- package/dist/docs/content/dataloader.mdx +0 -170
- package/dist/docs/reference/dataloader.mdx +0 -91
|
@@ -1,41 +1,42 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
title: "Background Tasks and Cron"
|
|
3
|
+
description: "Schedule background tasks, recurring cron jobs, intervals, and startup timeouts with overlap prevention and drift correction in ExisJS."
|
|
4
|
+
nextUrl: "/docs/swagger"
|
|
5
|
+
nextTitle: "OpenAPI & Swagger"
|
|
4
6
|
---
|
|
5
7
|
|
|
6
|
-
#
|
|
8
|
+
# Background Tasks & Cron
|
|
7
9
|
|
|
8
|
-
ExisJS
|
|
10
|
+
ExisJS provides an integrated task scheduling system for background jobs, recurring intervals, and delayed timeouts. It eliminates common Node.js scheduling hazards including timer drift, execution overlap, unhandled exceptions crashing the process, timezone/DST inaccuracies, and lingering zombie timers during graceful shutdowns.
|
|
9
11
|
|
|
10
|
-
Both **Functional** and **Class-Based
|
|
12
|
+
Both **Functional** (`cron()`) and **Class-Based OOP** (`@Cron()`) paradigms are fully supported with complete feature parity.
|
|
11
13
|
|
|
12
14
|
---
|
|
13
15
|
|
|
14
16
|
## File Conventions & Auto-Discovery
|
|
15
17
|
|
|
16
|
-
ExisJS
|
|
18
|
+
ExisJS automatically discovers, compiles, and mounts scheduled cron tasks during server bootstrap using two flexible layout conventions:
|
|
17
19
|
|
|
18
|
-
1. **Single-File
|
|
19
|
-
Define and manage all your
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Organize distinct tasks into separate files inside `src/cron/` (e.g. `src/cron/sync.ts`, `src/cron/reports.ts`). Every file inside `src/cron/` is automatically registered upon application boot.
|
|
20
|
+
1. **Single-File / Root HTTP Convention (`src/http/cron.ts` or `src/http/cron.js`)**:
|
|
21
|
+
Define and manage all your application's background jobs in a single root file at `src/http/cron.ts`. You can also co-locate cron files within route slices (e.g., `src/http/admin/cron.ts` or `src/http/billing/cron.ts`). Multiple jobs can be exported using named exports, default exports, or an array of job definitions (`export default [job1, job2]`).
|
|
22
|
+
2. **Dedicated Task Directory (`src/cron/*`)**:
|
|
23
|
+
Organize individual tasks into separate files inside `src/cron/` (e.g., `src/cron/cleanup.ts`, `src/cron/sync.ts`). Every file inside `src/cron/` is automatically registered upon boot.
|
|
23
24
|
|
|
24
25
|
---
|
|
25
26
|
|
|
26
27
|
## 1. Functional Paradigm (`cron`)
|
|
27
28
|
|
|
28
|
-
Import `cron` from `exisjs/cron` to define scheduled tasks.
|
|
29
|
+
Import `cron` and `CronExpression` from `exisjs/cron` to define scheduled background tasks.
|
|
29
30
|
|
|
30
|
-
### Single-File
|
|
31
|
+
### Root Single-File Management (`src/http/cron.ts`)
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
You can define and export all your application's background tasks directly within `src/http/cron.ts`:
|
|
33
34
|
|
|
34
35
|
```typescript filename="src/http/cron.ts"
|
|
35
36
|
import { cron, CronExpression } from 'exisjs/cron'
|
|
36
37
|
|
|
37
|
-
//
|
|
38
|
-
export const
|
|
38
|
+
// Task 1: Nightly synchronization at midnight UTC
|
|
39
|
+
export const nightlySync = cron({
|
|
39
40
|
name: 'nightly-sync',
|
|
40
41
|
schedule: CronExpression.EVERY_DAY_AT_MIDNIGHT,
|
|
41
42
|
timezone: 'UTC',
|
|
@@ -43,30 +44,58 @@ export const syncJob = cron({
|
|
|
43
44
|
retries: 2,
|
|
44
45
|
retryDelayMs: 3000,
|
|
45
46
|
async run({ app, log }) {
|
|
46
|
-
log.info('
|
|
47
|
+
log.info('Running nightly data synchronization...')
|
|
47
48
|
},
|
|
48
49
|
onError(err, { log }) {
|
|
49
|
-
log.error({ err }, 'Nightly sync failed after
|
|
50
|
+
log.error({ err }, 'Nightly sync failed after retry attempts')
|
|
50
51
|
}
|
|
51
52
|
})
|
|
52
53
|
|
|
53
|
-
//
|
|
54
|
-
export const
|
|
55
|
-
log.info('
|
|
54
|
+
// Task 2: Human-readable duration schedule
|
|
55
|
+
export const queuePoller = cron.every('5 minutes', async ({ log }) => {
|
|
56
|
+
log.info('Polling external queue...')
|
|
57
|
+
}, {
|
|
58
|
+
name: 'queue-poller',
|
|
59
|
+
preventOverlap: true
|
|
56
60
|
})
|
|
57
61
|
|
|
58
|
-
//
|
|
62
|
+
// Task 3: Fixed millisecond interval
|
|
59
63
|
export const heartbeat = cron.interval(30_000, async ({ log }) => {
|
|
60
64
|
log.info('System heartbeat active')
|
|
65
|
+
}, {
|
|
66
|
+
name: 'health-heartbeat'
|
|
61
67
|
})
|
|
62
68
|
|
|
63
|
-
//
|
|
64
|
-
export const
|
|
65
|
-
log.info('Pre-warming cache...')
|
|
69
|
+
// Task 4: One-time startup delayed task (runs 5s after server boots)
|
|
70
|
+
export const cacheWarmup = cron.timeout(5_000, async ({ log }) => {
|
|
71
|
+
log.info('Pre-warming cache in memory...')
|
|
72
|
+
}, {
|
|
73
|
+
name: 'cache-warmup'
|
|
66
74
|
})
|
|
67
75
|
```
|
|
68
76
|
|
|
69
|
-
###
|
|
77
|
+
### Exporting an Array of Jobs (`export default [...]`)
|
|
78
|
+
|
|
79
|
+
In both `src/http/cron.ts` and `src/cron/*.ts`, you can also export an array of jobs as the default export:
|
|
80
|
+
|
|
81
|
+
```typescript filename="src/http/cron.ts"
|
|
82
|
+
import { cron, CronExpression } from 'exisjs/cron'
|
|
83
|
+
|
|
84
|
+
export default [
|
|
85
|
+
cron({
|
|
86
|
+
name: 'session-cleanup',
|
|
87
|
+
schedule: CronExpression.EVERY_HOUR,
|
|
88
|
+
async run({ log }) {
|
|
89
|
+
log.info('Purging expired sessions...')
|
|
90
|
+
}
|
|
91
|
+
}),
|
|
92
|
+
cron.interval(60_000, async ({ log }) => {
|
|
93
|
+
log.info('Checking worker status...')
|
|
94
|
+
}, { name: 'worker-status' })
|
|
95
|
+
]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Dedicated File Convention (`src/cron/cleanup.ts`)
|
|
70
99
|
|
|
71
100
|
```typescript filename="src/cron/cleanup.ts"
|
|
72
101
|
import { cron, CronExpression } from 'exisjs/cron'
|
|
@@ -86,111 +115,196 @@ export default cron({
|
|
|
86
115
|
|
|
87
116
|
## 2. Class-Based (OOP) Paradigm (`@Cron`)
|
|
88
117
|
|
|
89
|
-
In
|
|
118
|
+
In class-based applications, schedule methods on `@Injectable()` service classes using decorators from `exisjs/decorators` with full **Dependency Injection** support.
|
|
90
119
|
|
|
91
|
-
```typescript filename="src/cron/
|
|
120
|
+
```typescript filename="src/cron/maintenance.service.ts"
|
|
92
121
|
import { Injectable, Cron, Interval, TimeoutTask, CronExpression } from 'exisjs/decorators'
|
|
93
|
-
import { DatabaseService } from '../
|
|
94
|
-
import { LoggerService } from '../
|
|
122
|
+
import { DatabaseService } from '../database/database.service'
|
|
123
|
+
import { LoggerService } from '../common/logger.service'
|
|
95
124
|
|
|
96
125
|
@Injectable()
|
|
97
|
-
export default class
|
|
126
|
+
export default class MaintenanceService {
|
|
98
127
|
constructor(
|
|
99
|
-
private db: DatabaseService,
|
|
100
|
-
private logger: LoggerService
|
|
128
|
+
private readonly db: DatabaseService,
|
|
129
|
+
private readonly logger: LoggerService
|
|
101
130
|
) {}
|
|
102
131
|
|
|
103
132
|
@Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT, {
|
|
104
133
|
name: 'nightly-purge',
|
|
105
134
|
timezone: 'UTC',
|
|
106
135
|
preventOverlap: true,
|
|
136
|
+
retries: 2,
|
|
137
|
+
retryDelayMs: 5000,
|
|
107
138
|
})
|
|
108
|
-
async
|
|
139
|
+
async purgeExpiredSessions() {
|
|
109
140
|
this.logger.info('Purging expired user sessions...')
|
|
110
141
|
await this.db.deleteExpiredSessions()
|
|
111
142
|
}
|
|
112
143
|
|
|
113
|
-
@Interval(60_000, {
|
|
114
|
-
|
|
144
|
+
@Interval(60_000, {
|
|
145
|
+
name: 'db-health-check',
|
|
146
|
+
preventOverlap: true,
|
|
147
|
+
})
|
|
148
|
+
async pingDatabase() {
|
|
115
149
|
await this.db.ping()
|
|
116
150
|
}
|
|
117
151
|
|
|
118
|
-
@TimeoutTask(5_000, {
|
|
152
|
+
@TimeoutTask(5_000, {
|
|
153
|
+
name: 'cache-init',
|
|
154
|
+
})
|
|
119
155
|
async warmupCache() {
|
|
120
|
-
this.logger.info('Pre-warming cache...')
|
|
156
|
+
this.logger.info('Pre-warming cache after server boot...')
|
|
121
157
|
}
|
|
122
158
|
}
|
|
123
159
|
```
|
|
124
160
|
|
|
125
161
|
---
|
|
126
162
|
|
|
127
|
-
##
|
|
163
|
+
## Configuration Options (`CronJobOptions`)
|
|
164
|
+
|
|
165
|
+
The following options configure job execution, error recovery, and scheduling policies:
|
|
166
|
+
|
|
167
|
+
| Option | Type | Default | Description |
|
|
168
|
+
| :--- | :--- | :--- | :--- |
|
|
169
|
+
| `name` | `string` | Auto-generated | Unique identifier for the job, used in logs and programmatic management. |
|
|
170
|
+
| `schedule` | `string` | — | Standard 5-part or 6-part cron pattern (e.g., `'0 0 * * *'`). |
|
|
171
|
+
| `interval` | `number` | — | Execution interval in milliseconds (used with interval jobs). |
|
|
172
|
+
| `timeout` | `number` | — | Startup delay in milliseconds before executing once (used with timeout jobs). |
|
|
173
|
+
| `timezone` | `string` | System Local | IANA timezone identifier (e.g., `'UTC'`, `'America/New_York'`, `'Asia/Kolkata'`). |
|
|
174
|
+
| `preventOverlap` | `boolean` | `true` | When `true`, skips execution if the previous tick is still running. |
|
|
175
|
+
| `autoStart` | `boolean` | `true` | Automatically starts the scheduler when the job is registered. |
|
|
176
|
+
| `retries` | `number` | `0` | Number of retry attempts if the handler throws an error. |
|
|
177
|
+
| `retryDelayMs` | `number` | `1000` | Milliseconds to wait between retry attempts. |
|
|
178
|
+
| `run` / `handle` | `(ctx) => Promise<any>` | — | The execution handler function receiving `CronContext`. |
|
|
179
|
+
| `onError` | `(err, ctx) => void` | — | Optional callback triggered when all execution attempts fail. |
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Execution Context (`CronContext`)
|
|
184
|
+
|
|
185
|
+
Every job handler receives a `CronContext` object containing execution metadata and framework instances:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
export interface CronContext {
|
|
189
|
+
/** The Exis application instance */
|
|
190
|
+
app: App<any>
|
|
191
|
+
/** Structured logger instance */
|
|
192
|
+
log: Logger
|
|
193
|
+
/** Name of the running job */
|
|
194
|
+
jobName: string
|
|
195
|
+
/** Timestamp when this execution iteration started */
|
|
196
|
+
startedAt: Date
|
|
197
|
+
/** Current execution iteration count */
|
|
198
|
+
iteration: number
|
|
199
|
+
/** Signal aborted when graceful server shutdown is initiated */
|
|
200
|
+
signal?: AbortSignal
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Standard Cron Expression Constants (`CronExpression`)
|
|
207
|
+
|
|
208
|
+
ExisJS exports pre-tested cron expressions for common schedules:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import { CronExpression } from 'exisjs/cron'
|
|
212
|
+
|
|
213
|
+
CronExpression.EVERY_SECOND // '* * * * * *'
|
|
214
|
+
CronExpression.EVERY_5_SECONDS // '*/5 * * * * *'
|
|
215
|
+
CronExpression.EVERY_10_SECONDS // '*/10 * * * * *'
|
|
216
|
+
CronExpression.EVERY_30_SECONDS // '*/30 * * * * *'
|
|
217
|
+
CronExpression.EVERY_MINUTE // '* * * * *'
|
|
218
|
+
CronExpression.EVERY_5_MINUTES // '*/5 * * * *'
|
|
219
|
+
CronExpression.EVERY_10_MINUTES // '*/10 * * * *'
|
|
220
|
+
CronExpression.EVERY_30_MINUTES // '*/30 * * * *'
|
|
221
|
+
CronExpression.EVERY_HOUR // '0 * * * *'
|
|
222
|
+
CronExpression.EVERY_2_HOURS // '0 */2 * * *'
|
|
223
|
+
CronExpression.EVERY_6_HOURS // '0 */6 * * *'
|
|
224
|
+
CronExpression.EVERY_DAY_AT_MIDNIGHT // '0 0 * * *'
|
|
225
|
+
CronExpression.EVERY_DAY_AT_1AM // '0 1 * * *'
|
|
226
|
+
CronExpression.EVERY_DAY_AT_2AM // '0 2 * * *'
|
|
227
|
+
CronExpression.EVERY_DAY_AT_NOON // '0 12 * * *'
|
|
228
|
+
CronExpression.EVERY_WEEK // '0 0 * * 0'
|
|
229
|
+
CronExpression.EVERY_WEEKDAY // '0 0 * * 1-5'
|
|
230
|
+
CronExpression.EVERY_WEEKEND // '0 0 * * 6,0'
|
|
231
|
+
CronExpression.EVERY_MONTH // '0 0 1 * *'
|
|
232
|
+
CronExpression.EVERY_YEAR // '0 0 1 1 *'
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Core Reliability Guarantees
|
|
238
|
+
|
|
239
|
+
### 1. Overlap Prevention (`preventOverlap: true`)
|
|
240
|
+
If a job takes longer than its scheduling frequency (for example, a database migration running for 90 seconds on a 60-second interval), standard Node.js timers cause overlapping concurrent runs. ExisJS locks execution during active runs and skips overlapping ticks until the current run completes.
|
|
128
241
|
|
|
129
|
-
###
|
|
130
|
-
|
|
242
|
+
### 2. Isolated Error Sandbox
|
|
243
|
+
Exceptions thrown inside cron handlers are caught within an isolated execution boundary. An uncaught error in a background task will never crash the HTTP server or prevent subsequent scheduled runs. Errors are logged with execution duration and forwarded to your `onError` handler.
|
|
131
244
|
|
|
132
|
-
###
|
|
133
|
-
|
|
245
|
+
### 3. Accurate Timezone & DST Calculation
|
|
246
|
+
Cron schedules evaluate IANA timezones (e.g. `'America/Chicago'`, `'Europe/Berlin'`, `'UTC'`) using native `Intl.DateTimeFormat` evaluations, adjusting accurately for Daylight Saving Time (DST) transitions.
|
|
134
247
|
|
|
135
|
-
###
|
|
136
|
-
|
|
248
|
+
### 4. Graceful Shutdown & Drain Window
|
|
249
|
+
When the server receives `SIGTERM` or `SIGINT`:
|
|
250
|
+
1. The scheduler halts all future timer registrations.
|
|
251
|
+
2. Active timers are unreferenced (`timer.unref()`).
|
|
252
|
+
3. Running tasks are allowed to complete within the configurable drain window (default: 5000ms) before the process terminates.
|
|
137
253
|
|
|
138
254
|
---
|
|
139
255
|
|
|
140
|
-
##
|
|
256
|
+
## Programmatic Management (`app.cron`)
|
|
141
257
|
|
|
142
|
-
|
|
258
|
+
Manage registered jobs dynamically at runtime from HTTP endpoints or administrative services via `app.cron`:
|
|
143
259
|
|
|
144
|
-
```typescript filename="src/http/admin/
|
|
260
|
+
```typescript filename="src/http/admin/tasks/route.ts"
|
|
145
261
|
import { controller, route } from 'exisjs/router'
|
|
146
262
|
|
|
147
263
|
export default controller({
|
|
148
|
-
//
|
|
149
|
-
|
|
264
|
+
// Get execution statistics and status for all jobs
|
|
265
|
+
listStats: route.get('/', async ({ app }) => {
|
|
150
266
|
return {
|
|
151
|
-
jobs: app.cron.
|
|
267
|
+
jobs: app.cron.getStats()
|
|
152
268
|
}
|
|
153
269
|
}),
|
|
154
270
|
|
|
155
|
-
// Manually trigger
|
|
271
|
+
// Manually trigger an immediate execution
|
|
156
272
|
triggerJob: route.post('/:name/trigger', async ({ app, params }) => {
|
|
157
273
|
const result = await app.cron.trigger(params.name)
|
|
158
274
|
return { success: true, result }
|
|
159
275
|
}),
|
|
160
276
|
|
|
161
|
-
// Pause a job
|
|
277
|
+
// Pause a running job
|
|
162
278
|
pauseJob: route.post('/:name/pause', async ({ app, params }) => {
|
|
163
|
-
app.cron.
|
|
279
|
+
const job = app.cron.getJob(params.name)
|
|
280
|
+
if (!job) return { success: false, error: 'Job not found' }
|
|
281
|
+
|
|
282
|
+
job.pause()
|
|
164
283
|
return { success: true, message: `Job ${params.name} paused` }
|
|
165
284
|
}),
|
|
166
285
|
|
|
167
286
|
// Resume a paused job
|
|
168
287
|
resumeJob: route.post('/:name/resume', async ({ app, params }) => {
|
|
169
|
-
app.cron.
|
|
288
|
+
const job = app.cron.getJob(params.name)
|
|
289
|
+
if (!job) return { success: false, error: 'Job not found' }
|
|
290
|
+
|
|
291
|
+
job.resume()
|
|
170
292
|
return { success: true, message: `Job ${params.name} resumed` }
|
|
171
|
-
})
|
|
293
|
+
})
|
|
172
294
|
})
|
|
173
295
|
```
|
|
174
296
|
|
|
175
297
|
---
|
|
176
298
|
|
|
177
|
-
##
|
|
299
|
+
## CLI Generation
|
|
178
300
|
|
|
179
|
-
|
|
180
|
-
1. The scheduler stops scheduling future ticks immediately.
|
|
181
|
-
2. Active timers are unreferenced (`unref()`).
|
|
182
|
-
3. Running tasks are allowed to finish within the configured drain window (default: 5000ms) before the process terminates.
|
|
183
|
-
|
|
184
|
-
---
|
|
185
|
-
|
|
186
|
-
## 6. CLI Scaffolding
|
|
187
|
-
|
|
188
|
-
Generate cron job files using the ExisJS CLI:
|
|
301
|
+
Scaffold new scheduled tasks with the ExisJS CLI:
|
|
189
302
|
|
|
190
303
|
```bash
|
|
191
|
-
# Functional
|
|
304
|
+
# Functional job (generates src/cron/cleanup.ts)
|
|
192
305
|
npx exis generate cron cleanup
|
|
193
306
|
|
|
194
|
-
# Class-
|
|
307
|
+
# Class-based OOP service (generates src/cron/cleanup.service.ts with @Injectable & @Cron)
|
|
195
308
|
npx exis generate cron cleanup --oop
|
|
196
309
|
```
|
|
310
|
+
|