@lowerdeck/cron 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+
2
+ $ microbundle
3
+ No name was provided for external module '@lowerdeck/redis' in output.globals – guessing 'redis'
4
+ Build "@lowerdeck/cron" to dist:
5
+ 496 B: index.cjs.gz
6
+ 427 B: index.cjs.br
7
+ 441 B: index.module.js.gz
8
+ 381 B: index.module.js.br
9
+ 510 B: index.module.js.gz
10
+ 429 B: index.module.js.br
11
+ 594 B: index.umd.js.gz
12
+ 497 B: index.umd.js.br
@@ -0,0 +1,11 @@
1
+
2
+ $ vitest run --passWithNoTests
3
+ [?25l
4
+  RUN  v3.2.4 /Users/tobias/code/metorial/metorial-enterprise/oss/src/packages/backend/cron
5
+
6
+ No test files found, exiting with code 0
7
+
8
+ include: **/*.{test,spec}.?(c|m)[jt]s?(x)
9
+ exclude: **/node_modules/**, **/dist/**, **/cypress/**, **/.{idea,git,cache,output,temp}/**, **/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*
10
+
11
+ [?25h
package/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # `@lowerdeck/cron`
2
+
3
+ Distributed cron job scheduler using BullMQ and Redis. Schedule recurring tasks with cron expressions that run reliably across multiple instances.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @lowerdeck/cron
9
+ yarn add @lowerdeck/cron
10
+ bun add @lowerdeck/cron
11
+ pnpm add @lowerdeck/cron
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```typescript
17
+ import { createCron } from '@lowerdeck/cron';
18
+
19
+ // Create a cron job that runs every minute
20
+ const cronJob = createCron(
21
+ {
22
+ name: 'cleanup-task',
23
+ cron: '*/1 * * * *', // every minute
24
+ redisUrl: 'redis://localhost:6379'
25
+ },
26
+ async () => {
27
+ console.log('Running cleanup task');
28
+ // Your task logic here
29
+ }
30
+ );
31
+
32
+ // Start the cron job
33
+ const processor = await cronJob.start();
34
+
35
+ // Later, stop the cron job
36
+ await processor.close();
37
+
38
+ // Run every day at midnight
39
+ const dailyJob = createCron(
40
+ {
41
+ name: 'daily-report',
42
+ cron: '0 0 * * *',
43
+ redisUrl: process.env.REDIS_URL
44
+ },
45
+ async () => {
46
+ await generateDailyReport();
47
+ }
48
+ );
49
+
50
+ // Run every 15 minutes
51
+ const frequentJob = createCron(
52
+ {
53
+ name: 'sync-data',
54
+ cron: '*/15 * * * *',
55
+ redisUrl: process.env.REDIS_URL
56
+ },
57
+ async () => {
58
+ await syncDataFromAPI();
59
+ }
60
+ );
61
+ ```
62
+
63
+ ## License
64
+
65
+ This project is licensed under the Apache License 2.0.
66
+
67
+ <div align="center">
68
+ <sub>Built with ❤️ by <a href="https://metorial.com">Metorial</a></sub>
69
+ </div>
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ var e=require("@lowerdeck/redis"),r=require("bullmq"),n=function(){var e;return(e=console).log.apply(e,["[CRON MANAGER]:"].concat([].slice.call(arguments)))},o=new Set;exports.createCron=function(t,c){if(o.has(t.name))throw new Error("Cron with name "+t.name+" already exists");var i=e.parseRedisUrl(t.redisUrl),a=new r.Queue(t.name,{connection:i,defaultJobOptions:{removeOnComplete:!0,removeOnFail:!0}});return{start:function(){try{return n("Starting cron job "+t.name+" to run every "+t.cron+" using bullmq"),Promise.resolve(a.upsertJobScheduler("cron",{pattern:t.cron},{opts:{removeDependencyOnFailure:!0,removeOnComplete:!0,removeOnFail:!0,keepLogs:0}})).then(function(){var e=new r.Worker(t.name,function(){try{return n("Running cron job "+t.name),Promise.resolve(c()).then(function(){})}catch(e){return Promise.reject(e)}},{connection:i});return{close:e.close.bind(e)}})}catch(e){return Promise.reject(e)}}}};
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { IQueueProcessor } from '@lowerdeck/queue';\nimport { parseRedisUrl } from '@lowerdeck/redis';\nimport { Queue, Worker } from 'bullmq';\n\nlet log = (...any: any[]) => console.log('[CRON MANAGER]:', ...any);\n\nlet seenNames = new Set<string>();\n\nexport let createCron = (\n opts: {\n name: string;\n cron: string;\n redisUrl: string;\n },\n handler: () => Promise<void>\n): IQueueProcessor => {\n if (seenNames.has(opts.name)) {\n throw new Error(`Cron with name ${opts.name} already exists`);\n }\n\n let connection = parseRedisUrl(opts.redisUrl);\n let queue = new Queue(opts.name, {\n connection,\n defaultJobOptions: {\n removeOnComplete: true,\n removeOnFail: true\n }\n });\n\n return {\n start: async () => {\n log(`Starting cron job ${opts.name} to run every ${opts.cron} using bullmq`);\n\n await queue.upsertJobScheduler(\n 'cron',\n {\n pattern: opts.cron\n },\n {\n opts: {\n removeDependencyOnFailure: true,\n removeOnComplete: true,\n removeOnFail: true,\n keepLogs: 0\n }\n }\n );\n\n let worker = new Worker(\n opts.name,\n async () => {\n log(`Running cron job ${opts.name}`);\n await handler();\n },\n { connection }\n );\n\n return {\n close: worker.close.bind(worker)\n };\n }\n };\n};\n"],"names":["log","_console","console","apply","concat","slice","call","arguments","seenNames","Set","opts","handler","has","name","Error","connection","parseRedisUrl","redisUrl","queue","Queue","defaultJobOptions","removeOnComplete","removeOnFail","start","cron","Promise","resolve","upsertJobScheduler","pattern","removeDependencyOnFailure","keepLogs","then","worker","Worker","e","reject","close","bind"],"mappings":"sDAIIA,EAAM,WAAH,IAAAC,EAAA,OAAsBA,EAAAC,SAAQF,IAAGG,MAAAF,EAAA,CAAC,mBAAiBG,OAAA,GAAAC,MAAAC,KAAAC,YAAS,EAE/DC,EAAY,IAAIC,uBAEI,SACtBC,EAKAC,GAEA,GAAIH,EAAUI,IAAIF,EAAKG,MACrB,UAAUC,MAAwBJ,kBAAAA,EAAKG,KAAqB,mBAG9D,IAAIE,EAAaC,EAAaA,cAACN,EAAKO,UAChCC,EAAQ,IAAIC,EAAKA,MAACT,EAAKG,KAAM,CAC/BE,WAAAA,EACAK,kBAAmB,CACjBC,kBAAkB,EAClBC,cAAc,KAIlB,MAAO,CACLC,MAAK,WAAA,IAC0E,OAA7EvB,EAAyBU,qBAAAA,EAAKG,KAAqBH,iBAAAA,EAAKc,sBAAqBC,QAAAC,QAEvER,EAAMS,mBACV,OACA,CACEC,QAASlB,EAAKc,MAEhB,CACEd,KAAM,CACJmB,2BAA2B,EAC3BR,kBAAkB,EAClBC,cAAc,EACdQ,SAAU,MAGfC,KAAA,WAED,IAAIC,EAAS,IAAIC,EAAAA,OACfvB,EAAKG,KACM,WAAA,IAC4B,OAArCb,EAAG,oBAAqBU,EAAKG,MAAQY,QAAAC,QAC/Bf,KAASoB,KACjB,WAAA,EAAA,CAAC,MAAAG,GAAAT,OAAAA,QAAAU,OAAAD,EAAA,CAAA,EACD,CAAEnB,WAAAA,IAGJ,MAAO,CACLqB,MAAOJ,EAAOI,MAAMC,KAAKL,GACzB,EACJ,CAAC,MAAAE,GAAA,OAAAT,QAAAU,OAAAD,EAAA,CAAA,EAEL"}
@@ -0,0 +1,7 @@
1
+ import { IQueueProcessor } from '@lowerdeck/queue';
2
+ export declare let createCron: (opts: {
3
+ name: string;
4
+ cron: string;
5
+ redisUrl: string;
6
+ }, handler: () => Promise<void>) => IQueueProcessor;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAQnD,eAAO,IAAI,UAAU,GACnB,MAAM;IACJ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,EACD,SAAS,MAAM,OAAO,CAAC,IAAI,CAAC,KAC3B,eA+CF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import{parseRedisUrl as e}from"@lowerdeck/redis";import{Queue as n,Worker as r}from"bullmq";var o=function(){var e;return(e=console).log.apply(e,["[CRON MANAGER]:"].concat([].slice.call(arguments)))},t=new Set,c=function(c,i){if(t.has(c.name))throw new Error("Cron with name "+c.name+" already exists");var a=e(c.redisUrl),l=new n(c.name,{connection:a,defaultJobOptions:{removeOnComplete:!0,removeOnFail:!0}});return{start:function(){try{return o("Starting cron job "+c.name+" to run every "+c.cron+" using bullmq"),Promise.resolve(l.upsertJobScheduler("cron",{pattern:c.cron},{opts:{removeDependencyOnFailure:!0,removeOnComplete:!0,removeOnFail:!0,keepLogs:0}})).then(function(){var e=new r(c.name,function(){try{return o("Running cron job "+c.name),Promise.resolve(i()).then(function(){})}catch(e){return Promise.reject(e)}},{connection:a});return{close:e.close.bind(e)}})}catch(e){return Promise.reject(e)}}}};export{c as createCron};
2
+ //# sourceMappingURL=index.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.module.js","sources":["../src/index.ts"],"sourcesContent":["import { IQueueProcessor } from '@lowerdeck/queue';\nimport { parseRedisUrl } from '@lowerdeck/redis';\nimport { Queue, Worker } from 'bullmq';\n\nlet log = (...any: any[]) => console.log('[CRON MANAGER]:', ...any);\n\nlet seenNames = new Set<string>();\n\nexport let createCron = (\n opts: {\n name: string;\n cron: string;\n redisUrl: string;\n },\n handler: () => Promise<void>\n): IQueueProcessor => {\n if (seenNames.has(opts.name)) {\n throw new Error(`Cron with name ${opts.name} already exists`);\n }\n\n let connection = parseRedisUrl(opts.redisUrl);\n let queue = new Queue(opts.name, {\n connection,\n defaultJobOptions: {\n removeOnComplete: true,\n removeOnFail: true\n }\n });\n\n return {\n start: async () => {\n log(`Starting cron job ${opts.name} to run every ${opts.cron} using bullmq`);\n\n await queue.upsertJobScheduler(\n 'cron',\n {\n pattern: opts.cron\n },\n {\n opts: {\n removeDependencyOnFailure: true,\n removeOnComplete: true,\n removeOnFail: true,\n keepLogs: 0\n }\n }\n );\n\n let worker = new Worker(\n opts.name,\n async () => {\n log(`Running cron job ${opts.name}`);\n await handler();\n },\n { connection }\n );\n\n return {\n close: worker.close.bind(worker)\n };\n }\n };\n};\n"],"names":["log","_console","console","apply","concat","slice","call","arguments","seenNames","Set","createCron","opts","handler","has","name","Error","connection","parseRedisUrl","redisUrl","queue","Queue","defaultJobOptions","removeOnComplete","removeOnFail","start","cron","Promise","resolve","upsertJobScheduler","pattern","removeDependencyOnFailure","keepLogs","then","worker","Worker","e","reject","close","bind"],"mappings":"4FAIA,IAAIA,EAAM,WAAH,IAAAC,EAAA,OAAsBA,EAAAC,SAAQF,IAAGG,MAAAF,EAAA,CAAC,mBAAiBG,OAAA,GAAAC,MAAAC,KAAAC,YAAS,EAE/DC,EAAY,IAAIC,IAETC,EAAa,SACtBC,EAKAC,GAEA,GAAIJ,EAAUK,IAAIF,EAAKG,MACrB,UAAUC,MAAwBJ,kBAAAA,EAAKG,KAAqB,mBAG9D,IAAIE,EAAaC,EAAcN,EAAKO,UAChCC,EAAQ,IAAIC,EAAMT,EAAKG,KAAM,CAC/BE,WAAAA,EACAK,kBAAmB,CACjBC,kBAAkB,EAClBC,cAAc,KAIlB,MAAO,CACLC,MAAK,WAAA,IAC0E,OAA7ExB,EAAyBW,qBAAAA,EAAKG,KAAqBH,iBAAAA,EAAKc,sBAAqBC,QAAAC,QAEvER,EAAMS,mBACV,OACA,CACEC,QAASlB,EAAKc,MAEhB,CACEd,KAAM,CACJmB,2BAA2B,EAC3BR,kBAAkB,EAClBC,cAAc,EACdQ,SAAU,MAGfC,KAAA,WAED,IAAIC,EAAS,IAAIC,EACfvB,EAAKG,KACM,WAAA,IAC4B,OAArCd,EAAG,oBAAqBW,EAAKG,MAAQY,QAAAC,QAC/Bf,KAASoB,KACjB,WAAA,EAAA,CAAC,MAAAG,GAAAT,OAAAA,QAAAU,OAAAD,EAAA,CAAA,EACD,CAAEnB,WAAAA,IAGJ,MAAO,CACLqB,MAAOJ,EAAOI,MAAMC,KAAKL,GACzB,EACJ,CAAC,MAAAE,GAAA,OAAAT,QAAAU,OAAAD,EAAA,CAAA,EAEL"}
@@ -0,0 +1,2 @@
1
+ !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("@lowerdeck/redis"),require("bullmq")):"function"==typeof define&&define.amd?define(["exports","@lowerdeck/redis","bullmq"],n):n((e||self).cron={},e.redis,e.bullmq)}(this,function(e,n,r){var o=function(){var e;return(e=console).log.apply(e,["[CRON MANAGER]:"].concat([].slice.call(arguments)))},t=new Set;e.createCron=function(e,i){if(t.has(e.name))throw new Error("Cron with name "+e.name+" already exists");var c=n.parseRedisUrl(e.redisUrl),l=new r.Queue(e.name,{connection:c,defaultJobOptions:{removeOnComplete:!0,removeOnFail:!0}});return{start:function(){try{return o("Starting cron job "+e.name+" to run every "+e.cron+" using bullmq"),Promise.resolve(l.upsertJobScheduler("cron",{pattern:e.cron},{opts:{removeDependencyOnFailure:!0,removeOnComplete:!0,removeOnFail:!0,keepLogs:0}})).then(function(){var n=new r.Worker(e.name,function(){try{return o("Running cron job "+e.name),Promise.resolve(i()).then(function(){})}catch(e){return Promise.reject(e)}},{connection:c});return{close:n.close.bind(n)}})}catch(e){return Promise.reject(e)}}}}});
2
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.js","sources":["../src/index.ts"],"sourcesContent":["import { IQueueProcessor } from '@lowerdeck/queue';\nimport { parseRedisUrl } from '@lowerdeck/redis';\nimport { Queue, Worker } from 'bullmq';\n\nlet log = (...any: any[]) => console.log('[CRON MANAGER]:', ...any);\n\nlet seenNames = new Set<string>();\n\nexport let createCron = (\n opts: {\n name: string;\n cron: string;\n redisUrl: string;\n },\n handler: () => Promise<void>\n): IQueueProcessor => {\n if (seenNames.has(opts.name)) {\n throw new Error(`Cron with name ${opts.name} already exists`);\n }\n\n let connection = parseRedisUrl(opts.redisUrl);\n let queue = new Queue(opts.name, {\n connection,\n defaultJobOptions: {\n removeOnComplete: true,\n removeOnFail: true\n }\n });\n\n return {\n start: async () => {\n log(`Starting cron job ${opts.name} to run every ${opts.cron} using bullmq`);\n\n await queue.upsertJobScheduler(\n 'cron',\n {\n pattern: opts.cron\n },\n {\n opts: {\n removeDependencyOnFailure: true,\n removeOnComplete: true,\n removeOnFail: true,\n keepLogs: 0\n }\n }\n );\n\n let worker = new Worker(\n opts.name,\n async () => {\n log(`Running cron job ${opts.name}`);\n await handler();\n },\n { connection }\n );\n\n return {\n close: worker.close.bind(worker)\n };\n }\n };\n};\n"],"names":["log","_console","console","apply","concat","slice","call","arguments","seenNames","Set","opts","handler","has","name","Error","connection","parseRedisUrl","redisUrl","queue","Queue","defaultJobOptions","removeOnComplete","removeOnFail","start","cron","Promise","resolve","upsertJobScheduler","pattern","removeDependencyOnFailure","keepLogs","then","worker","Worker","e","reject","close","bind"],"mappings":"6TAIA,IAAIA,EAAM,WAAH,IAAAC,EAAA,OAAsBA,EAAAC,SAAQF,IAAGG,MAAAF,EAAA,CAAC,mBAAiBG,OAAA,GAAAC,MAAAC,KAAAC,YAAS,EAE/DC,EAAY,IAAIC,iBAEI,SACtBC,EAKAC,GAEA,GAAIH,EAAUI,IAAIF,EAAKG,MACrB,UAAUC,MAAwBJ,kBAAAA,EAAKG,KAAqB,mBAG9D,IAAIE,EAAaC,EAAaA,cAACN,EAAKO,UAChCC,EAAQ,IAAIC,EAAKA,MAACT,EAAKG,KAAM,CAC/BE,WAAAA,EACAK,kBAAmB,CACjBC,kBAAkB,EAClBC,cAAc,KAIlB,MAAO,CACLC,MAAK,WAAA,IAC0E,OAA7EvB,EAAyBU,qBAAAA,EAAKG,KAAqBH,iBAAAA,EAAKc,sBAAqBC,QAAAC,QAEvER,EAAMS,mBACV,OACA,CACEC,QAASlB,EAAKc,MAEhB,CACEd,KAAM,CACJmB,2BAA2B,EAC3BR,kBAAkB,EAClBC,cAAc,EACdQ,SAAU,MAGfC,KAAA,WAED,IAAIC,EAAS,IAAIC,EAAAA,OACfvB,EAAKG,KACM,WAAA,IAC4B,OAArCb,EAAG,oBAAqBU,EAAKG,MAAQY,QAAAC,QAC/Bf,KAASoB,KACjB,WAAA,EAAA,CAAC,MAAAG,GAAAT,OAAAA,QAAAU,OAAAD,EAAA,CAAA,EACD,CAAEnB,WAAAA,IAGJ,MAAO,CACLqB,MAAOJ,EAAOI,MAAMC,KAAKL,GACzB,EACJ,CAAC,MAAAE,GAAA,OAAAT,QAAAU,OAAAD,EAAA,CAAA,EAEL"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@lowerdeck/cron",
3
+ "version": "1.0.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "author": "Tobias Herber",
8
+ "license": "Apache 2",
9
+ "type": "module",
10
+ "source": "src/index.ts",
11
+ "exports": {
12
+ "types": "./dist/index.d.ts",
13
+ "require": "./dist/index.cjs",
14
+ "import": "./dist/index.module.js",
15
+ "default": "./dist/index.modern.js"
16
+ },
17
+ "main": "./dist/index.cjs",
18
+ "module": "./dist/index.module.js",
19
+ "types": "dist/index.d.ts",
20
+ "unpkg": "./dist/index.umd.js",
21
+ "scripts": {
22
+ "test": "vitest run --passWithNoTests",
23
+ "lint": "prettier src/**/*.ts --check",
24
+ "build": "microbundle"
25
+ },
26
+ "dependencies": {
27
+ "@lowerdeck/queue": "^1.0.0",
28
+ "@lowerdeck/redis": "^1.0.0",
29
+ "bullmq": "^5.34.3"
30
+ },
31
+ "devDependencies": {
32
+ "@lowerdeck/tsconfig": "^1.0.0",
33
+ "typescript": "5.8.2",
34
+ "microbundle": "^0.15.1",
35
+ "vitest": "^3.1.2"
36
+ }
37
+ }
package/src/index.ts ADDED
@@ -0,0 +1,63 @@
1
+ import { IQueueProcessor } from '@lowerdeck/queue';
2
+ import { parseRedisUrl } from '@lowerdeck/redis';
3
+ import { Queue, Worker } from 'bullmq';
4
+
5
+ let log = (...any: any[]) => console.log('[CRON MANAGER]:', ...any);
6
+
7
+ let seenNames = new Set<string>();
8
+
9
+ export let createCron = (
10
+ opts: {
11
+ name: string;
12
+ cron: string;
13
+ redisUrl: string;
14
+ },
15
+ handler: () => Promise<void>
16
+ ): IQueueProcessor => {
17
+ if (seenNames.has(opts.name)) {
18
+ throw new Error(`Cron with name ${opts.name} already exists`);
19
+ }
20
+
21
+ let connection = parseRedisUrl(opts.redisUrl);
22
+ let queue = new Queue(opts.name, {
23
+ connection,
24
+ defaultJobOptions: {
25
+ removeOnComplete: true,
26
+ removeOnFail: true
27
+ }
28
+ });
29
+
30
+ return {
31
+ start: async () => {
32
+ log(`Starting cron job ${opts.name} to run every ${opts.cron} using bullmq`);
33
+
34
+ await queue.upsertJobScheduler(
35
+ 'cron',
36
+ {
37
+ pattern: opts.cron
38
+ },
39
+ {
40
+ opts: {
41
+ removeDependencyOnFailure: true,
42
+ removeOnComplete: true,
43
+ removeOnFail: true,
44
+ keepLogs: 0
45
+ }
46
+ }
47
+ );
48
+
49
+ let worker = new Worker(
50
+ opts.name,
51
+ async () => {
52
+ log(`Running cron job ${opts.name}`);
53
+ await handler();
54
+ },
55
+ { connection }
56
+ );
57
+
58
+ return {
59
+ close: worker.close.bind(worker)
60
+ };
61
+ }
62
+ };
63
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "@lowerdeck/tsconfig/base.json",
4
+ "exclude": ["dist"],
5
+ "include": ["src"],
6
+ "compilerOptions": {
7
+ "outDir": "dist",
8
+ "lib": ["es2021"],
9
+ "target": "ES2019"
10
+ }
11
+ }