jm2 0.1.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/GNU-AGPL-3.0 +665 -0
- package/README.md +603 -0
- package/bin/jm2.js +24 -0
- package/package.json +70 -0
- package/src/cli/commands/add.js +206 -0
- package/src/cli/commands/config.js +212 -0
- package/src/cli/commands/edit.js +198 -0
- package/src/cli/commands/export.js +61 -0
- package/src/cli/commands/flush.js +132 -0
- package/src/cli/commands/history.js +179 -0
- package/src/cli/commands/import.js +180 -0
- package/src/cli/commands/list.js +174 -0
- package/src/cli/commands/logs.js +415 -0
- package/src/cli/commands/pause.js +97 -0
- package/src/cli/commands/remove.js +107 -0
- package/src/cli/commands/restart.js +68 -0
- package/src/cli/commands/resume.js +96 -0
- package/src/cli/commands/run.js +115 -0
- package/src/cli/commands/show.js +159 -0
- package/src/cli/commands/start.js +46 -0
- package/src/cli/commands/status.js +47 -0
- package/src/cli/commands/stop.js +48 -0
- package/src/cli/index.js +274 -0
- package/src/cli/utils/output.js +267 -0
- package/src/cli/utils/prompts.js +56 -0
- package/src/core/config.js +227 -0
- package/src/core/history-db.js +439 -0
- package/src/core/job.js +329 -0
- package/src/core/logger.js +382 -0
- package/src/core/storage.js +315 -0
- package/src/daemon/executor.js +409 -0
- package/src/daemon/index.js +873 -0
- package/src/daemon/scheduler.js +465 -0
- package/src/ipc/client.js +112 -0
- package/src/ipc/protocol.js +183 -0
- package/src/ipc/server.js +92 -0
- package/src/utils/cron.js +205 -0
- package/src/utils/datetime.js +237 -0
- package/src/utils/duration.js +226 -0
- package/src/utils/paths.js +164 -0
package/README.md
ADDED
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
# JM2 - Job Manager 2
|
|
2
|
+
|
|
3
|
+
A simple yet powerful job scheduler for Node.js, combining the functionality of `cron` (periodic tasks) and `at` (one-time tasks). Designed to be as easy to use as pm2.
|
|
4
|
+
|
|
5
|
+
<a href="https://www.buymeacoffee.com/landicefuy" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 🔄 **Periodic Jobs** - Schedule recurring tasks using cron expressions
|
|
10
|
+
- ⏰ **One-time Jobs** - Schedule tasks to run once at a specific time
|
|
11
|
+
- 💾 **Persistent Storage** - Jobs survive daemon restarts and system reboots
|
|
12
|
+
- 🖥️ **Simple CLI** - Intuitive command-line interface inspired by pm2
|
|
13
|
+
- 📊 **Job Monitoring** - View job status, history, and logs
|
|
14
|
+
- 🏷️ **Job Tagging** - Organize jobs with tags for easy management
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### Global Installation (Recommended)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g jm2
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Using npx (No Installation Required)
|
|
25
|
+
|
|
26
|
+
You can use jm2 directly with npx without installing it globally:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Start the daemon
|
|
30
|
+
npx jm2 start
|
|
31
|
+
|
|
32
|
+
# Add a job
|
|
33
|
+
npx jm2 add "echo 'Hello World'" --cron "* * * * *" --name hello
|
|
34
|
+
|
|
35
|
+
# List jobs
|
|
36
|
+
npx jm2 list
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Note:** When using npx, the daemon will also run without global installation. All commands work the same way.
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Start the daemon
|
|
45
|
+
jm2 start
|
|
46
|
+
|
|
47
|
+
# Add a periodic job (runs every minute)
|
|
48
|
+
jm2 add "echo 'Hello World'" --cron "* * * * *" --name hello
|
|
49
|
+
|
|
50
|
+
# Add a one-time job (runs at specific time)
|
|
51
|
+
jm2 add "node backup.js" --at "2024-12-25 10:00" --name christmas-backup
|
|
52
|
+
|
|
53
|
+
# List all jobs
|
|
54
|
+
jm2 list
|
|
55
|
+
|
|
56
|
+
# Stop the daemon
|
|
57
|
+
jm2 stop
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## CLI Reference
|
|
61
|
+
|
|
62
|
+
### Daemon Management
|
|
63
|
+
|
|
64
|
+
#### `jm2 start`
|
|
65
|
+
Start the JM2 daemon process.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
jm2 start
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Options:
|
|
72
|
+
- `--foreground, -f` - Run in foreground (don't daemonize)
|
|
73
|
+
|
|
74
|
+
#### `jm2 stop`
|
|
75
|
+
Stop the JM2 daemon process.
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
jm2 stop
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### `jm2 restart`
|
|
82
|
+
Restart the JM2 daemon process.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
jm2 restart
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### `jm2 status`
|
|
89
|
+
Show daemon status and statistics.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
jm2 status
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Output example:
|
|
96
|
+
```
|
|
97
|
+
JM2 Daemon Status
|
|
98
|
+
─────────────────────────────────
|
|
99
|
+
Status: Running
|
|
100
|
+
PID: 12345
|
|
101
|
+
Uptime: 2d 5h 30m
|
|
102
|
+
Jobs: 15 total (10 active, 5 paused)
|
|
103
|
+
Executed: 1,234 runs today
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Job Management
|
|
107
|
+
|
|
108
|
+
#### `jm2 add <command>`
|
|
109
|
+
Add a new scheduled job.
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Periodic job with cron expression
|
|
113
|
+
jm2 add "npm run backup" --cron "0 2 * * *" --name nightly-backup
|
|
114
|
+
|
|
115
|
+
# One-time job at specific datetime
|
|
116
|
+
jm2 add "node deploy.js" --at "2024-12-25 10:00" --name deploy
|
|
117
|
+
|
|
118
|
+
# One-time job with relative time
|
|
119
|
+
jm2 add "echo 'reminder'" --in "30m" --name reminder
|
|
120
|
+
|
|
121
|
+
# Job without name (auto-generates job-1, job-2, etc.)
|
|
122
|
+
jm2 add "echo 'quick task'" --in "5m"
|
|
123
|
+
|
|
124
|
+
# Job with duplicate name handling
|
|
125
|
+
jm2 add "npm run backup" --cron "0 3 * * *" --name backup --auto-suffix
|
|
126
|
+
# If "backup" exists, creates "backup-2", "backup-3", etc.
|
|
127
|
+
|
|
128
|
+
# Job with tags
|
|
129
|
+
jm2 add "npm test" --cron "0 * * * *" --name hourly-test --tag ci --tag testing
|
|
130
|
+
|
|
131
|
+
# Job with working directory
|
|
132
|
+
jm2 add "npm run build" --cron "0 0 * * *" --name build --cwd /path/to/project
|
|
133
|
+
|
|
134
|
+
# Job with environment variables
|
|
135
|
+
jm2 add "node app.js" --cron "*/5 * * * *" --name app --env NODE_ENV=production --env PORT=3000
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Options:
|
|
139
|
+
- `--cron, -c <expression>` - Cron expression for periodic jobs
|
|
140
|
+
- `--at, -a <datetime>` - Specific datetime for one-time jobs (see [Datetime Format](#datetime-format-for---at))
|
|
141
|
+
- `--in, -i <duration>` - Relative time for one-time jobs (e.g., "30m", "2h", "1d")
|
|
142
|
+
- `--name, -n <name>` - Job name (optional, auto-generates `job-1`, `job-2`, etc. if not provided). **Error if name already exists** unless `--auto-suffix` is used
|
|
143
|
+
- `--auto-suffix` - Auto-add suffix (`-2`, `-3`, etc.) if name already exists
|
|
144
|
+
- `--tag, -t <tag>` - Add tag(s) to the job (can be used multiple times)
|
|
145
|
+
- `--cwd <path>` - Working directory for the command
|
|
146
|
+
- `--env, -e <KEY=value>` - Environment variable (can be used multiple times)
|
|
147
|
+
- `--shell <shell>` - Shell to use (default: /bin/sh on Unix, cmd.exe on Windows)
|
|
148
|
+
- `--timeout <duration>` - Maximum execution time (e.g., "5m", "1h")
|
|
149
|
+
- `--retry <count>` - Number of retries on failure (default: 0)
|
|
150
|
+
- `--paused` - Add job in paused state
|
|
151
|
+
|
|
152
|
+
#### `jm2 list`
|
|
153
|
+
List all scheduled jobs.
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# List all jobs
|
|
157
|
+
jm2 list
|
|
158
|
+
|
|
159
|
+
# List jobs with specific tag
|
|
160
|
+
jm2 list --tag backup
|
|
161
|
+
|
|
162
|
+
# List only active jobs
|
|
163
|
+
jm2 list --active
|
|
164
|
+
|
|
165
|
+
# List only paused jobs
|
|
166
|
+
jm2 list --paused
|
|
167
|
+
|
|
168
|
+
# Show detailed output
|
|
169
|
+
jm2 list --verbose
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Options:
|
|
173
|
+
- `--tag, -t <tag>` - Filter by tag
|
|
174
|
+
- `--active` - Show only active jobs
|
|
175
|
+
- `--paused` - Show only paused jobs
|
|
176
|
+
- `--verbose, -v` - Show detailed information
|
|
177
|
+
|
|
178
|
+
Output example:
|
|
179
|
+
```
|
|
180
|
+
┌────┬──────────────────┬────────┬─────────────────┬──────────────────────┬────────────┐
|
|
181
|
+
│ ID │ Name │ Status │ Schedule │ Next Run │ Last Run │
|
|
182
|
+
├────┼──────────────────┼────────┼─────────────────┼──────────────────────┼────────────┤
|
|
183
|
+
│ 1 │ nightly-backup │ active │ 0 2 * * * │ 2024-12-20 02:00:00 │ 2h ago │
|
|
184
|
+
│ 2 │ hourly-test │ active │ 0 * * * * │ 2024-12-19 15:00:00 │ 45m ago │
|
|
185
|
+
│ 3 │ deploy │ active │ at 2024-12-25 │ 2024-12-25 10:00:00 │ never │
|
|
186
|
+
│ 4 │ old-task │ paused │ */5 * * * * │ - │ 3d ago │
|
|
187
|
+
└────┴──────────────────┴────────┴─────────────────┴──────────────────────┴────────────┘
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
#### `jm2 show <id|name>`
|
|
191
|
+
Show detailed information about a specific job.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
jm2 show nightly-backup
|
|
195
|
+
jm2 show 1
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Output example:
|
|
199
|
+
```
|
|
200
|
+
Job: nightly-backup (ID: 1)
|
|
201
|
+
───────────────────────────────────
|
|
202
|
+
Command: npm run backup
|
|
203
|
+
Schedule: 0 2 * * * (cron)
|
|
204
|
+
Status: active
|
|
205
|
+
Created: 2024-12-01 10:30:00
|
|
206
|
+
Tags: backup, database
|
|
207
|
+
|
|
208
|
+
Working Dir: /home/user/project
|
|
209
|
+
Environment:
|
|
210
|
+
NODE_ENV=production
|
|
211
|
+
DB_HOST=localhost
|
|
212
|
+
|
|
213
|
+
Execution History (last 5):
|
|
214
|
+
✓ 2024-12-19 02:00:00 - completed in 45s (exit: 0)
|
|
215
|
+
✓ 2024-12-18 02:00:00 - completed in 42s (exit: 0)
|
|
216
|
+
✗ 2024-12-17 02:00:00 - failed in 12s (exit: 1)
|
|
217
|
+
✓ 2024-12-16 02:00:00 - completed in 44s (exit: 0)
|
|
218
|
+
✓ 2024-12-15 02:00:00 - completed in 43s (exit: 0)
|
|
219
|
+
|
|
220
|
+
Next Run: 2024-12-20 02:00:00 (in 8h 30m)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### `jm2 remove <id|name>`
|
|
224
|
+
Remove a scheduled job.
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
jm2 remove nightly-backup
|
|
228
|
+
jm2 remove 1
|
|
229
|
+
|
|
230
|
+
# Remove multiple jobs
|
|
231
|
+
jm2 remove 1 2 3
|
|
232
|
+
|
|
233
|
+
# Remove by tag
|
|
234
|
+
jm2 remove --tag old-jobs
|
|
235
|
+
|
|
236
|
+
# Force remove without confirmation
|
|
237
|
+
jm2 remove nightly-backup --force
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Options:
|
|
241
|
+
- `--tag, -t <tag>` - Remove all jobs with this tag
|
|
242
|
+
- `--force, -f` - Skip confirmation prompt
|
|
243
|
+
|
|
244
|
+
#### `jm2 pause <id|name>`
|
|
245
|
+
Pause a scheduled job.
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
jm2 pause nightly-backup
|
|
249
|
+
jm2 pause 1
|
|
250
|
+
|
|
251
|
+
# Pause multiple jobs
|
|
252
|
+
jm2 pause 1 2 3
|
|
253
|
+
|
|
254
|
+
# Pause by tag
|
|
255
|
+
jm2 pause --tag testing
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Options:
|
|
259
|
+
- `--tag, -t <tag>` - Pause all jobs with this tag
|
|
260
|
+
|
|
261
|
+
#### `jm2 resume <id|name>`
|
|
262
|
+
Resume a paused job.
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
jm2 resume nightly-backup
|
|
266
|
+
jm2 resume 1
|
|
267
|
+
|
|
268
|
+
# Resume multiple jobs
|
|
269
|
+
jm2 resume 1 2 3
|
|
270
|
+
|
|
271
|
+
# Resume by tag
|
|
272
|
+
jm2 resume --tag testing
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Options:
|
|
276
|
+
- `--tag, -t <tag>` - Resume all jobs with this tag
|
|
277
|
+
|
|
278
|
+
#### `jm2 run <id|name>`
|
|
279
|
+
Manually trigger a job to run immediately.
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
jm2 run nightly-backup
|
|
283
|
+
jm2 run 1
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Options:
|
|
287
|
+
- `--wait, -w` - Wait for job to complete and show output
|
|
288
|
+
|
|
289
|
+
#### `jm2 edit <id|name>`
|
|
290
|
+
Edit an existing job's configuration.
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# Change cron schedule
|
|
294
|
+
jm2 edit nightly-backup --cron "0 3 * * *"
|
|
295
|
+
|
|
296
|
+
# Change command
|
|
297
|
+
jm2 edit nightly-backup --command "npm run full-backup"
|
|
298
|
+
|
|
299
|
+
# Add/remove tags
|
|
300
|
+
jm2 edit nightly-backup --tag important --untag old
|
|
301
|
+
|
|
302
|
+
# Change working directory
|
|
303
|
+
jm2 edit nightly-backup --cwd /new/path
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Options:
|
|
307
|
+
- `--cron, -c <expression>` - New cron expression
|
|
308
|
+
- `--at, -a <datetime>` - Convert to one-time job at datetime
|
|
309
|
+
- `--command <cmd>` - New command to execute
|
|
310
|
+
- `--name, -n <name>` - Rename the job
|
|
311
|
+
- `--tag, -t <tag>` - Add tag (can be used multiple times)
|
|
312
|
+
- `--untag <tag>` - Remove tag (can be used multiple times)
|
|
313
|
+
- `--cwd <path>` - New working directory
|
|
314
|
+
- `--env, -e <KEY=value>` - Set/update environment variable
|
|
315
|
+
- `--unenv <KEY>` - Remove environment variable
|
|
316
|
+
- `--timeout <duration>` - New timeout value
|
|
317
|
+
- `--retry <count>` - New retry count
|
|
318
|
+
|
|
319
|
+
### Logs and History
|
|
320
|
+
|
|
321
|
+
#### `jm2 logs [id|name]`
|
|
322
|
+
View job execution logs.
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
# View all recent logs
|
|
326
|
+
jm2 logs
|
|
327
|
+
|
|
328
|
+
# View logs for specific job
|
|
329
|
+
jm2 logs nightly-backup
|
|
330
|
+
|
|
331
|
+
# Follow logs in real-time
|
|
332
|
+
jm2 logs --follow
|
|
333
|
+
|
|
334
|
+
# Show last N lines
|
|
335
|
+
jm2 logs --lines 100
|
|
336
|
+
|
|
337
|
+
# Filter by date
|
|
338
|
+
jm2 logs --since "2024-12-01"
|
|
339
|
+
jm2 logs --until "2024-12-15"
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Options:
|
|
343
|
+
- `--follow, -f` - Follow log output in real-time
|
|
344
|
+
- `--lines, -n <count>` - Number of lines to show (default: 50)
|
|
345
|
+
- `--since <datetime>` - Show logs since datetime
|
|
346
|
+
- `--until <datetime>` - Show logs until datetime
|
|
347
|
+
- `--errors` - Show only error logs
|
|
348
|
+
|
|
349
|
+
#### `jm2 history [id|name]`
|
|
350
|
+
View job execution history.
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
# View all execution history
|
|
354
|
+
jm2 history
|
|
355
|
+
|
|
356
|
+
# View history for specific job
|
|
357
|
+
jm2 history nightly-backup
|
|
358
|
+
|
|
359
|
+
# Show last N executions
|
|
360
|
+
jm2 history --count 20
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Options:
|
|
364
|
+
- `--count, -c <number>` - Number of executions to show (default: 10)
|
|
365
|
+
- `--failed` - Show only failed executions
|
|
366
|
+
- `--success` - Show only successful executions
|
|
367
|
+
|
|
368
|
+
### Utility Commands
|
|
369
|
+
|
|
370
|
+
#### `jm2 flush`
|
|
371
|
+
Clear completed one-time jobs and old logs.
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
# Clear completed one-time jobs
|
|
375
|
+
jm2 flush
|
|
376
|
+
|
|
377
|
+
# Clear logs older than 30 days
|
|
378
|
+
jm2 flush --logs --days 30
|
|
379
|
+
|
|
380
|
+
# Clear all history
|
|
381
|
+
jm2 flush --history
|
|
382
|
+
|
|
383
|
+
# Force without confirmation
|
|
384
|
+
jm2 flush --force
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Options:
|
|
388
|
+
- `--logs` - Clear old log files
|
|
389
|
+
- `--history` - Clear execution history
|
|
390
|
+
- `--days <number>` - Clear items older than N days (default: 7)
|
|
391
|
+
- `--force, -f` - Skip confirmation prompt
|
|
392
|
+
|
|
393
|
+
#### `jm2 export`
|
|
394
|
+
Export jobs configuration.
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
# Export to stdout
|
|
398
|
+
jm2 export
|
|
399
|
+
|
|
400
|
+
# Export to file
|
|
401
|
+
jm2 export --output jobs.json
|
|
402
|
+
|
|
403
|
+
# Export specific jobs
|
|
404
|
+
jm2 export --tag production
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Options:
|
|
408
|
+
- `--output, -o <file>` - Output file path
|
|
409
|
+
- `--tag, -t <tag>` - Export only jobs with this tag
|
|
410
|
+
|
|
411
|
+
#### `jm2 import`
|
|
412
|
+
Import jobs from configuration file.
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
jm2 import jobs.json
|
|
416
|
+
|
|
417
|
+
# Merge with existing jobs
|
|
418
|
+
jm2 import jobs.json --merge
|
|
419
|
+
|
|
420
|
+
# Replace all existing jobs
|
|
421
|
+
jm2 import jobs.json --replace
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Options:
|
|
425
|
+
- `--merge` - Merge with existing jobs (default)
|
|
426
|
+
- `--replace` - Replace all existing jobs
|
|
427
|
+
|
|
428
|
+
## Cron Expression Reference
|
|
429
|
+
|
|
430
|
+
```
|
|
431
|
+
┌───────────── minute (0 - 59)
|
|
432
|
+
│ ┌───────────── hour (0 - 23)
|
|
433
|
+
│ │ ┌───────────── day of month (1 - 31)
|
|
434
|
+
│ │ │ ┌───────────── month (1 - 12)
|
|
435
|
+
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
|
|
436
|
+
│ │ │ │ │
|
|
437
|
+
│ │ │ │ │
|
|
438
|
+
* * * * *
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Common Examples
|
|
442
|
+
|
|
443
|
+
| Expression | Description |
|
|
444
|
+
|------------|-------------|
|
|
445
|
+
| `* * * * *` | Every minute |
|
|
446
|
+
| `*/5 * * * *` | Every 5 minutes |
|
|
447
|
+
| `0 * * * *` | Every hour |
|
|
448
|
+
| `0 0 * * *` | Every day at midnight |
|
|
449
|
+
| `0 2 * * *` | Every day at 2:00 AM |
|
|
450
|
+
| `0 0 * * 0` | Every Sunday at midnight |
|
|
451
|
+
| `0 0 1 * *` | First day of every month |
|
|
452
|
+
| `0 9-17 * * 1-5` | Every hour from 9 AM to 5 PM, Monday to Friday |
|
|
453
|
+
|
|
454
|
+
## Datetime Format for `--at`
|
|
455
|
+
|
|
456
|
+
The `--at` option accepts flexible datetime formats:
|
|
457
|
+
|
|
458
|
+
### Time Only (HH:mm or HH:mm:ss)
|
|
459
|
+
Schedules for today, or **tomorrow if the time has already passed**.
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
# Schedule for 3:30 PM today (or tomorrow if it's past 3:30 PM)
|
|
463
|
+
jm2 add "echo 'meeting'" --at "15:30" --name meeting
|
|
464
|
+
|
|
465
|
+
# With seconds
|
|
466
|
+
jm2 add "node task.js" --at "09:00:00" --name morning-task
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Date + Time (Full datetime)
|
|
470
|
+
Schedules for the exact datetime. **Shows error if the time is in the past.**
|
|
471
|
+
|
|
472
|
+
```bash
|
|
473
|
+
# ISO 8601 format
|
|
474
|
+
jm2 add "node deploy.js" --at "2024-12-25T10:00:00" --name deploy
|
|
475
|
+
|
|
476
|
+
# Simple format
|
|
477
|
+
jm2 add "npm run backup" --at "2024-12-25 10:00" --name backup
|
|
478
|
+
|
|
479
|
+
# With seconds
|
|
480
|
+
jm2 add "node task.js" --at "2024-12-25 10:00:00" --name task
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Date Only (YYYY-MM-DD)
|
|
484
|
+
Schedules for midnight (00:00:00) on that date. **Shows error if the date is in the past.**
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
jm2 add "npm run report" --at "2024-12-31" --name year-end
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Supported Formats Summary
|
|
491
|
+
|
|
492
|
+
| Format | Example | Behavior |
|
|
493
|
+
|--------|---------|----------|
|
|
494
|
+
| `HH:mm` | `15:30` | Today, or tomorrow if past |
|
|
495
|
+
| `HH:mm:ss` | `15:30:00` | Today, or tomorrow if past |
|
|
496
|
+
| `YYYY-MM-DD` | `2024-12-25` | Midnight on date (error if past) |
|
|
497
|
+
| `YYYY-MM-DD HH:mm` | `2024-12-25 10:00` | Exact datetime (error if past) |
|
|
498
|
+
| `YYYY-MM-DD HH:mm:ss` | `2024-12-25 10:00:00` | Exact datetime (error if past) |
|
|
499
|
+
| `YYYY-MM-DDTHH:mm:ss` | `2024-12-25T10:00:00` | ISO 8601 (error if past) |
|
|
500
|
+
|
|
501
|
+
## Duration Format
|
|
502
|
+
|
|
503
|
+
For `--in`, `--timeout` options:
|
|
504
|
+
|
|
505
|
+
| Format | Description |
|
|
506
|
+
|--------|-------------|
|
|
507
|
+
| `30s` | 30 seconds |
|
|
508
|
+
| `5m` | 5 minutes |
|
|
509
|
+
| `2h` | 2 hours |
|
|
510
|
+
| `1d` | 1 day |
|
|
511
|
+
| `1w` | 1 week |
|
|
512
|
+
| `1h30m` | 1 hour and 30 minutes |
|
|
513
|
+
|
|
514
|
+
## Configuration
|
|
515
|
+
|
|
516
|
+
JM2 stores its data in `~/.jm2/`:
|
|
517
|
+
|
|
518
|
+
```
|
|
519
|
+
~/.jm2/
|
|
520
|
+
├── config.json # Daemon configuration
|
|
521
|
+
├── jobs.json # Job definitions
|
|
522
|
+
├── daemon.pid # Daemon process ID
|
|
523
|
+
├── daemon.log # Daemon logs
|
|
524
|
+
└── logs/ # Job execution logs (named by task)
|
|
525
|
+
├── nightly-backup.log
|
|
526
|
+
├── hourly-test.log
|
|
527
|
+
├── job-1.log # Auto-generated name
|
|
528
|
+
└── job-2.log
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### Configuration Options
|
|
532
|
+
|
|
533
|
+
Edit `~/.jm2/config.json`:
|
|
534
|
+
|
|
535
|
+
```json
|
|
536
|
+
{
|
|
537
|
+
"logRetentionDays": 30,
|
|
538
|
+
"historyRetentionDays": 90,
|
|
539
|
+
"maxConcurrentJobs": 10,
|
|
540
|
+
"defaultShell": "/bin/bash",
|
|
541
|
+
"timezone": "UTC"
|
|
542
|
+
}
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
## Exit Codes
|
|
546
|
+
|
|
547
|
+
| Code | Description |
|
|
548
|
+
|------|-------------|
|
|
549
|
+
| 0 | Success |
|
|
550
|
+
| 1 | General error |
|
|
551
|
+
| 2 | Invalid arguments |
|
|
552
|
+
| 3 | Daemon not running |
|
|
553
|
+
| 4 | Job not found |
|
|
554
|
+
| 5 | Permission denied |
|
|
555
|
+
| 6 | Job name already exists |
|
|
556
|
+
| 7 | Scheduled time is in the past |
|
|
557
|
+
|
|
558
|
+
## Examples
|
|
559
|
+
|
|
560
|
+
### Backup Database Every Night
|
|
561
|
+
|
|
562
|
+
```bash
|
|
563
|
+
jm2 add "pg_dump mydb > /backups/db-$(date +%Y%m%d).sql" \
|
|
564
|
+
--cron "0 2 * * *" \
|
|
565
|
+
--name db-backup \
|
|
566
|
+
--tag backup \
|
|
567
|
+
--tag database \
|
|
568
|
+
--cwd /home/user
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### Run Tests Every Hour During Work Hours
|
|
572
|
+
|
|
573
|
+
```bash
|
|
574
|
+
jm2 add "npm test" \
|
|
575
|
+
--cron "0 9-17 * * 1-5" \
|
|
576
|
+
--name work-tests \
|
|
577
|
+
--tag testing \
|
|
578
|
+
--cwd /home/user/project \
|
|
579
|
+
--timeout 10m
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### Schedule a One-time Deployment
|
|
583
|
+
|
|
584
|
+
```bash
|
|
585
|
+
jm2 add "npm run deploy:production" \
|
|
586
|
+
--at "2024-12-25 03:00" \
|
|
587
|
+
--name christmas-deploy \
|
|
588
|
+
--tag deployment \
|
|
589
|
+
--cwd /home/user/app \
|
|
590
|
+
--env NODE_ENV=production
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Set a Reminder in 30 Minutes
|
|
594
|
+
|
|
595
|
+
```bash
|
|
596
|
+
jm2 add "notify-send 'Meeting in 5 minutes!'" \
|
|
597
|
+
--in 30m \
|
|
598
|
+
--name meeting-reminder
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
## License
|
|
602
|
+
|
|
603
|
+
JM2 is made available under the terms of the GNU Affero General Public License 3.0 (AGPL 3.0). For other licenses contact [me](mailto:landicefu@gmail.com).
|
package/bin/jm2.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* jm2 CLI Entry Point
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* jm2 start Start the daemon
|
|
8
|
+
* jm2 stop Stop the daemon
|
|
9
|
+
* jm2 restart Restart the daemon
|
|
10
|
+
* jm2 status Show daemon status
|
|
11
|
+
* jm2 add <command> Add a new job
|
|
12
|
+
* jm2 list List all jobs
|
|
13
|
+
* jm2 show <id|name> Show job details
|
|
14
|
+
* jm2 remove <id|name> Remove a job
|
|
15
|
+
* jm2 pause <id|name> Pause a job
|
|
16
|
+
* jm2 resume <id|name> Resume a job
|
|
17
|
+
* jm2 run <id|name> Run a job manually
|
|
18
|
+
* jm2 logs <id|name> Show job logs
|
|
19
|
+
* jm2 history <id|name> Show job history
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { runCli } from '../src/cli/index.js';
|
|
23
|
+
|
|
24
|
+
runCli();
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jm2",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Job Manager 2 - A simple yet powerful job scheduler combining cron and at functionality",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/cli/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/cli/index.js",
|
|
9
|
+
"./package.json": "./package.json"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"jm2": "bin/jm2.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin/",
|
|
16
|
+
"src/",
|
|
17
|
+
"README.md",
|
|
18
|
+
"GNU-AGPL-3.0"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"start": "node src/daemon/index.js",
|
|
22
|
+
"test": "vitest",
|
|
23
|
+
"test:run": "vitest run",
|
|
24
|
+
"test:coverage": "vitest run --coverage",
|
|
25
|
+
"lint": "eslint src/ bin/ tests/",
|
|
26
|
+
"lint:fix": "eslint src/ bin/ tests/ --fix",
|
|
27
|
+
"reset": "node bin/jm2.js stop 2>/dev/null || true; rm -rf ~/.jm2; echo 'jm2 data reset complete'"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"cron",
|
|
31
|
+
"scheduler",
|
|
32
|
+
"job",
|
|
33
|
+
"task",
|
|
34
|
+
"daemon",
|
|
35
|
+
"cli",
|
|
36
|
+
"at",
|
|
37
|
+
"periodic",
|
|
38
|
+
"timer"
|
|
39
|
+
],
|
|
40
|
+
"author": "Landice Fu <landice.fu@gmail.com>",
|
|
41
|
+
"license": "AGPL-3.0",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=20.0.0"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"sideEffects": false,
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"better-sqlite3": "^11.0.0",
|
|
51
|
+
"chalk": "^5.4.1",
|
|
52
|
+
"cli-table3": "^0.6.5",
|
|
53
|
+
"commander": "^14.0.2",
|
|
54
|
+
"cron-parser": "^5.4.0",
|
|
55
|
+
"dayjs": "^1.11.19",
|
|
56
|
+
"ora": "^9.0.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"eslint": "^9.20.0",
|
|
60
|
+
"vitest": "^4.0.18"
|
|
61
|
+
},
|
|
62
|
+
"repository": {
|
|
63
|
+
"type": "git",
|
|
64
|
+
"url": "git+https://github.com/landicefu/jm2"
|
|
65
|
+
},
|
|
66
|
+
"bugs": {
|
|
67
|
+
"url": "https://github.com/landicefu/jm2/issues"
|
|
68
|
+
},
|
|
69
|
+
"homepage": "https://github.com/landicefu/jm2#readme"
|
|
70
|
+
}
|