agenda 5.0.0 → 6.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.
Files changed (358) hide show
  1. package/LICENSE.md +4 -0
  2. package/README.md +222 -1063
  3. package/dist/Job.d.ts +190 -0
  4. package/dist/Job.js +568 -0
  5. package/dist/Job.js.map +1 -0
  6. package/dist/JobProcessingQueue.d.ts +47 -0
  7. package/dist/JobProcessingQueue.js +101 -0
  8. package/dist/JobProcessingQueue.js.map +1 -0
  9. package/dist/JobProcessor.d.ts +70 -0
  10. package/dist/JobProcessor.js +458 -0
  11. package/dist/JobProcessor.js.map +1 -0
  12. package/dist/backends/index.d.ts +18 -0
  13. package/dist/backends/index.js +20 -0
  14. package/dist/backends/index.js.map +1 -0
  15. package/dist/decorators/Define.d.ts +33 -0
  16. package/dist/decorators/Define.js +44 -0
  17. package/dist/decorators/Define.js.map +1 -0
  18. package/dist/decorators/Every.d.ts +43 -0
  19. package/dist/decorators/Every.js +55 -0
  20. package/dist/decorators/Every.js.map +1 -0
  21. package/dist/decorators/JobsController.d.ts +43 -0
  22. package/dist/decorators/JobsController.js +37 -0
  23. package/dist/decorators/JobsController.js.map +1 -0
  24. package/dist/decorators/index.d.ts +41 -0
  25. package/dist/decorators/index.js +46 -0
  26. package/dist/decorators/index.js.map +1 -0
  27. package/dist/decorators/metadata.d.ts +50 -0
  28. package/dist/decorators/metadata.js +35 -0
  29. package/dist/decorators/metadata.js.map +1 -0
  30. package/dist/decorators/register.d.ts +52 -0
  31. package/dist/decorators/register.js +139 -0
  32. package/dist/decorators/register.js.map +1 -0
  33. package/dist/index.d.ts +359 -8
  34. package/dist/index.js +532 -20
  35. package/dist/index.js.map +1 -1
  36. package/dist/notifications/BaseNotificationChannel.d.ts +36 -0
  37. package/dist/notifications/BaseNotificationChannel.js +80 -0
  38. package/dist/notifications/BaseNotificationChannel.js.map +1 -0
  39. package/dist/notifications/InMemoryNotificationChannel.d.ts +12 -0
  40. package/dist/notifications/InMemoryNotificationChannel.js +26 -0
  41. package/dist/notifications/InMemoryNotificationChannel.js.map +1 -0
  42. package/dist/notifications/index.d.ts +2 -0
  43. package/dist/notifications/index.js +3 -0
  44. package/dist/notifications/index.js.map +1 -0
  45. package/dist/types/AgendaBackend.d.ts +53 -0
  46. package/dist/types/AgendaBackend.js +2 -0
  47. package/dist/types/AgendaBackend.js.map +1 -0
  48. package/dist/types/AgendaConfig.d.ts +9 -0
  49. package/dist/types/AgendaConfig.js +2 -0
  50. package/dist/types/AgendaConfig.js.map +1 -0
  51. package/dist/types/AgendaStatus.d.ts +32 -0
  52. package/dist/types/AgendaStatus.js +2 -0
  53. package/dist/types/AgendaStatus.js.map +1 -0
  54. package/dist/types/DbOptions.d.ts +4 -0
  55. package/dist/types/DbOptions.js +2 -0
  56. package/dist/types/DbOptions.js.map +1 -0
  57. package/dist/types/JobDefinition.d.ts +40 -0
  58. package/dist/types/JobDefinition.js +2 -0
  59. package/dist/types/JobDefinition.js.map +1 -0
  60. package/dist/types/JobParameters.d.ts +106 -0
  61. package/dist/types/JobParameters.js +17 -0
  62. package/dist/types/JobParameters.js.map +1 -0
  63. package/dist/types/JobQuery.d.ts +79 -0
  64. package/dist/types/JobQuery.js +33 -0
  65. package/dist/types/JobQuery.js.map +1 -0
  66. package/dist/types/JobRepository.d.ts +96 -0
  67. package/dist/types/JobRepository.js +2 -0
  68. package/dist/types/JobRepository.js.map +1 -0
  69. package/dist/types/NotificationChannel.d.ts +71 -0
  70. package/dist/types/NotificationChannel.js +2 -0
  71. package/dist/types/NotificationChannel.js.map +1 -0
  72. package/dist/utils/backoff.d.ts +152 -0
  73. package/dist/utils/backoff.js +167 -0
  74. package/dist/utils/backoff.js.map +1 -0
  75. package/dist/utils/dateConstraints.d.ts +48 -0
  76. package/dist/utils/dateConstraints.js +128 -0
  77. package/dist/utils/dateConstraints.js.map +1 -0
  78. package/dist/utils/isValidDate.d.ts +1 -0
  79. package/dist/utils/isValidDate.js +5 -0
  80. package/dist/utils/isValidDate.js.map +1 -0
  81. package/dist/utils/nextRunAt.d.ts +10 -0
  82. package/dist/utils/nextRunAt.js +110 -0
  83. package/dist/utils/nextRunAt.js.map +1 -0
  84. package/dist/utils/priority.d.ts +13 -0
  85. package/dist/utils/priority.js +20 -0
  86. package/dist/utils/priority.js.map +1 -0
  87. package/dist/utils/processEvery.d.ts +1 -0
  88. package/dist/utils/processEvery.js +7 -0
  89. package/dist/utils/processEvery.js.map +1 -0
  90. package/dist/utils/stack.d.ts +1 -0
  91. package/dist/utils/stack.js +18 -0
  92. package/dist/utils/stack.js.map +1 -0
  93. package/package.json +40 -76
  94. package/History.md +0 -617
  95. package/dist/agenda/cancel.d.ts +0 -11
  96. package/dist/agenda/cancel.d.ts.map +0 -1
  97. package/dist/agenda/cancel.js +0 -41
  98. package/dist/agenda/cancel.js.map +0 -1
  99. package/dist/agenda/close.d.ts +0 -17
  100. package/dist/agenda/close.d.ts.map +0 -1
  101. package/dist/agenda/close.js +0 -47
  102. package/dist/agenda/close.js.map +0 -1
  103. package/dist/agenda/create.d.ts +0 -11
  104. package/dist/agenda/create.d.ts.map +0 -1
  105. package/dist/agenda/create.js +0 -27
  106. package/dist/agenda/create.js.map +0 -1
  107. package/dist/agenda/database.d.ts +0 -20
  108. package/dist/agenda/database.d.ts.map +0 -1
  109. package/dist/agenda/database.js +0 -56
  110. package/dist/agenda/database.js.map +0 -1
  111. package/dist/agenda/db-init.d.ts +0 -11
  112. package/dist/agenda/db-init.d.ts.map +0 -1
  113. package/dist/agenda/db-init.js +0 -40
  114. package/dist/agenda/db-init.js.map +0 -1
  115. package/dist/agenda/default-concurrency.d.ts +0 -9
  116. package/dist/agenda/default-concurrency.d.ts.map +0 -1
  117. package/dist/agenda/default-concurrency.js +0 -21
  118. package/dist/agenda/default-concurrency.js.map +0 -1
  119. package/dist/agenda/default-lock-lifetime.d.ts +0 -10
  120. package/dist/agenda/default-lock-lifetime.d.ts.map +0 -1
  121. package/dist/agenda/default-lock-lifetime.js +0 -22
  122. package/dist/agenda/default-lock-lifetime.js.map +0 -1
  123. package/dist/agenda/default-lock-limit.d.ts +0 -10
  124. package/dist/agenda/default-lock-limit.d.ts.map +0 -1
  125. package/dist/agenda/default-lock-limit.js +0 -22
  126. package/dist/agenda/default-lock-limit.js.map +0 -1
  127. package/dist/agenda/define.d.ts +0 -45
  128. package/dist/agenda/define.d.ts.map +0 -1
  129. package/dist/agenda/define.js +0 -44
  130. package/dist/agenda/define.js.map +0 -1
  131. package/dist/agenda/disable.d.ts +0 -11
  132. package/dist/agenda/disable.d.ts.map +0 -1
  133. package/dist/agenda/disable.js +0 -42
  134. package/dist/agenda/disable.js.map +0 -1
  135. package/dist/agenda/drain.d.ts +0 -9
  136. package/dist/agenda/drain.d.ts.map +0 -1
  137. package/dist/agenda/drain.js +0 -46
  138. package/dist/agenda/drain.js.map +0 -1
  139. package/dist/agenda/enable.d.ts +0 -12
  140. package/dist/agenda/enable.d.ts.map +0 -1
  141. package/dist/agenda/enable.js +0 -43
  142. package/dist/agenda/enable.js.map +0 -1
  143. package/dist/agenda/every.d.ts +0 -15
  144. package/dist/agenda/every.d.ts.map +0 -1
  145. package/dist/agenda/every.js +0 -77
  146. package/dist/agenda/every.js.map +0 -1
  147. package/dist/agenda/find-and-lock-next-job.d.ts +0 -13
  148. package/dist/agenda/find-and-lock-next-job.d.ts.map +0 -1
  149. package/dist/agenda/find-and-lock-next-job.js +0 -75
  150. package/dist/agenda/find-and-lock-next-job.js.map +0 -1
  151. package/dist/agenda/has-mongo-protocol.d.ts +0 -7
  152. package/dist/agenda/has-mongo-protocol.d.ts.map +0 -1
  153. package/dist/agenda/has-mongo-protocol.js +0 -13
  154. package/dist/agenda/has-mongo-protocol.js.map +0 -1
  155. package/dist/agenda/index.d.ts +0 -130
  156. package/dist/agenda/index.d.ts.map +0 -1
  157. package/dist/agenda/index.js +0 -128
  158. package/dist/agenda/index.js.map +0 -1
  159. package/dist/agenda/job-processing-queue.d.ts +0 -18
  160. package/dist/agenda/job-processing-queue.d.ts.map +0 -1
  161. package/dist/agenda/job-processing-queue.js +0 -76
  162. package/dist/agenda/job-processing-queue.js.map +0 -1
  163. package/dist/agenda/jobs.d.ts +0 -15
  164. package/dist/agenda/jobs.d.ts.map +0 -1
  165. package/dist/agenda/jobs.js +0 -36
  166. package/dist/agenda/jobs.js.map +0 -1
  167. package/dist/agenda/lock-limit.d.ts +0 -9
  168. package/dist/agenda/lock-limit.d.ts.map +0 -1
  169. package/dist/agenda/lock-limit.js +0 -22
  170. package/dist/agenda/lock-limit.js.map +0 -1
  171. package/dist/agenda/max-concurrency.d.ts +0 -10
  172. package/dist/agenda/max-concurrency.d.ts.map +0 -1
  173. package/dist/agenda/max-concurrency.js +0 -22
  174. package/dist/agenda/max-concurrency.js.map +0 -1
  175. package/dist/agenda/mongo.d.ts +0 -12
  176. package/dist/agenda/mongo.d.ts.map +0 -1
  177. package/dist/agenda/mongo.js +0 -18
  178. package/dist/agenda/mongo.js.map +0 -1
  179. package/dist/agenda/name.d.ts +0 -9
  180. package/dist/agenda/name.d.ts.map +0 -1
  181. package/dist/agenda/name.js +0 -21
  182. package/dist/agenda/name.js.map +0 -1
  183. package/dist/agenda/now.d.ts +0 -11
  184. package/dist/agenda/now.d.ts.map +0 -1
  185. package/dist/agenda/now.js +0 -41
  186. package/dist/agenda/now.js.map +0 -1
  187. package/dist/agenda/process-every.d.ts +0 -9
  188. package/dist/agenda/process-every.d.ts.map +0 -1
  189. package/dist/agenda/process-every.js +0 -23
  190. package/dist/agenda/process-every.js.map +0 -1
  191. package/dist/agenda/purge.d.ts +0 -9
  192. package/dist/agenda/purge.d.ts.map +0 -1
  193. package/dist/agenda/purge.js +0 -33
  194. package/dist/agenda/purge.js.map +0 -1
  195. package/dist/agenda/save-job.d.ts +0 -11
  196. package/dist/agenda/save-job.d.ts.map +0 -1
  197. package/dist/agenda/save-job.js +0 -156
  198. package/dist/agenda/save-job.js.map +0 -1
  199. package/dist/agenda/schedule.d.ts +0 -14
  200. package/dist/agenda/schedule.d.ts.map +0 -1
  201. package/dist/agenda/schedule.js +0 -62
  202. package/dist/agenda/schedule.js.map +0 -1
  203. package/dist/agenda/sort.d.ts +0 -10
  204. package/dist/agenda/sort.d.ts.map +0 -1
  205. package/dist/agenda/sort.js +0 -22
  206. package/dist/agenda/sort.js.map +0 -1
  207. package/dist/agenda/start.d.ts +0 -10
  208. package/dist/agenda/start.d.ts.map +0 -1
  209. package/dist/agenda/start.js +0 -39
  210. package/dist/agenda/start.js.map +0 -1
  211. package/dist/agenda/stop.d.ts +0 -9
  212. package/dist/agenda/stop.d.ts.map +0 -1
  213. package/dist/agenda/stop.js +0 -57
  214. package/dist/agenda/stop.js.map +0 -1
  215. package/dist/cjs.d.ts +0 -2
  216. package/dist/cjs.d.ts.map +0 -1
  217. package/dist/cjs.js +0 -7
  218. package/dist/cjs.js.map +0 -1
  219. package/dist/index.d.ts.map +0 -1
  220. package/dist/job/compute-next-run-at.d.ts +0 -8
  221. package/dist/job/compute-next-run-at.d.ts.map +0 -1
  222. package/dist/job/compute-next-run-at.js +0 -162
  223. package/dist/job/compute-next-run-at.js.map +0 -1
  224. package/dist/job/disable.d.ts +0 -8
  225. package/dist/job/disable.d.ts.map +0 -1
  226. package/dist/job/disable.js +0 -14
  227. package/dist/job/disable.js.map +0 -1
  228. package/dist/job/enable.d.ts +0 -8
  229. package/dist/job/enable.d.ts.map +0 -1
  230. package/dist/job/enable.js +0 -14
  231. package/dist/job/enable.js.map +0 -1
  232. package/dist/job/fail.d.ts +0 -9
  233. package/dist/job/fail.d.ts.map +0 -1
  234. package/dist/job/fail.js +0 -28
  235. package/dist/job/fail.js.map +0 -1
  236. package/dist/job/index.d.ts +0 -142
  237. package/dist/job/index.d.ts.map +0 -1
  238. package/dist/job/index.js +0 -82
  239. package/dist/job/index.js.map +0 -1
  240. package/dist/job/is-running.d.ts +0 -12
  241. package/dist/job/is-running.d.ts.map +0 -1
  242. package/dist/job/is-running.js +0 -27
  243. package/dist/job/is-running.js.map +0 -1
  244. package/dist/job/priority.d.ts +0 -7
  245. package/dist/job/priority.d.ts.map +0 -1
  246. package/dist/job/priority.js +0 -14
  247. package/dist/job/priority.js.map +0 -1
  248. package/dist/job/remove.d.ts +0 -8
  249. package/dist/job/remove.d.ts.map +0 -1
  250. package/dist/job/remove.js +0 -24
  251. package/dist/job/remove.js.map +0 -1
  252. package/dist/job/repeat-at.d.ts +0 -9
  253. package/dist/job/repeat-at.d.ts.map +0 -1
  254. package/dist/job/repeat-at.js +0 -15
  255. package/dist/job/repeat-at.js.map +0 -1
  256. package/dist/job/repeat-every.d.ts +0 -17
  257. package/dist/job/repeat-every.d.ts.map +0 -1
  258. package/dist/job/repeat-every.js +0 -32
  259. package/dist/job/repeat-every.js.map +0 -1
  260. package/dist/job/run.d.ts +0 -8
  261. package/dist/job/run.d.ts.map +0 -1
  262. package/dist/job/run.js +0 -99
  263. package/dist/job/run.js.map +0 -1
  264. package/dist/job/save.d.ts +0 -9
  265. package/dist/job/save.d.ts.map +0 -1
  266. package/dist/job/save.js +0 -25
  267. package/dist/job/save.js.map +0 -1
  268. package/dist/job/schedule.d.ts +0 -9
  269. package/dist/job/schedule.d.ts.map +0 -1
  270. package/dist/job/schedule.js +0 -21
  271. package/dist/job/schedule.js.map +0 -1
  272. package/dist/job/set-shouldsaveresult.d.ts +0 -7
  273. package/dist/job/set-shouldsaveresult.d.ts.map +0 -1
  274. package/dist/job/set-shouldsaveresult.js +0 -13
  275. package/dist/job/set-shouldsaveresult.js.map +0 -1
  276. package/dist/job/to-json.d.ts +0 -9
  277. package/dist/job/to-json.d.ts.map +0 -1
  278. package/dist/job/to-json.js +0 -36
  279. package/dist/job/to-json.js.map +0 -1
  280. package/dist/job/touch.d.ts +0 -8
  281. package/dist/job/touch.d.ts.map +0 -1
  282. package/dist/job/touch.js +0 -25
  283. package/dist/job/touch.js.map +0 -1
  284. package/dist/job/unique.d.ts +0 -12
  285. package/dist/job/unique.d.ts.map +0 -1
  286. package/dist/job/unique.js +0 -17
  287. package/dist/job/unique.js.map +0 -1
  288. package/dist/utils/create-job.d.ts +0 -10
  289. package/dist/utils/create-job.d.ts.map +0 -1
  290. package/dist/utils/create-job.js +0 -16
  291. package/dist/utils/create-job.js.map +0 -1
  292. package/dist/utils/index.d.ts +0 -4
  293. package/dist/utils/index.d.ts.map +0 -1
  294. package/dist/utils/index.js +0 -16
  295. package/dist/utils/index.js.map +0 -1
  296. package/dist/utils/parse-priority.d.ts +0 -6
  297. package/dist/utils/parse-priority.d.ts.map +0 -1
  298. package/dist/utils/parse-priority.js +0 -35
  299. package/dist/utils/parse-priority.js.map +0 -1
  300. package/dist/utils/process-jobs.d.ts +0 -8
  301. package/dist/utils/process-jobs.d.ts.map +0 -1
  302. package/dist/utils/process-jobs.js +0 -308
  303. package/dist/utils/process-jobs.js.map +0 -1
  304. package/es.js +0 -1
  305. package/lib/agenda/cancel.ts +0 -28
  306. package/lib/agenda/close.ts +0 -37
  307. package/lib/agenda/create.ts +0 -22
  308. package/lib/agenda/database.ts +0 -63
  309. package/lib/agenda/db-init.ts +0 -45
  310. package/lib/agenda/default-concurrency.ts +0 -19
  311. package/lib/agenda/default-lock-lifetime.ts +0 -17
  312. package/lib/agenda/default-lock-limit.ts +0 -17
  313. package/lib/agenda/define.ts +0 -85
  314. package/lib/agenda/disable.ts +0 -28
  315. package/lib/agenda/drain.ts +0 -30
  316. package/lib/agenda/enable.ts +0 -29
  317. package/lib/agenda/every.ts +0 -86
  318. package/lib/agenda/find-and-lock-next-job.ts +0 -78
  319. package/lib/agenda/has-mongo-protocol.ts +0 -8
  320. package/lib/agenda/index.ts +0 -227
  321. package/lib/agenda/job-processing-queue.ts +0 -99
  322. package/lib/agenda/jobs.ts +0 -31
  323. package/lib/agenda/lock-limit.ts +0 -17
  324. package/lib/agenda/max-concurrency.ts +0 -20
  325. package/lib/agenda/mongo.ts +0 -21
  326. package/lib/agenda/name.ts +0 -16
  327. package/lib/agenda/now.ts +0 -31
  328. package/lib/agenda/process-every.ts +0 -18
  329. package/lib/agenda/purge.ts +0 -19
  330. package/lib/agenda/save-job.ts +0 -185
  331. package/lib/agenda/schedule.ts +0 -79
  332. package/lib/agenda/sort.ts +0 -17
  333. package/lib/agenda/start.ts +0 -30
  334. package/lib/agenda/stop.ts +0 -49
  335. package/lib/cjs.ts +0 -5
  336. package/lib/index.ts +0 -11
  337. package/lib/job/compute-next-run-at.ts +0 -191
  338. package/lib/job/disable.ts +0 -11
  339. package/lib/job/enable.ts +0 -11
  340. package/lib/job/fail.ts +0 -29
  341. package/lib/job/index.ts +0 -221
  342. package/lib/job/is-running.ts +0 -29
  343. package/lib/job/priority.ts +0 -11
  344. package/lib/job/remove.ts +0 -10
  345. package/lib/job/repeat-at.ts +0 -12
  346. package/lib/job/repeat-every.ts +0 -40
  347. package/lib/job/run.ts +0 -125
  348. package/lib/job/save.ts +0 -11
  349. package/lib/job/schedule.ts +0 -15
  350. package/lib/job/set-shouldsaveresult.ts +0 -10
  351. package/lib/job/to-json.ts +0 -36
  352. package/lib/job/touch.ts +0 -11
  353. package/lib/job/unique.ts +0 -18
  354. package/lib/utils/create-job.ts +0 -13
  355. package/lib/utils/index.ts +0 -3
  356. package/lib/utils/parse-priority.ts +0 -37
  357. package/lib/utils/process-jobs.ts +0 -379
  358. package/tsconfig.json +0 -72
package/README.md CHANGED
@@ -1,1185 +1,344 @@
1
+ # Agenda
2
+
1
3
  <p align="center">
2
- <img src="https://cdn.jsdelivr.net/gh/agenda/agenda@master/agenda.svg" alt="Agenda" width="100" height="100">
4
+ <img src="https://cdn.jsdelivr.net/gh/agenda/agenda@main/agenda.svg" alt="Agenda" width="100" height="100">
3
5
  </p>
6
+
4
7
  <p align="center">
5
8
  A light-weight job scheduling library for Node.js
6
9
  </p>
7
10
 
8
- # Agenda offers
9
-
10
- - Minimal overhead. Agenda aims to keep its code base small.
11
- - Mongo backed persistence layer.
12
- - Promises based API.
13
- - Scheduling with configurable priority, concurrency, repeating and persistence of job results.
14
- - Scheduling via cron or human readable syntax.
15
- - Event backed job queue that you can hook into.
16
- - [Agenda-rest](https://github.com/agenda/agenda-rest): optional standalone REST API.
17
- - [Inversify-agenda](https://github.com/lautarobock/inversify-agenda) - Some utilities for the development of agenda workers with Inversify.
18
- - [Agendash](https://github.com/agenda/agendash): optional standalone web-interface.
19
-
20
- ### Feature Comparison
21
-
22
- Since there are a few job queue solutions, here a table comparing them to help you use the one that
23
- better suits your needs.
24
-
25
- Agenda is great if you need a MongoDB job scheduler, but try **[Bree](https://jobscheduler.net)** if you need something simpler (built by a previous maintainer).
11
+ [![NPM Version](https://img.shields.io/npm/v/agenda.svg)](https://www.npmjs.com/package/agenda)
12
+ [![NPM Downloads](https://img.shields.io/npm/dm/agenda.svg)](https://www.npmjs.com/package/agenda)
26
13
 
27
- | Feature | Bull | Bee | Agenda |
28
- | :--------------- | :-------------: | :------: | :----: |
29
- | Backend | redis | redis | mongo |
30
- | Priorities | ✓ | | ✓ |
31
- | Concurrency | ✓ | ✓ | ✓ |
32
- | Delayed jobs | ✓ | | ✓ |
33
- | Global events | ✓ | | |
34
- | Rate Limiter | ✓ | | |
35
- | Pause/Resume | ✓ | | |
36
- | Sandboxed worker | ✓ | | |
37
- | Repeatable jobs | ✓ | | ✓ |
38
- | Atomic ops | ✓ | ✓ | |
39
- | Persistence | ✓ | ✓ | ✓ |
40
- | UI | ✓ | | ✓ |
41
- | REST API | | | ✓ |
42
- | Optimized for | Jobs / Messages | Messages | Jobs |
14
+ > **Migrating from v5?** See the [Migration Guide](https://github.com/agenda/agenda/blob/main/docs/migration-guide-v6.md) for all breaking changes.
43
15
 
44
- _Kudos for making the comparison chart goes to [Bull](https://www.npmjs.com/package/bull#feature-comparison) maintainers._
16
+ ## Agenda 6.x
45
17
 
46
- # Installation
18
+ Agenda 6.x is a complete TypeScript rewrite with a focus on **modularity** and **flexibility**:
47
19
 
48
- Install via NPM
20
+ - **Pluggable storage backends** - Choose from MongoDB, PostgreSQL, Redis, or implement your own. Each backend is a separate package - install only what you need.
49
21
 
50
- npm install agenda
22
+ - **Pluggable notification channels** - Move beyond polling with real-time job notifications via Redis, PostgreSQL LISTEN/NOTIFY, or other pub/sub systems. Jobs get processed immediately when saved, not on the next poll cycle.
51
23
 
52
- You will also need a working [Mongo](https://www.mongodb.com/) database (v3) to point it to.
24
+ - **Modern stack** - ESM-only, Node.js 18+, full TypeScript with strict typing.
53
25
 
54
- # CJS / Module Imports
26
+ See the [6.x Roadmap](https://github.com/agenda/agenda/issues/1610) for details and progress.
55
27
 
56
- for regular javascript code, just use the default entrypoint
28
+ ## Features
57
29
 
58
- ```js
59
- const Agenda = require("agenda");
60
- ```
61
-
62
- For Typescript, Webpack or other module imports, use `agenda/es` entrypoint:
63
- e.g.
64
-
65
- ```ts
66
- import Agenda, { Job, JobAttributesData } from 'agenda'
67
-
68
- const mongoConnectionString = "mongodb://127.0.0.1/agenda";
69
- const agenda = new Agenda({ db: { address: mongoConnectionString } });
70
-
71
- interface CreateContact extends JobAttributesData {
72
- contactDetails: Contact // app-specific type
73
- }
30
+ - Minimal overhead job scheduling
31
+ - Pluggable storage backends (MongoDB, PostgreSQL, Redis)
32
+ - TypeScript support with full typing
33
+ - Scheduling via cron or human-readable syntax
34
+ - Configurable concurrency and locking
35
+ - Real-time job notifications (optional)
36
+ - Sandboxed worker execution via fork mode
37
+ - TypeScript decorators for class-based job definitions
74
38
 
75
- agenda.define<CreateContact>('CREATE CONTACT', async (job: Job<CreateContact>) => {
76
- const contactDetails = job.attrs.data.contactDetails; // type Contact
77
- })
78
-
79
- agenda.now<CreateContact>('CREATE CONTACT', {
80
- contactDetails: {...} // required attr
81
- })
82
-
83
- agenda.schedule<CreateContact>('in 5 minutes', 'CREATE CONTACT', {
84
- contactDetails: {...} // required attr
85
- })
86
- ```
87
-
88
- # Example Usage
89
-
90
- ```js
91
- const mongoConnectionString = "mongodb://127.0.0.1/agenda";
92
-
93
- const agenda = new Agenda({ db: { address: mongoConnectionString } });
94
-
95
- // Or override the default collection name:
96
- // const agenda = new Agenda({db: {address: mongoConnectionString, collection: 'jobCollectionName'}});
97
-
98
- // or pass additional connection options:
99
- // const agenda = new Agenda({db: {address: mongoConnectionString, collection: 'jobCollectionName', options: {ssl: true}}});
100
-
101
- // or pass in an existing mongodb-native MongoClient instance
102
- // const agenda = new Agenda({mongo: myMongoClient});
103
-
104
- agenda.define("delete old users", async (job) => {
105
- await User.remove({ lastLogIn: { $lt: twoDaysAgo } });
106
- });
39
+ ## Installation
107
40
 
108
- (async function () {
109
- // IIFE to give access to async/await
110
- await agenda.start();
41
+ Install the core package and your preferred backend:
111
42
 
112
- await agenda.every("3 minutes", "delete old users");
113
-
114
- // Alternatively, you could also do:
115
- await agenda.every("*/3 * * * *", "delete old users");
116
- })();
117
- ```
118
-
119
- ```js
120
- agenda.define(
121
- "send email report",
122
- { priority: "high", concurrency: 10 },
123
- async (job) => {
124
- const { to } = job.attrs.data;
125
- await emailClient.send({
126
- to,
127
- from: "example@example.com",
128
- subject: "Email Report",
129
- body: "...",
130
- });
131
- }
132
- );
133
-
134
- (async function () {
135
- await agenda.start();
136
- await agenda.schedule("in 20 minutes", "send email report", {
137
- to: "admin@example.com",
138
- });
139
- })();
140
- ```
141
-
142
- ```js
143
- (async function () {
144
- const weeklyReport = agenda.create("send email report", {
145
- to: "example@example.com",
146
- });
147
- await agenda.start();
148
- await weeklyReport.repeatEvery("1 week").save();
149
- })();
150
- ```
151
-
152
- # Full documentation
153
-
154
- Agenda's basic control structure is an instance of an agenda. Agenda's are
155
- mapped to a database collection and load the jobs from within.
156
-
157
- ## Table of Contents
158
-
159
- - [Configuring an agenda](#configuring-an-agenda)
160
- - [Agenda Events](#agenda-events)
161
- - [Defining job processors](#defining-job-processors)
162
- - [Creating jobs](#creating-jobs)
163
- - [Managing jobs](#managing-jobs)
164
- - [Starting the job processor](#starting-the-job-processor)
165
- - [Multiple job processors](#multiple-job-processors)
166
- - [Manually working with jobs](#manually-working-with-a-job)
167
- - [Job Queue Events](#job-queue-events)
168
- - [Frequently asked questions](#frequently-asked-questions)
169
- - [Example Project structure](#example-project-structure)
170
- - [Known Issues](#known-issues)
171
- - [Debugging Issues](#debugging-issues)
172
- - [Acknowledgements](#acknowledgements)
173
-
174
- ## Configuring an agenda
175
-
176
- All configuration methods are chainable, meaning you can do something like:
177
-
178
- ```js
179
- const agenda = new Agenda();
180
- agenda
181
- .database(...)
182
- .processEvery('3 minutes')
183
- ...;
184
- ```
185
-
186
- Agenda uses [Human Interval](http://github.com/rschmukler/human-interval) for specifying the intervals. It supports the following units:
187
-
188
- `seconds`, `minutes`, `hours`, `days`,`weeks`, `months` -- assumes 30 days, `years` -- assumes 365 days
43
+ ```bash
44
+ # For MongoDB
45
+ npm install agenda @agendajs/mongo-backend
189
46
 
190
- More sophisticated examples
47
+ # For PostgreSQL
48
+ npm install agenda @agendajs/postgres-backend
191
49
 
192
- ```js
193
- agenda.processEvery("one minute");
194
- agenda.processEvery("1.5 minutes");
195
- agenda.processEvery("3 days and 4 hours");
196
- agenda.processEvery("3 days, 4 hours and 36 seconds");
50
+ # For Redis
51
+ npm install agenda @agendajs/redis-backend
197
52
  ```
198
53
 
199
- ### database(url, [collectionName])
200
-
201
- Specifies the database at the `url` specified. If no collection name is given,
202
- `agendaJobs` is used.
54
+ **Requirements:**
55
+ - Node.js 18+
56
+ - Database of your choice (MongoDB 4+, PostgreSQL, or Redis)
203
57
 
204
- ```js
205
- agenda.database("localhost:27017/agenda-test", "agendaJobs");
206
- ```
58
+ ## Quick Start
207
59
 
208
- You can also specify it during instantiation.
60
+ ```javascript
61
+ import { Agenda } from 'agenda';
62
+ import { MongoBackend } from '@agendajs/mongo-backend';
209
63
 
210
- ```js
211
64
  const agenda = new Agenda({
212
- db: { address: "localhost:27017/agenda-test", collection: "agendaJobs" },
65
+ backend: new MongoBackend({ address: 'mongodb://localhost/agenda' })
213
66
  });
214
- ```
215
-
216
- Agenda will emit a `ready` event (see [Agenda Events](#agenda-events)) when properly connected to the database.
217
- It is safe to call `agenda.start()` without waiting for this event, as this is handled internally.
218
- If you're using the `db` options, or call `database`, then you may still need to listen for `ready` before saving jobs.
219
-
220
- ### mongo(dbInstance)
221
-
222
- Use an existing mongodb-native MongoClient/Db instance. This can help consolidate connections to a
223
- database. You can instead use `.database` to have agenda handle connecting for you.
224
-
225
- You can also specify it during instantiation:
226
-
227
- ```js
228
- const agenda = new Agenda({ mongo: mongoClientInstance.db("agenda-test") });
229
- ```
230
-
231
- Note that MongoClient.connect() returns a mongoClientInstance since [node-mongodb-native 3.0.0](https://github.com/mongodb/node-mongodb-native/blob/master/CHANGES_3.0.0.md), while it used to return a dbInstance that could then be directly passed to agenda.
232
67
 
233
- ### name(name)
234
-
235
- Sets the `lastModifiedBy` field to `name` in the jobs collection.
236
- Useful if you have multiple job processors (agendas) and want to see which
237
- job queue last ran the job.
238
-
239
- ```js
240
- agenda.name(os.hostname + "-" + process.pid);
241
- ```
242
-
243
- You can also specify it during instantiation
244
-
245
- ```js
246
- const agenda = new Agenda({ name: "test queue" });
247
- ```
248
-
249
- ### processEvery(interval)
250
-
251
- Takes a string `interval` which can be either a traditional javascript number,
252
- or a string such as `3 minutes`
253
-
254
- Specifies the frequency at which agenda will query the database looking for jobs
255
- that need to be processed. Agenda internally uses `setTimeout` to guarantee that
256
- jobs run at (close to ~3ms) the right time.
257
-
258
- Decreasing the frequency will result in fewer database queries, but more jobs
259
- being stored in memory.
260
-
261
- Also worth noting is that if the job queue is shutdown, any jobs stored in memory
262
- that haven't run will still be locked, meaning that you may have to wait for the
263
- lock to expire. By default it is `'5 seconds'`.
264
-
265
- ```js
266
- agenda.processEvery("1 minute");
267
- ```
268
-
269
- You can also specify it during instantiation
270
-
271
- ```js
272
- const agenda = new Agenda({ processEvery: "30 seconds" });
273
- ```
274
-
275
- ### maxConcurrency(number)
276
-
277
- Takes a `number` which specifies the max number of jobs that can be running at
278
- any given moment. By default it is `20`.
279
-
280
- ```js
281
- agenda.maxConcurrency(20);
282
- ```
283
-
284
- You can also specify it during instantiation
285
-
286
- ```js
287
- const agenda = new Agenda({ maxConcurrency: 20 });
288
- ```
289
-
290
- ### defaultConcurrency(number)
291
-
292
- Takes a `number` which specifies the default number of a specific job that can be running at
293
- any given moment. By default it is `5`.
294
-
295
- ```js
296
- agenda.defaultConcurrency(5);
297
- ```
298
-
299
- You can also specify it during instantiation
300
-
301
- ```js
302
- const agenda = new Agenda({ defaultConcurrency: 5 });
303
- ```
304
-
305
- ### lockLimit(number)
306
-
307
- Takes a `number` which specifies the max number jobs that can be locked at any given moment. By default it is `0` for no max.
308
-
309
- ```js
310
- agenda.lockLimit(0);
311
- ```
312
-
313
- You can also specify it during instantiation
314
-
315
- ```js
316
- const agenda = new Agenda({ lockLimit: 0 });
317
- ```
318
-
319
- ### defaultLockLimit(number)
320
-
321
- Takes a `number` which specifies the default number of a specific job that can be locked at any given moment. By default it is `0` for no max.
322
-
323
- ```js
324
- agenda.defaultLockLimit(0);
325
- ```
326
-
327
- You can also specify it during instantiation
328
-
329
- ```js
330
- const agenda = new Agenda({ defaultLockLimit: 0 });
331
- ```
332
-
333
- ### defaultLockLifetime(number)
334
-
335
- Takes a `number` which specifies the default lock lifetime in milliseconds. By
336
- default it is 10 minutes. This can be overridden by specifying the
337
- `lockLifetime` option to a defined job.
338
-
339
- A job will unlock if it is finished (ie. the returned Promise resolves/rejects
340
- or `done` is specified in the params and `done()` is called) before the
341
- `lockLifetime`. The lock is useful if the job crashes or times out.
342
-
343
- ```js
344
- agenda.defaultLockLifetime(10000);
345
- ```
346
-
347
- You can also specify it during instantiation
348
-
349
- ```js
350
- const agenda = new Agenda({ defaultLockLifetime: 10000 });
351
- ```
352
-
353
- ### sort(query)
354
-
355
- Takes a `query` which specifies the sort query to be used for finding and locking the next job.
356
-
357
- By default it is `{ nextRunAt: 1, priority: -1 }`, which obeys a first in first out approach, with respect to priority.
358
-
359
- ### disableAutoIndex(boolean)
360
-
361
- Optional. Disables the automatic creation of the default index on the jobs table.
362
- By default, Agenda creates an index to optimize its queries against Mongo while processing jobs.
363
-
364
- This is useful if you want to use your own index in specific use-cases.
365
-
366
- ## Agenda Events
367
-
368
- An instance of an agenda will emit the following events:
369
-
370
- - `ready` - called when Agenda mongo connection is successfully opened and indices created.
371
- If you're passing agenda an existing connection, you shouldn't need to listen for this, as `agenda.start()` will not resolve until indices have been created.
372
- If you're using the `db` options, or call `database`, then you may still need to listen for the `ready` event before saving jobs. `agenda.start()` will still wait for the connection to be opened.
373
- - `error` - called when Agenda mongo connection process has thrown an error
374
-
375
- ```js
376
- await agenda.start();
377
- ```
378
-
379
- ## Defining Job Processors
380
-
381
- Before you can use a job, you must define its processing behavior.
382
-
383
- ### define(jobName, [options], handler)
384
-
385
- Defines a job with the name of `jobName`. When a job of `jobName` gets run, it
386
- will be passed to `handler(job, done)`. To maintain asynchronous behavior, you may
387
- either provide a Promise-returning function in `handler` _or_ provide `done` as a
388
- second parameter to `handler`. If `done` is specified in the function signature, you
389
- must call `done()` when you are processing the job. If your function is
390
- synchronous or returns a Promise, you may omit `done` from the signature.
391
-
392
- `options` is an optional argument which can overwrite the defaults. It can take
393
- the following:
394
-
395
- - `concurrency`: `number` maximum number of that job that can be running at once (per instance of agenda)
396
- - `lockLimit`: `number` maximum number of that job that can be locked at once (per instance of agenda)
397
- - `lockLifetime`: `number` interval in ms of how long the job stays locked for (see [multiple job processors](#multiple-job-processors) for more info).
398
- A job will automatically unlock once a returned promise resolves/rejects (or if `done` is specified in the signature and `done()` is called).
399
- - `priority`: `(lowest|low|normal|high|highest|number)` specifies the priority
400
- of the job. Higher priority jobs will run first. See the priority mapping
401
- below
402
- - `shouldSaveResult`: `boolean` flag that specifies whether the result of the job should also be stored in the database. Defaults to false
403
-
404
- Priority mapping:
405
-
406
- ```
407
- {
408
- highest: 20,
409
- high: 10,
410
- normal: 0,
411
- low: -10,
412
- lowest: -20
413
- }
414
- ```
415
-
416
- Async Job:
417
-
418
- ```js
419
- agenda.define("some long running job", async (job) => {
420
- const data = await doSomelengthyTask();
421
- await formatThatData(data);
422
- await sendThatData(data);
423
- });
424
- ```
425
-
426
- Async Job (using `done`):
427
-
428
- ```js
429
- agenda.define("some long running job", (job, done) => {
430
- doSomelengthyTask((data) => {
431
- formatThatData(data);
432
- sendThatData(data);
433
- done();
434
- });
435
- });
436
- ```
437
-
438
- Sync Job:
439
-
440
- ```js
441
- agenda.define("say hello", (job) => {
442
- console.log("Hello!");
443
- });
444
- ```
445
-
446
- `define()` acts like an assignment: if `define(jobName, ...)` is called multiple times (e.g. every time your script starts), the definition in the last call will overwrite the previous one. Thus, if you `define` the `jobName` only once in your code, it's safe for that call to execute multiple times.
447
-
448
- ## Creating Jobs
449
-
450
- ### every(interval, name, [data], [options])
451
-
452
- Runs job `name` at the given `interval`. Optionally, data and options can be passed in.
453
- Every creates a job of type `single`, which means that it will only create one
454
- job in the database, even if that line is run multiple times. This lets you put
455
- it in a file that may get run multiple times, such as `webserver.js` which may
456
- reboot from time to time.
457
-
458
- `interval` can be a human-readable format `String`, a cron format `String`, or a `Number`.
459
-
460
- `data` is an optional argument that will be passed to the processing function
461
- under `job.attrs.data`.
462
-
463
- `options` is an optional argument that will be passed to [`job.repeatEvery`](#repeateveryinterval-options).
464
- In order to use this argument, `data` must also be specified.
465
-
466
- Returns the `job`.
467
-
468
- ```js
469
- agenda.define("printAnalyticsReport", async (job) => {
470
- const users = await User.doSomethingReallyIntensive();
471
- processUserData(users);
472
- console.log("I print a report!");
68
+ // Define a job
69
+ agenda.define('send email', async (job) => {
70
+ const { to, subject } = job.attrs.data;
71
+ await sendEmail(to, subject);
473
72
  });
474
73
 
475
- agenda.every("15 minutes", "printAnalyticsReport");
476
- ```
477
-
478
- Optionally, `name` could be array of job names, which is convenient for scheduling
479
- different jobs for same `interval`.
480
-
481
- ```js
482
- agenda.every("15 minutes", [
483
- "printAnalyticsReport",
484
- "sendNotifications",
485
- "updateUserRecords",
486
- ]);
487
- ```
488
-
489
- In this case, `every` returns array of `jobs`.
490
-
491
- ### schedule(when, name, [data])
492
-
493
- Schedules a job to run `name` once at a given time. `when` can be a `Date` or a
494
- `String` such as `tomorrow at 5pm`.
495
-
496
- `data` is an optional argument that will be passed to the processing function
497
- under `job.attrs.data`.
498
-
499
- Returns the `job`.
500
-
501
- ```js
502
- agenda.schedule("tomorrow at noon", "printAnalyticsReport", { userCount: 100 });
503
- ```
504
-
505
- Optionally, `name` could be array of job names, similar to the `every` method.
506
-
507
- ```js
508
- agenda.schedule("tomorrow at noon", [
509
- "printAnalyticsReport",
510
- "sendNotifications",
511
- "updateUserRecords",
512
- ]);
513
- ```
514
-
515
- In this case, `schedule` returns array of `jobs`.
516
-
517
- ### now(name, [data])
518
-
519
- Schedules a job to run `name` once immediately.
520
-
521
- `data` is an optional argument that will be passed to the processing function
522
- under `job.attrs.data`.
523
-
524
- Returns the `job`.
525
-
526
- ```js
527
- agenda.now("do the hokey pokey");
528
- ```
529
-
530
- ### create(jobName, data)
531
-
532
- Returns an instance of a `jobName` with `data`. This does _NOT_ save the job in
533
- the database. See below to learn how to manually work with jobs.
534
-
535
- ```js
536
- const job = agenda.create("printAnalyticsReport", { userCount: 100 });
537
- await job.save();
538
- console.log("Job successfully saved");
539
- ```
540
-
541
- ## Managing Jobs
542
-
543
- ### jobs(mongodb-native query, mongodb-native sort, mongodb-native limit, mongodb-native skip)
544
-
545
- Lets you query (then sort, limit and skip the result) all of the jobs in the agenda job's database. These are full [mongodb-native](https://github.com/mongodb/node-mongodb-native) `find`, `sort`, `limit` and `skip` commands. See mongodb-native's documentation for details.
546
-
547
- ```js
548
- const jobs = await agenda.jobs(
549
- { name: "printAnalyticsReport" },
550
- { data: -1 },
551
- 3,
552
- 1
553
- );
554
- // Work with jobs (see below)
555
- ```
556
-
557
- ### cancel(mongodb-native query)
558
-
559
- Cancels any jobs matching the passed mongodb-native query, and removes them from the database. Returns a Promise resolving to the number of cancelled jobs, or rejecting on error.
560
-
561
- ```js
562
- const numRemoved = await agenda.cancel({ name: "printAnalyticsReport" });
563
- ```
564
-
565
- This functionality can also be achieved by first retrieving all the jobs from the database using `agenda.jobs()`, looping through the resulting array and calling `job.remove()` on each. It is however preferable to use `agenda.cancel()` for this use case, as this ensures the operation is atomic.
566
-
567
- ### disable(mongodb-native query)
568
-
569
- Disables any jobs matching the passed mongodb-native query, preventing any matching jobs from being run by the Job Processor.
570
-
571
- ```js
572
- const numDisabled = await agenda.disable({ name: "pollExternalService" });
573
- ```
574
-
575
- Similar to `agenda.cancel()`, this functionality can be acheived with a combination of `agenda.jobs()` and `job.disable()`
576
-
577
- ### enable(mongodb-native query)
578
-
579
- Enables any jobs matching the passed mongodb-native query, allowing any matching jobs to be run by the Job Processor.
580
-
581
- ```js
582
- const numEnabled = await agenda.enable({ name: "pollExternalService" });
583
- ```
584
-
585
- Similar to `agenda.cancel()`, this functionality can be acheived with a combination of `agenda.jobs()` and `job.enable()`
586
-
587
- ### purge()
588
-
589
- Removes all jobs in the database without defined behaviors. Useful if you change a definition name and want to remove old jobs. Returns a Promise resolving to the number of removed jobs, or rejecting on error.
590
-
591
- _IMPORTANT:_ Do not run this before you finish defining all of your jobs. If you do, you will nuke your database of jobs.
592
-
593
- ```js
594
- const numRemoved = await agenda.purge();
595
- ```
596
-
597
- ## Starting the job processor
598
-
599
- To get agenda to start processing jobs from the database you must start it. This
600
- will schedule an interval (based on `processEvery`) to check for new jobs and
601
- run them. You can also stop the queue.
602
-
603
- ### start
604
-
605
- Starts the job queue processing, checking [`processEvery`](#processeveryinterval) time to see if there
606
- are new jobs. Must be called _after_ `processEvery`, and _before_ any job scheduling (e.g. `every`).
607
-
608
- ### stop
609
-
610
- Stops the job queue processing. Unlocks currently running jobs.
611
-
612
- This can be very useful for graceful shutdowns so that currently running/grabbed jobs are abandoned so that other
613
- job queues can grab them / they are unlocked should the job queue start again. Here is an example of how to do a graceful
614
- shutdown.
615
-
616
- ```js
617
- async function graceful() {
618
- await agenda.stop();
619
- process.exit(0);
620
- }
621
-
622
- process.on("SIGTERM", graceful);
623
- process.on("SIGINT", graceful);
624
- ```
625
-
626
- ### drain
627
-
628
- Stops the job queue processing and waits till all current jobs finishes.
629
-
630
- This can be very useful for graceful shutdowns so that currently running/grabbed jobs are finished before shutting down. Here is an example of how to do a graceful
631
- shutdown.
632
-
633
- ```js
634
- async function graceful() {
635
- await agenda.drain();
636
- process.exit(0);
637
- }
74
+ // Start processing
75
+ await agenda.start();
638
76
 
639
- process.on("SIGTERM", graceful);
640
- process.on("SIGINT", graceful);
77
+ // Schedule jobs
78
+ await agenda.every('1 hour', 'send email', { to: 'user@example.com', subject: 'Hello' });
79
+ await agenda.schedule('in 5 minutes', 'send email', { to: 'admin@example.com', subject: 'Report' });
80
+ await agenda.now('send email', { to: 'support@example.com', subject: 'Urgent' });
641
81
  ```
642
82
 
643
- ### close(force)
644
-
645
- Closes database connection. You don't normally have to do this, but it might be useful for testing purposes.
83
+ ## Official Backend Packages
646
84
 
647
- Using `force` boolean you can force close connection.
85
+ | Package | Backend | Notifications | Install |
86
+ |---------|---------|---------------|---------|
87
+ | [`@agendajs/mongo-backend`](https://www.npmjs.com/package/@agendajs/mongo-backend) | MongoDB | Polling only | `npm install @agendajs/mongo-backend` |
88
+ | [`@agendajs/postgres-backend`](https://www.npmjs.com/package/@agendajs/postgres-backend) | PostgreSQL | LISTEN/NOTIFY | `npm install @agendajs/postgres-backend` |
89
+ | [`@agendajs/redis-backend`](https://www.npmjs.com/package/@agendajs/redis-backend) | Redis | Pub/Sub | `npm install @agendajs/redis-backend` |
648
90
 
649
- Read more from [Node.js MongoDB Driver API](https://mongodb.github.io/node-mongodb-native/2.0/api/Db.html#close)
91
+ ### Backend Capabilities
650
92
 
651
- ```js
652
- await agenda.close({ force: true });
653
- ```
93
+ | Backend | Storage | Notifications | Notes |
94
+ |---------|:-------:|:-------------:|-------|
95
+ | **MongoDB** (`MongoBackend`) | ✅ | ❌ | Storage only. Combine with external notification channel for real-time. |
96
+ | **PostgreSQL** (`PostgresBackend`) | ✅ | ✅ | Full backend. Uses LISTEN/NOTIFY for notifications. |
97
+ | **Redis** (`RedisBackend`) | ✅ | ✅ | Full backend. Uses Pub/Sub for notifications. |
98
+ | **InMemoryNotificationChannel** | ❌ | ✅ | Notifications only. For single-process/testing. |
654
99
 
655
- ## Multiple job processors
100
+ ## Backend Configuration
656
101
 
657
- Sometimes you may want to have multiple node instances / machines process from
658
- the same queue. Agenda supports a locking mechanism to ensure that multiple
659
- queues don't process the same job.
102
+ ### MongoDB
660
103
 
661
- You can configure the locking mechanism by specifying `lockLifetime` as an
662
- interval when defining the job.
104
+ ```javascript
105
+ import { Agenda } from 'agenda';
106
+ import { MongoBackend } from '@agendajs/mongo-backend';
663
107
 
664
- ```js
665
- agenda.define("someJob", { lockLifetime: 10000 }, (job, cb) => {
666
- // Do something in 10 seconds or less...
108
+ // Via connection string
109
+ const agenda = new Agenda({
110
+ backend: new MongoBackend({ address: 'mongodb://localhost/agenda' })
667
111
  });
668
- ```
669
-
670
- This will ensure that no other job processor (this one included) attempts to run the job again
671
- for the next 10 seconds. If you have a particularly long running job, you will want to
672
- specify a longer lockLifetime.
673
-
674
- By default it is 10 minutes. Typically you shouldn't have a job that runs for 10 minutes,
675
- so this is really insurance should the job queue crash before the job is unlocked.
676
-
677
- When a job is finished (i.e. the returned promise resolves/rejects or `done` is
678
- specified in the signature and `done()` is called), it will automatically unlock.
679
-
680
- ## Manually working with a job
681
-
682
- A job instance has many instance methods. All mutating methods must be followed
683
- with a call to `await job.save()` in order to persist the changes to the database.
684
-
685
- ### repeatEvery(interval, [options])
686
-
687
- Specifies an `interval` on which the job should repeat. The job runs at the time of defining as well in configured intervals, that is "run _now_ and in intervals".
688
-
689
- `interval` can be a human-readable format `String`, a cron format `String`, or a `Number`.
690
112
 
691
- `options` is an optional argument containing:
692
-
693
- `options.timezone`: should be a string as accepted by [moment-timezone](https://momentjs.com/timezone/) and is considered when using an interval in the cron string format.
694
-
695
- `options.skipImmediate`: `true` | `false` (default) Setting this `true` will skip the immediate run. The first run will occur only in configured interval.
696
-
697
- `options.startDate`: `Date` the first time the job runs, should be equal or after the start date.
698
-
699
- `options.endDate`: `Date` the job should not repeat after the endDate. The job can run on the end-date itself, but not after that.
700
-
701
- `options.skipDays`: `human readable string` ('2 days'). After each run, it will skip the duration of 'skipDays'
702
-
703
- ```js
704
- job.repeatEvery("10 minutes");
705
- await job.save();
706
- ```
707
-
708
- ```js
709
- job.repeatEvery("3 minutes", {
710
- skipImmediate: true,
113
+ // Via existing MongoDB connection
114
+ const agenda = new Agenda({
115
+ backend: new MongoBackend({ mongo: existingDb })
711
116
  });
712
- await job.save();
713
- ```
714
117
 
715
- ```js
716
- job.repeatEvery("0 6 * * *", {
717
- timezone: "America/New_York",
118
+ // With options
119
+ const agenda = new Agenda({
120
+ backend: new MongoBackend({
121
+ mongo: db,
122
+ collection: 'jobs' // Collection name (default: 'agendaJobs')
123
+ }),
124
+ processEvery: '30 seconds', // Job polling interval
125
+ maxConcurrency: 20, // Max concurrent jobs
126
+ defaultConcurrency: 5 // Default per job type
718
127
  });
719
- await job.save();
720
- ```
721
-
722
- ### repeatAt(time)
723
-
724
- Specifies a `time` when the job should repeat. [Possible values](https://github.com/matthewmueller/date#examples)
725
-
726
- ```js
727
- job.repeatAt("3:30pm");
728
- await job.save();
729
- ```
730
-
731
- ### schedule(time)
732
-
733
- Specifies the next `time` at which the job should run.
734
-
735
- ```js
736
- job.schedule("tomorrow at 6pm");
737
- await job.save();
738
- ```
739
-
740
- ### priority(priority)
741
-
742
- Specifies the `priority` weighting of the job. Can be a number or a string from
743
- the above priority table.
744
-
745
- ```js
746
- job.priority("low");
747
- await job.save();
748
- ```
749
-
750
- ### setShouldSaveResult(setShouldSaveResult)
751
-
752
- Specifies whether the result of the job should also be stored in the database. Defaults to false.
753
-
754
- ```js
755
- job.setShouldSaveResult(true);
756
- await job.save();
757
- ```
758
-
759
- The data returned by the job will be available on the `result` attribute after it succeeded and got retrieved again from the database, e.g. via `agenda.jobs(...)` or through the [success job event](#agenda-events)).
760
-
761
- ### unique(properties, [options])
762
-
763
- Ensure that only one instance of this job exists with the specified properties
764
-
765
- `options` is an optional argument which can overwrite the defaults. It can take
766
- the following:
767
-
768
- - `insertOnly`: `boolean` will prevent any properties from persisting if the job already exists. Defaults to false.
769
-
770
- ```js
771
- job.unique({ "data.type": "active", "data.userId": "123", nextRunAt: date });
772
- await job.save();
773
- ```
774
-
775
- _IMPORTANT:_ To [guarantee uniqueness](https://docs.mongodb.com/manual/reference/method/db.collection.update/#use-unique-indexes) as well as avoid high CPU usage by MongoDB make sure to create a unique index on the used fields, like `name`, `data.type` and `data.userId` for the example above.
776
-
777
- ### fail(reason)
778
-
779
- Sets `job.attrs.failedAt` to `now`, and sets `job.attrs.failReason` to `reason`.
780
-
781
- Optionally, `reason` can be an error, in which case `job.attrs.failReason` will
782
- be set to `error.message`
783
-
784
- ```js
785
- job.fail("insufficient disk space");
786
- // or
787
- job.fail(new Error("insufficient disk space"));
788
- await job.save();
789
128
  ```
790
129
 
791
- ### run(callback)
130
+ ### PostgreSQL
792
131
 
793
- Runs the given `job` and calls `callback(err, job)` upon completion. Normally
794
- you never need to call this manually.
132
+ ```javascript
133
+ import { Agenda } from 'agenda';
134
+ import { PostgresBackend } from '@agendajs/postgres-backend';
795
135
 
796
- ```js
797
- job.run((err, job) => {
798
- console.log("I don't know why you would need to do this...");
136
+ const agenda = new Agenda({
137
+ backend: new PostgresBackend({
138
+ connectionString: 'postgresql://user:pass@localhost:5432/mydb'
139
+ })
799
140
  });
800
141
  ```
801
142
 
802
- ### save()
803
-
804
- Saves the `job.attrs` into the database. Returns a Promise resolving to a Job instance, or rejecting on error.
805
-
806
- ```js
807
- try {
808
- await job.save();
809
- console.log("Successfully saved job to collection");
810
- } catch (e) {
811
- console.error("Error saving job to collection");
812
- }
813
- ```
814
-
815
- ### remove()
143
+ ### Redis
816
144
 
817
- Removes the `job` from the database. Returns a Promise resolving to the number of jobs removed, or rejecting on error.
145
+ ```javascript
146
+ import { Agenda } from 'agenda';
147
+ import { RedisBackend } from '@agendajs/redis-backend';
818
148
 
819
- ```js
820
- try {
821
- await job.remove();
822
- console.log("Successfully removed job from collection");
823
- } catch (e) {
824
- console.error("Error removing job from collection");
825
- }
149
+ const agenda = new Agenda({
150
+ backend: new RedisBackend({
151
+ connectionString: 'redis://localhost:6379'
152
+ })
153
+ });
826
154
  ```
827
155
 
828
- ### disable()
829
-
830
- Disables the `job`. Upcoming runs won't execute.
831
-
832
- ### enable()
833
-
834
- Enables the `job` if it got disabled before. Upcoming runs will execute.
156
+ ## Real-Time Notifications
835
157
 
836
- ### touch()
158
+ For faster job processing across distributed systems:
837
159
 
838
- Resets the lock on the job. Useful to indicate that the job hasn't timed out
839
- when you have very long running jobs. The call returns a promise that resolves
840
- when the job's lock has been renewed.
160
+ ```javascript
161
+ import { Agenda, InMemoryNotificationChannel } from 'agenda';
162
+ import { MongoBackend } from '@agendajs/mongo-backend';
841
163
 
842
- ```js
843
- agenda.define("super long job", async (job) => {
844
- await doSomeLongTask();
845
- await job.touch();
846
- await doAnotherLongTask();
847
- await job.touch();
848
- await finishOurLongTasks();
164
+ const agenda = new Agenda({
165
+ backend: new MongoBackend({ mongo: db }),
166
+ notificationChannel: new InMemoryNotificationChannel()
849
167
  });
850
168
  ```
851
169
 
852
- ## Job Queue Events
170
+ ### Mixing Storage and Notification Backends
853
171
 
854
- An instance of an agenda will emit the following events:
172
+ You can use MongoDB for storage while using a different system for real-time notifications:
855
173
 
856
- - `start` - called just before a job starts
857
- - `start:job name` - called just before the specified job starts
174
+ ```javascript
175
+ import { Agenda } from 'agenda';
176
+ import { MongoBackend } from '@agendajs/mongo-backend';
177
+ import { RedisBackend } from '@agendajs/redis-backend';
858
178
 
859
- ```js
860
- agenda.on("start", (job) => {
861
- console.log("Job %s starting", job.attrs.name);
179
+ // MongoDB for storage + Redis for real-time notifications
180
+ const redisBackend = new RedisBackend({ connectionString: 'redis://localhost:6379' });
181
+ const agenda = new Agenda({
182
+ backend: new MongoBackend({ mongo: db }),
183
+ notificationChannel: redisBackend.notificationChannel
862
184
  });
863
185
  ```
864
186
 
865
- - `complete` - called when a job finishes, regardless of if it succeeds or fails
866
- - `complete:job name` - called when a job finishes, regardless of if it succeeds or fails
187
+ This is useful when you want MongoDB's proven durability and flexible queries for job storage, but need faster real-time notifications across multiple processes.
867
188
 
868
- ```js
869
- agenda.on("complete", (job) => {
870
- console.log(`Job ${job.attrs.name} finished`);
871
- });
872
- ```
189
+ ## API Overview
873
190
 
874
- - `success` - called when a job finishes successfully
875
- - `success:job name` - called when a job finishes successfully
191
+ ### Defining Jobs
876
192
 
877
- ```js
878
- agenda.on("success:send email", (job) => {
879
- console.log(`Sent Email Successfully to ${job.attrs.data.to}`);
193
+ ```javascript
194
+ // Simple async handler
195
+ agenda.define('my-job', async (job) => {
196
+ console.log('Processing:', job.attrs.data);
880
197
  });
881
- ```
882
198
 
883
- - `fail` - called when a job throws an error
884
- - `fail:job name` - called when a job throws an error
885
-
886
- ```js
887
- agenda.on("fail:send email", (err, job) => {
888
- console.log(`Job failed with error: ${err.message}`);
199
+ // With options
200
+ agenda.define('my-job', async (job) => { /* ... */ }, {
201
+ concurrency: 10,
202
+ lockLimit: 5,
203
+ lockLifetime: 10 * 60 * 1000, // 10 minutes
204
+ priority: 'high'
889
205
  });
890
206
  ```
891
207
 
892
- ## Frequently Asked Questions
893
-
894
- ### What is the order in which jobs run?
895
-
896
- Jobs are run with priority in a first in first out order (so they will be run in the order they were scheduled AND with respect to highest priority).
897
-
898
- For example, if we have two jobs named "send-email" queued (both with the same priority), and the first job is queued at 3:00 PM and second job is queued at 3:05 PM with the same `priority` value, then the first job will run first if we start to send "send-email" jobs at 3:10 PM. However if the first job has a priority of `5` and the second job has a priority of `10`, then the second will run first (priority takes precedence) at 3:10 PM.
899
-
900
- The default [MongoDB sort object](https://docs.mongodb.com/manual/reference/method/cursor.sort/) is `{ nextRunAt: 1, priority: -1 }` and can be changed through the option `sort` when configuring Agenda.
901
-
902
- ### What is the difference between `lockLimit` and `maxConcurrency`?
903
-
904
- Agenda will lock jobs 1 by one, setting the `lockedAt` property in mongoDB, and creating an instance of the `Job` class which it caches into the `_lockedJobs` array. This defaults to having no limit, but can be managed using lockLimit. If all jobs will need to be run before agenda's next interval (set via `agenda.processEvery`), then agenda will attempt to lock all jobs.
905
-
906
- Agenda will also pull jobs from `_lockedJobs` and into `_runningJobs`. These jobs are actively being worked on by user code, and this is limited by `maxConcurrency` (defaults to 20).
907
-
908
- If you have multiple instances of agenda processing the same job definition with a fast repeat time you may find they get unevenly loaded. This is because they will compete to lock as many jobs as possible, even if they don't have enough concurrency to process them. This can be resolved by tweaking the `maxConcurrency` and `lockLimit` properties.
909
-
910
- ### Sample Project Structure?
911
-
912
- Agenda doesn't have a preferred project structure and leaves it to the user to
913
- choose how they would like to use it. That being said, you can check out the
914
- [example project structure](#example-project-structure) below.
915
-
916
- ### Can I Donate?
917
-
918
- Thanks! I'm flattered, but it's really not necessary. If you really want to, you can find my [gittip here](https://www.gittip.com/rschmukler/).
919
-
920
- ### Web Interface?
921
-
922
- Agenda itself does not have a web interface built in but we do offer stand-alone web interface [Agendash](https://github.com/agenda/agendash):
923
-
924
- <a href="https://raw.githubusercontent.com/agenda/agendash/master/job-details.png"><img src="https://raw.githubusercontent.com/agenda/agendash/master/job-details.png" style="max-width:100%" alt="Agendash interface"></a>
925
-
926
- ### Mongo vs Redis
927
-
928
- The decision to use Mongo instead of Redis is intentional. Redis is often used for
929
- non-essential data (such as sessions) and without configuration doesn't
930
- guarantee the same level of persistence as Mongo (should the server need to be
931
- restarted/crash).
932
-
933
- Agenda decides to focus on persistence without requiring special configuration
934
- of Redis (thereby degrading the performance of the Redis server on non-critical
935
- data, such as sessions).
936
-
937
- Ultimately if enough people want a Redis driver instead of Mongo, I will write
938
- one. (Please open an issue requesting it). For now, Agenda decided to focus on
939
- guaranteed persistence.
940
-
941
- ### Spawning / forking processes
942
-
943
- Ultimately Agenda can work from a single job queue across multiple machines, node processes, or forks. If you are interested in having more than one worker, [Bars3s](http://github.com/bars3s) has written up a fantastic example of how one might do it:
208
+ ### Defining Jobs with Decorators
944
209
 
945
- ```js
946
- const cluster = require("cluster");
947
- const os = require("os");
210
+ For a class-based approach, use TypeScript decorators:
948
211
 
949
- const httpServer = require("./app/http-server");
950
- const jobWorker = require("./app/job-worker");
212
+ ```typescript
213
+ import { JobsController, Define, Every, registerJobs, Job } from 'agenda';
951
214
 
952
- const jobWorkers = [];
953
- const webWorkers = [];
954
-
955
- if (cluster.isMaster) {
956
- const cpuCount = os.cpus().length;
957
- // Create a worker for each CPU
958
- for (let i = 0; i < cpuCount; i += 1) {
959
- addJobWorker();
960
- addWebWorker();
961
- }
962
-
963
- cluster.on("exit", (worker, code, signal) => {
964
- if (jobWorkers.indexOf(worker.id) !== -1) {
965
- console.log(
966
- `job worker ${worker.process.pid} exited (signal: ${signal}). Trying to respawn...`
967
- );
968
- removeJobWorker(worker.id);
969
- addJobWorker();
970
- }
971
-
972
- if (webWorkers.indexOf(worker.id) !== -1) {
973
- console.log(
974
- `http worker ${worker.process.pid} exited (signal: ${signal}). Trying to respawn...`
975
- );
976
- removeWebWorker(worker.id);
977
- addWebWorker();
978
- }
979
- });
980
- } else {
981
- if (process.env.web) {
982
- console.log(`start http server: ${cluster.worker.id}`);
983
- // Initialize the http server here
984
- httpServer.start();
215
+ @JobsController({ namespace: 'email' })
216
+ class EmailJobs {
217
+ @Define({ concurrency: 5 })
218
+ async sendWelcome(job: Job<{ userId: string }>) {
219
+ console.log('Sending welcome to:', job.attrs.data.userId);
985
220
  }
986
221
 
987
- if (process.env.job) {
988
- console.log(`start job server: ${cluster.worker.id}`);
989
- // Initialize the Agenda here
990
- jobWorker.start();
222
+ @Every('1 hour')
223
+ async cleanupBounced(job: Job) {
224
+ console.log('Cleaning up bounced emails');
991
225
  }
992
226
  }
993
227
 
994
- function addWebWorker() {
995
- webWorkers.push(cluster.fork({ web: 1 }).id);
996
- }
997
-
998
- function addJobWorker() {
999
- jobWorkers.push(cluster.fork({ job: 1 }).id);
1000
- }
1001
-
1002
- function removeWebWorker(id) {
1003
- webWorkers.splice(webWorkers.indexOf(id), 1);
1004
- }
1005
-
1006
- function removeJobWorker(id) {
1007
- jobWorkers.splice(jobWorkers.indexOf(id), 1);
1008
- }
1009
- ```
1010
-
1011
- ### Recovering lost Mongo connections ("auto_reconnect")
1012
-
1013
- Agenda is configured by default to automatically reconnect indefinitely, emitting an [error event](#agenda-events)
1014
- when no connection is available on each [process tick](#processeveryinterval), allowing you to restore the Mongo
1015
- instance without having to restart the application.
1016
-
1017
- However, if you are using an [existing Mongo client](#mongomongoclientinstance)
1018
- you'll need to configure the `reconnectTries` and `reconnectInterval` [connection settings](http://mongodb.github.io/node-mongodb-native/3.0/reference/connecting/connection-settings/)
1019
- manually, otherwise you'll find that Agenda will throw an error with the message "MongoDB connection is not recoverable,
1020
- application restart required" if the connection cannot be recovered within 30 seconds.
1021
-
1022
- # Example Project Structure
1023
-
1024
- Agenda will only process jobs that it has definitions for. This allows you to
1025
- selectively choose which jobs a given agenda will process.
1026
-
1027
- Consider the following project structure, which allows us to share models with
1028
- the rest of our code base, and specify which jobs a worker processes, if any at
1029
- all.
228
+ registerJobs(agenda, [new EmailJobs()]);
229
+ await agenda.start();
1030
230
 
1031
- ```
1032
- - server.js
1033
- - worker.js
1034
- lib/
1035
- - agenda.js
1036
- controllers/
1037
- - user-controller.js
1038
- jobs/
1039
- - email.js
1040
- - video-processing.js
1041
- - image-processing.js
1042
- models/
1043
- - user-model.js
1044
- - blog-post.model.js
231
+ // Schedule using namespaced name
232
+ await agenda.now('email.sendWelcome', { userId: '123' });
1045
233
  ```
1046
234
 
1047
- Sample job processor (eg. `jobs/email.js`)
235
+ See [Decorators Documentation](./docs/decorators.md) for full details.
1048
236
 
1049
- ```js
1050
- let email = require("some-email-lib"),
1051
- User = require("../models/user-model.js");
237
+ ### Scheduling Jobs
1052
238
 
1053
- module.exports = function (agenda) {
1054
- agenda.define("registration email", async (job) => {
1055
- const user = await User.get(job.attrs.data.userId);
1056
- await email(
1057
- user.email(),
1058
- "Thanks for registering",
1059
- "Thanks for registering " + user.name()
1060
- );
1061
- });
239
+ ```javascript
240
+ // Run immediately
241
+ await agenda.now('my-job', { userId: '123' });
1062
242
 
1063
- agenda.define("reset password", async (job) => {
1064
- // Etc
1065
- });
243
+ // Run at specific time
244
+ await agenda.schedule('tomorrow at noon', 'my-job', data);
245
+ await agenda.schedule(new Date('2024-12-25'), 'my-job', data);
1066
246
 
1067
- // More email related jobs
1068
- };
247
+ // Run repeatedly
248
+ await agenda.every('5 minutes', 'my-job');
249
+ await agenda.every('0 * * * *', 'my-job'); // Cron syntax
1069
250
  ```
1070
251
 
1071
- lib/agenda.js
1072
-
1073
- ```js
1074
- const Agenda = require("agenda");
1075
-
1076
- const connectionOpts = {
1077
- db: { address: "localhost:27017/agenda-test", collection: "agendaJobs" },
1078
- };
1079
-
1080
- const agenda = new Agenda(connectionOpts);
252
+ ### Job Control
1081
253
 
1082
- const jobTypes = process.env.JOB_TYPES ? process.env.JOB_TYPES.split(",") : [];
254
+ ```javascript
255
+ // Cancel jobs (removes from database)
256
+ await agenda.cancel({ name: 'my-job' });
1083
257
 
1084
- jobTypes.forEach((type) => {
1085
- require("./jobs/" + type)(agenda);
1086
- });
1087
-
1088
- if (jobTypes.length) {
1089
- agenda.start(); // Returns a promise, which should be handled appropriately
1090
- }
258
+ // Disable/enable jobs globally (by query)
259
+ await agenda.disable({ name: 'my-job' }); // Disable all jobs matching query
260
+ await agenda.enable({ name: 'my-job' }); // Enable all jobs matching query
1091
261
 
1092
- module.exports = agenda;
1093
- ```
262
+ // Disable/enable individual jobs
263
+ const job = await agenda.create('my-job', data);
264
+ job.disable();
265
+ await job.save();
1094
266
 
1095
- lib/controllers/user-controller.js
1096
-
1097
- ```js
1098
- let app = express(),
1099
- User = require("../models/user-model"),
1100
- agenda = require("../worker.js");
1101
-
1102
- app.post("/users", (req, res, next) => {
1103
- const user = new User(req.body);
1104
- user.save((err) => {
1105
- if (err) {
1106
- return next(err);
1107
- }
1108
- agenda.now("registration email", { userId: user.primary() });
1109
- res.send(201, user.toJson());
1110
- });
267
+ // Progress tracking
268
+ agenda.define('long-job', async (job) => {
269
+ for (let i = 0; i <= 100; i += 10) {
270
+ await doWork();
271
+ await job.touch(i); // Report progress 0-100
272
+ }
1111
273
  });
1112
274
  ```
1113
275
 
1114
- worker.js
1115
-
1116
- ```js
1117
- require("./lib/agenda.js");
1118
- ```
1119
-
1120
- Now you can do the following in your project:
1121
-
1122
- ```bash
1123
- node server.js
1124
- ```
276
+ ### Stopping / Draining
1125
277
 
1126
- Fire up an instance with no `JOB_TYPES`, giving you the ability to process jobs,
1127
- but not wasting resources processing jobs.
278
+ ```javascript
279
+ // Stop immediately - unlocks running jobs so other workers can pick them up
280
+ await agenda.stop();
1128
281
 
1129
- ```bash
1130
- JOB_TYPES=email node server.js
282
+ // Drain - waits for running jobs to complete before stopping
283
+ await agenda.drain();
1131
284
  ```
1132
285
 
1133
- Allow your http server to process email jobs.
286
+ Use `drain()` for graceful shutdowns where you want in-progress jobs to finish their work.
1134
287
 
1135
- ```bash
1136
- JOB_TYPES=email node worker.js
1137
- ```
288
+ ### Events
1138
289
 
1139
- Fire up an instance that processes email jobs.
290
+ ```javascript
291
+ agenda.on('start', (job) => console.log('Job started:', job.attrs.name));
292
+ agenda.on('complete', (job) => console.log('Job completed:', job.attrs.name));
293
+ agenda.on('success', (job) => console.log('Job succeeded:', job.attrs.name));
294
+ agenda.on('fail', (err, job) => console.log('Job failed:', job.attrs.name, err));
1140
295
 
1141
- ```bash
1142
- JOB_TYPES=video-processing,image-processing node worker.js
296
+ // Job-specific events
297
+ agenda.on('start:send email', (job) => { /* ... */ });
298
+ agenda.on('fail:send email', (err, job) => { /* ... */ });
1143
299
  ```
1144
300
 
1145
- Fire up an instance that processes video-processing/image-processing jobs. Good for a heavy hitting server.
1146
-
1147
- # Debugging Issues
301
+ ## Custom Backend
1148
302
 
1149
- If you think you have encountered a bug, please feel free to report it here:
303
+ For databases other than MongoDB, PostgreSQL, or Redis, implement `IAgendaBackend`:
1150
304
 
1151
- [Submit Issue](https://github.com/agenda/agenda/issues/new)
305
+ ```javascript
306
+ import { IAgendaBackend, IJobRepository } from 'agenda';
1152
307
 
1153
- Please provide us with as much details as possible such as:
308
+ class SQLiteBackend implements IAgendaBackend {
309
+ readonly repository: IJobRepository;
310
+ readonly notificationChannel = undefined; // Or implement INotificationChannel
1154
311
 
1155
- - Agenda version
1156
- - Environment (OSX, Linux, Windows, etc)
1157
- - Small description of what happened
1158
- - Any relevant stack track
1159
- - Agenda logs (see below)
1160
-
1161
- #### To turn on logging, please set your DEBUG env variable like so:
312
+ async connect() { /* ... */ }
313
+ async disconnect() { /* ... */ }
314
+ }
1162
315
 
1163
- - OSX: `DEBUG="agenda:*" ts-node src/index.js`
1164
- - Linux: `DEBUG="agenda:*" ts-node src/index.js`
1165
- - Windows CMD: `set DEBUG=agenda:*`
1166
- - Windows PowerShell: `$env:DEBUG = "agenda:*"`
316
+ const agenda = new Agenda({
317
+ backend: new SQLiteBackend({ path: './jobs.db' })
318
+ });
319
+ ```
1167
320
 
1168
- While not necessary, attaching a text file with this debug information would
1169
- be extremely useful in debugging certain issues and is encouraged.
321
+ See [Custom Backend Driver](https://github.com/agenda/agenda/blob/main/docs/custom-database-driver.md) for details.
1170
322
 
1171
- # Known Issues
323
+ ## Documentation
1172
324
 
1173
- #### "Multiple order-by items are not supported. Please specify a single order-by item."
325
+ - [Full Documentation](https://github.com/agenda/agenda#readme)
326
+ - [Migration Guide (v5 to v6)](https://github.com/agenda/agenda/blob/main/docs/migration-guide-v6.md)
327
+ - [Custom Backend Driver](https://github.com/agenda/agenda/blob/main/docs/custom-database-driver.md)
328
+ - [TypeScript Decorators](./docs/decorators.md)
329
+ - [API Reference](https://agenda.github.io/agenda/)
1174
330
 
1175
- When running Agenda on Azure cosmosDB, you might run into this issue caused by Agenda's sort query used for finding and locking the next job. To fix this, you can pass [custom sort option](https://github.com/agenda/agenda#sortquery): `sort: { nextRunAt: 1 }`
331
+ ## Related Packages
1176
332
 
1177
- # Acknowledgements
333
+ **Official Backend Packages:**
334
+ - [@agendajs/mongo-backend](https://www.npmjs.com/package/@agendajs/mongo-backend) - MongoDB backend
335
+ - [@agendajs/postgres-backend](https://www.npmjs.com/package/@agendajs/postgres-backend) - PostgreSQL backend with LISTEN/NOTIFY
336
+ - [@agendajs/redis-backend](https://www.npmjs.com/package/@agendajs/redis-backend) - Redis backend with Pub/Sub
1178
337
 
1179
- - Agenda was originally created by [@rschmukler](https://github.com/rschmukler).
1180
- - [Agendash](https://github.com/agenda/agendash) was originally created by [@joeframbach](https://github.com/joeframbach).
1181
- - These days Agenda has a great community of [contributors](https://github.com/agenda/agenda/graphs/contributors) around it. [Join us!](https://github.com/agenda/agenda/wiki)
338
+ **Tools:**
339
+ - [agendash](https://www.npmjs.com/package/agendash) - Web dashboard for Agenda
340
+ - [agenda-rest](https://www.npmjs.com/package/agenda-rest) - REST API for Agenda
1182
341
 
1183
- # License
342
+ ## License
1184
343
 
1185
- [The MIT License](LICENSE.md)
344
+ MIT