@motiadev/adapter-redis-cron 0.14.0-beta.165-285707 → 0.14.0-beta.165-602289
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/dist/index.d.mts +3 -0
- package/dist/index.mjs +3 -0
- package/dist/redis-cron-adapter.d.mts +30 -0
- package/dist/redis-cron-adapter.d.mts.map +1 -0
- package/dist/redis-cron-adapter.mjs +205 -0
- package/dist/redis-cron-adapter.mjs.map +1 -0
- package/dist/types.d.mts +12 -0
- package/dist/types.d.mts.map +1 -0
- package/package.json +11 -6
- package/tsdown.config.ts +17 -0
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -5
- package/dist/redis-cron-adapter.d.ts +0 -26
- package/dist/redis-cron-adapter.d.ts.map +0 -1
- package/dist/redis-cron-adapter.js +0 -232
- package/dist/types.d.ts +0 -9
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
package/dist/index.d.mts
ADDED
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { RedisCronAdapterOptions } from "./types.mjs";
|
|
2
|
+
import { RedisClientOptions, RedisClientType } from "redis";
|
|
3
|
+
import { CronAdapter, CronLock, CronLockInfo } from "@motiadev/core";
|
|
4
|
+
|
|
5
|
+
//#region src/redis-cron-adapter.d.ts
|
|
6
|
+
declare class RedisCronAdapter implements CronAdapter {
|
|
7
|
+
private client;
|
|
8
|
+
private keyPrefix;
|
|
9
|
+
private lockTTL;
|
|
10
|
+
private lockRetryDelay;
|
|
11
|
+
private lockRetryAttempts;
|
|
12
|
+
private instanceId;
|
|
13
|
+
private enableHealthCheck;
|
|
14
|
+
private connected;
|
|
15
|
+
private isExternalClient;
|
|
16
|
+
constructor(redisConnection: RedisClientType | RedisClientOptions, options?: RedisCronAdapterOptions);
|
|
17
|
+
private connect;
|
|
18
|
+
private ensureConnected;
|
|
19
|
+
private makeKey;
|
|
20
|
+
acquireLock(jobName: string, ttl?: number): Promise<CronLock | null>;
|
|
21
|
+
releaseLock(lock: CronLock): Promise<void>;
|
|
22
|
+
renewLock(lock: CronLock, ttl: number): Promise<boolean>;
|
|
23
|
+
isHealthy(): Promise<boolean>;
|
|
24
|
+
shutdown(): Promise<void>;
|
|
25
|
+
getActiveLocks(): Promise<CronLockInfo[]>;
|
|
26
|
+
private scanKeys;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { RedisCronAdapter };
|
|
30
|
+
//# sourceMappingURL=redis-cron-adapter.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-cron-adapter.d.mts","names":[],"sources":["../src/redis-cron-adapter.ts"],"sourcesContent":[],"mappings":";;;;;cASa,gBAAA,YAA4B;;EAA5B,QAAA,SAAA;EAWkB,QAAA,OAAA;EAAkB,QAAA,cAAA;EAA8B,QAAA,iBAAA;EA4DnB,QAAA,UAAA;EAAR,QAAA,iBAAA;EA8C1B,QAAA,SAAA;EAAW,QAAA,gBAAA;EA6Bb,WAAA,CAAA,eAAA,EAvIO,eAuIP,GAvIyB,kBAuIzB,EAAA,OAAA,CAAA,EAvIuD,uBAuIvD;EAAwB,QAAA,OAAA;EAwC3B,QAAA,eAAA;EAcD,QAAA,OAAA;EAyBc,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,GAAA,CAAA,EAAA,MAAA,CAAA,EA1JkB,OA0JlB,CA1J0B,QA0J1B,GAAA,IAAA,CAAA;EAAR,WAAA,CAAA,IAAA,EA5GA,QA4GA,CAAA,EA5GW,OA4GX,CAAA,IAAA,CAAA;EAjOe,SAAA,CAAA,IAAA,EAkJjB,QAlJiB,EAAA,GAAA,EAAA,MAAA,CAAA,EAkJO,OAlJP,CAAA,OAAA,CAAA;EAAW,SAAA,CAAA,CAAA,EA0L/B,OA1L+B,CAAA,OAAA,CAAA;cAwMhC;oBAyBM,QAAQ"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { createClient } from "redis";
|
|
2
|
+
import { v4 } from "uuid";
|
|
3
|
+
|
|
4
|
+
//#region src/redis-cron-adapter.ts
|
|
5
|
+
function isRedisClient(input) {
|
|
6
|
+
return typeof input === "object" && "isOpen" in input && "connect" in input;
|
|
7
|
+
}
|
|
8
|
+
var RedisCronAdapter = class {
|
|
9
|
+
constructor(redisConnection, options) {
|
|
10
|
+
this.connected = false;
|
|
11
|
+
this.keyPrefix = options?.keyPrefix || "motia:cron:lock:";
|
|
12
|
+
this.lockTTL = options?.lockTTL || 3e5;
|
|
13
|
+
this.lockRetryDelay = options?.lockRetryDelay || 1e3;
|
|
14
|
+
this.lockRetryAttempts = options?.lockRetryAttempts || 0;
|
|
15
|
+
this.instanceId = options?.instanceId || `motia-${v4()}`;
|
|
16
|
+
this.enableHealthCheck = options?.enableHealthCheck ?? true;
|
|
17
|
+
if (isRedisClient(redisConnection)) {
|
|
18
|
+
this.client = redisConnection;
|
|
19
|
+
this.isExternalClient = true;
|
|
20
|
+
this.connected = this.client.isOpen;
|
|
21
|
+
} else {
|
|
22
|
+
const config = redisConnection;
|
|
23
|
+
this.isExternalClient = false;
|
|
24
|
+
this.client = createClient(config);
|
|
25
|
+
this.client.on("error", (err) => {
|
|
26
|
+
console.error("[Redis Cron] Client error:", err);
|
|
27
|
+
});
|
|
28
|
+
this.client.on("connect", () => {
|
|
29
|
+
this.connected = true;
|
|
30
|
+
});
|
|
31
|
+
this.client.on("disconnect", () => {
|
|
32
|
+
console.warn("[Redis Cron] Disconnected");
|
|
33
|
+
this.connected = false;
|
|
34
|
+
});
|
|
35
|
+
this.client.on("reconnecting", () => {
|
|
36
|
+
console.log("[Redis Cron] Reconnecting...");
|
|
37
|
+
});
|
|
38
|
+
this.connect();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async connect() {
|
|
42
|
+
if (!this.connected && !this.client.isOpen) try {
|
|
43
|
+
await this.client.connect();
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("[Redis Cron] Failed to connect:", error);
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async ensureConnected() {
|
|
50
|
+
if (!this.client.isOpen) await this.connect();
|
|
51
|
+
}
|
|
52
|
+
makeKey(jobName) {
|
|
53
|
+
return `${this.keyPrefix}${jobName}`;
|
|
54
|
+
}
|
|
55
|
+
async acquireLock(jobName, ttl) {
|
|
56
|
+
await this.ensureConnected();
|
|
57
|
+
const lockTTL = ttl || this.lockTTL;
|
|
58
|
+
const lockId = v4();
|
|
59
|
+
const key = this.makeKey(jobName);
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
const lock = {
|
|
62
|
+
jobName,
|
|
63
|
+
lockId,
|
|
64
|
+
acquiredAt: now,
|
|
65
|
+
expiresAt: now + lockTTL,
|
|
66
|
+
instanceId: this.instanceId
|
|
67
|
+
};
|
|
68
|
+
const lockData = JSON.stringify(lock);
|
|
69
|
+
if (await this.client.set(key, lockData, {
|
|
70
|
+
PX: lockTTL,
|
|
71
|
+
NX: true
|
|
72
|
+
}) === "OK") return lock;
|
|
73
|
+
if (this.lockRetryAttempts > 0) for (let attempt = 0; attempt < this.lockRetryAttempts; attempt++) {
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, this.lockRetryDelay));
|
|
75
|
+
if (await this.client.set(key, lockData, {
|
|
76
|
+
PX: lockTTL,
|
|
77
|
+
NX: true
|
|
78
|
+
}) === "OK") return lock;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
async releaseLock(lock) {
|
|
83
|
+
await this.ensureConnected();
|
|
84
|
+
const key = this.makeKey(lock.jobName);
|
|
85
|
+
const luaScript = `
|
|
86
|
+
local current = redis.call('GET', KEYS[1])
|
|
87
|
+
if not current then
|
|
88
|
+
return 0
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
local lock = cjson.decode(current)
|
|
92
|
+
if lock.lockId == ARGV[1] and lock.instanceId == ARGV[2] then
|
|
93
|
+
return redis.call('DEL', KEYS[1])
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
return 0
|
|
97
|
+
`;
|
|
98
|
+
try {
|
|
99
|
+
await this.client.eval(luaScript, {
|
|
100
|
+
keys: [key],
|
|
101
|
+
arguments: [lock.lockId, lock.instanceId]
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error("[Redis Cron] Error releasing lock:", error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async renewLock(lock, ttl) {
|
|
108
|
+
await this.ensureConnected();
|
|
109
|
+
const key = this.makeKey(lock.jobName);
|
|
110
|
+
const expiresAt = Date.now() + ttl;
|
|
111
|
+
const renewedLock = {
|
|
112
|
+
...lock,
|
|
113
|
+
expiresAt
|
|
114
|
+
};
|
|
115
|
+
const luaScript = `
|
|
116
|
+
local current = redis.call('GET', KEYS[1])
|
|
117
|
+
if not current then
|
|
118
|
+
return 0
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
local lock = cjson.decode(current)
|
|
122
|
+
if lock.lockId == ARGV[1] and lock.instanceId == ARGV[2] then
|
|
123
|
+
redis.call('SET', KEYS[1], ARGV[3], 'PX', ARGV[4])
|
|
124
|
+
return 1
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
return 0
|
|
128
|
+
`;
|
|
129
|
+
try {
|
|
130
|
+
return await this.client.eval(luaScript, {
|
|
131
|
+
keys: [key],
|
|
132
|
+
arguments: [
|
|
133
|
+
lock.lockId,
|
|
134
|
+
lock.instanceId,
|
|
135
|
+
JSON.stringify(renewedLock),
|
|
136
|
+
ttl.toString()
|
|
137
|
+
]
|
|
138
|
+
}) === 1;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error("[Redis Cron] Error renewing lock:", error);
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async isHealthy() {
|
|
145
|
+
if (!this.enableHealthCheck) return true;
|
|
146
|
+
try {
|
|
147
|
+
await this.ensureConnected();
|
|
148
|
+
return await this.client.ping() === "PONG";
|
|
149
|
+
} catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async shutdown() {
|
|
154
|
+
await this.ensureConnected();
|
|
155
|
+
const pattern = `${this.keyPrefix}*`;
|
|
156
|
+
const keys = await this.scanKeys(pattern);
|
|
157
|
+
for (const key of keys) {
|
|
158
|
+
const lockData = await this.client.get(key);
|
|
159
|
+
if (lockData) try {
|
|
160
|
+
if (JSON.parse(lockData).instanceId === this.instanceId) await this.client.del(key);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error("[Redis Cron] Error cleaning up lock during shutdown:", error);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (!this.isExternalClient && this.client.isOpen) await this.client.quit();
|
|
166
|
+
}
|
|
167
|
+
async getActiveLocks() {
|
|
168
|
+
await this.ensureConnected();
|
|
169
|
+
const pattern = `${this.keyPrefix}*`;
|
|
170
|
+
const keys = await this.scanKeys(pattern);
|
|
171
|
+
const locks = [];
|
|
172
|
+
for (const key of keys) {
|
|
173
|
+
const lockData = await this.client.get(key);
|
|
174
|
+
if (lockData) try {
|
|
175
|
+
const lock = JSON.parse(lockData);
|
|
176
|
+
locks.push({
|
|
177
|
+
jobName: lock.jobName,
|
|
178
|
+
instanceId: lock.instanceId,
|
|
179
|
+
acquiredAt: lock.acquiredAt,
|
|
180
|
+
expiresAt: lock.expiresAt
|
|
181
|
+
});
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error("[Redis Cron] Error parsing lock data:", error);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return locks;
|
|
187
|
+
}
|
|
188
|
+
async scanKeys(pattern) {
|
|
189
|
+
const keys = [];
|
|
190
|
+
let cursor = "0";
|
|
191
|
+
do {
|
|
192
|
+
const result = await this.client.scan(cursor.toString(), {
|
|
193
|
+
MATCH: pattern,
|
|
194
|
+
COUNT: 100
|
|
195
|
+
});
|
|
196
|
+
cursor = result.cursor;
|
|
197
|
+
keys.push(...result.keys);
|
|
198
|
+
} while (String(cursor) !== "0");
|
|
199
|
+
return keys;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
//#endregion
|
|
204
|
+
export { RedisCronAdapter };
|
|
205
|
+
//# sourceMappingURL=redis-cron-adapter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-cron-adapter.mjs","names":["uuidv4","config: RedisClientOptions","lock: CronLock","renewedLock: CronLock","locks: CronLockInfo[]","keys: string[]","cursor: string | number"],"sources":["../src/redis-cron-adapter.ts"],"sourcesContent":["import type { CronAdapter, CronLock, CronLockInfo } from '@motiadev/core'\nimport { createClient, type RedisClientOptions, type RedisClientType } from 'redis'\nimport { v4 as uuidv4 } from 'uuid'\nimport type { RedisCronAdapterOptions } from './types'\n\nfunction isRedisClient(input: RedisClientType | RedisClientOptions): input is RedisClientType {\n return typeof input === 'object' && 'isOpen' in input && 'connect' in input\n}\n\nexport class RedisCronAdapter implements CronAdapter {\n private client: RedisClientType\n private keyPrefix: string\n private lockTTL: number\n private lockRetryDelay: number\n private lockRetryAttempts: number\n private instanceId: string\n private enableHealthCheck: boolean\n private connected = false\n private isExternalClient: boolean\n\n constructor(redisConnection: RedisClientType | RedisClientOptions, options?: RedisCronAdapterOptions) {\n this.keyPrefix = options?.keyPrefix || 'motia:cron:lock:'\n this.lockTTL = options?.lockTTL || 300000\n this.lockRetryDelay = options?.lockRetryDelay || 1000\n this.lockRetryAttempts = options?.lockRetryAttempts || 0\n this.instanceId = options?.instanceId || `motia-${uuidv4()}`\n this.enableHealthCheck = options?.enableHealthCheck ?? true\n\n if (isRedisClient(redisConnection)) {\n this.client = redisConnection\n this.isExternalClient = true\n this.connected = this.client.isOpen\n } else {\n const config: RedisClientOptions = redisConnection\n this.isExternalClient = false\n\n this.client = createClient(config) as RedisClientType\n\n this.client.on('error', (err) => {\n console.error('[Redis Cron] Client error:', err)\n })\n\n this.client.on('connect', () => {\n this.connected = true\n })\n\n this.client.on('disconnect', () => {\n console.warn('[Redis Cron] Disconnected')\n this.connected = false\n })\n\n this.client.on('reconnecting', () => {\n console.log('[Redis Cron] Reconnecting...')\n })\n\n this.connect()\n }\n }\n\n private async connect(): Promise<void> {\n if (!this.connected && !this.client.isOpen) {\n try {\n await this.client.connect()\n } catch (error) {\n console.error('[Redis Cron] Failed to connect:', error)\n throw error\n }\n }\n }\n\n private async ensureConnected(): Promise<void> {\n if (!this.client.isOpen) {\n await this.connect()\n }\n }\n\n private makeKey(jobName: string): string {\n return `${this.keyPrefix}${jobName}`\n }\n\n async acquireLock(jobName: string, ttl?: number): Promise<CronLock | null> {\n await this.ensureConnected()\n\n const lockTTL = ttl || this.lockTTL\n const lockId = uuidv4()\n const key = this.makeKey(jobName)\n const now = Date.now()\n const expiresAt = now + lockTTL\n\n const lock: CronLock = {\n jobName,\n lockId,\n acquiredAt: now,\n expiresAt,\n instanceId: this.instanceId,\n }\n\n const lockData = JSON.stringify(lock)\n\n const result = await this.client.set(key, lockData, {\n PX: lockTTL,\n NX: true,\n })\n\n if (result === 'OK') {\n return lock\n }\n\n if (this.lockRetryAttempts > 0) {\n for (let attempt = 0; attempt < this.lockRetryAttempts; attempt++) {\n await new Promise((resolve) => setTimeout(resolve, this.lockRetryDelay))\n\n const retryResult = await this.client.set(key, lockData, {\n PX: lockTTL,\n NX: true,\n })\n\n if (retryResult === 'OK') {\n return lock\n }\n }\n }\n\n return null\n }\n\n async releaseLock(lock: CronLock): Promise<void> {\n await this.ensureConnected()\n\n const key = this.makeKey(lock.jobName)\n\n const luaScript = `\n local current = redis.call('GET', KEYS[1])\n if not current then\n return 0\n end\n \n local lock = cjson.decode(current)\n if lock.lockId == ARGV[1] and lock.instanceId == ARGV[2] then\n return redis.call('DEL', KEYS[1])\n end\n \n return 0\n `\n\n try {\n await this.client.eval(luaScript, {\n keys: [key],\n arguments: [lock.lockId, lock.instanceId],\n })\n } catch (error) {\n console.error('[Redis Cron] Error releasing lock:', error)\n }\n }\n\n async renewLock(lock: CronLock, ttl: number): Promise<boolean> {\n await this.ensureConnected()\n\n const key = this.makeKey(lock.jobName)\n const now = Date.now()\n const expiresAt = now + ttl\n\n const renewedLock: CronLock = {\n ...lock,\n expiresAt,\n }\n\n const luaScript = `\n local current = redis.call('GET', KEYS[1])\n if not current then\n return 0\n end\n \n local lock = cjson.decode(current)\n if lock.lockId == ARGV[1] and lock.instanceId == ARGV[2] then\n redis.call('SET', KEYS[1], ARGV[3], 'PX', ARGV[4])\n return 1\n end\n \n return 0\n `\n\n try {\n const result = await this.client.eval(luaScript, {\n keys: [key],\n arguments: [lock.lockId, lock.instanceId, JSON.stringify(renewedLock), ttl.toString()],\n })\n\n return result === 1\n } catch (error) {\n console.error('[Redis Cron] Error renewing lock:', error)\n return false\n }\n }\n\n async isHealthy(): Promise<boolean> {\n if (!this.enableHealthCheck) {\n return true\n }\n\n try {\n await this.ensureConnected()\n const result = await this.client.ping()\n return result === 'PONG'\n } catch {\n return false\n }\n }\n\n async shutdown(): Promise<void> {\n await this.ensureConnected()\n\n const pattern = `${this.keyPrefix}*`\n const keys = await this.scanKeys(pattern)\n\n for (const key of keys) {\n const lockData = await this.client.get(key)\n if (lockData) {\n try {\n const lock: CronLock = JSON.parse(lockData)\n if (lock.instanceId === this.instanceId) {\n await this.client.del(key)\n }\n } catch (error) {\n console.error('[Redis Cron] Error cleaning up lock during shutdown:', error)\n }\n }\n }\n\n if (!this.isExternalClient && this.client.isOpen) {\n await this.client.quit()\n }\n }\n\n async getActiveLocks(): Promise<CronLockInfo[]> {\n await this.ensureConnected()\n\n const pattern = `${this.keyPrefix}*`\n const keys = await this.scanKeys(pattern)\n const locks: CronLockInfo[] = []\n\n for (const key of keys) {\n const lockData = await this.client.get(key)\n if (lockData) {\n try {\n const lock: CronLock = JSON.parse(lockData)\n locks.push({\n jobName: lock.jobName,\n instanceId: lock.instanceId,\n acquiredAt: lock.acquiredAt,\n expiresAt: lock.expiresAt,\n })\n } catch (error) {\n console.error('[Redis Cron] Error parsing lock data:', error)\n }\n }\n }\n\n return locks\n }\n\n private async scanKeys(pattern: string): Promise<string[]> {\n const keys: string[] = []\n let cursor: string | number = '0'\n\n do {\n const result = await this.client.scan(cursor.toString(), {\n MATCH: pattern,\n COUNT: 100,\n })\n cursor = result.cursor\n keys.push(...result.keys)\n } while (String(cursor) !== '0')\n\n return keys\n }\n}\n"],"mappings":"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"}
|
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
interface RedisCronAdapterOptions {
|
|
3
|
+
keyPrefix?: string;
|
|
4
|
+
lockTTL?: number;
|
|
5
|
+
lockRetryDelay?: number;
|
|
6
|
+
lockRetryAttempts?: number;
|
|
7
|
+
instanceId?: string;
|
|
8
|
+
enableHealthCheck?: boolean;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { RedisCronAdapterOptions };
|
|
12
|
+
//# sourceMappingURL=types.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";UAAiB,uBAAA;EAAA,SAAA,CAAA,EAAA,MAAA"}
|
package/package.json
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motiadev/adapter-redis-cron",
|
|
3
3
|
"description": "Redis cron adapter for Motia framework, enabling distributed cron job coordination to prevent duplicate executions across multiple instances.",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.mjs",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.mts",
|
|
8
|
+
"version": "0.14.0-beta.165-602289",
|
|
7
9
|
"dependencies": {
|
|
8
10
|
"redis": "^5.9.0",
|
|
9
11
|
"uuid": "^11.1.0",
|
|
10
|
-
"@motiadev/core": "0.14.0-beta.165-
|
|
12
|
+
"@motiadev/core": "0.14.0-beta.165-602289"
|
|
11
13
|
},
|
|
12
14
|
"devDependencies": {
|
|
13
15
|
"@types/node": "^22.10.2",
|
|
16
|
+
"rimraf": "^6.0.1",
|
|
17
|
+
"tsdown": "^0.16.6",
|
|
14
18
|
"typescript": "^5.7.2"
|
|
15
19
|
},
|
|
16
20
|
"peerDependencies": {
|
|
17
21
|
"@motiadev/core": ">=0.8.0"
|
|
18
22
|
},
|
|
19
23
|
"scripts": {
|
|
20
|
-
"build": "
|
|
24
|
+
"build": "tsdown",
|
|
25
|
+
"dev": "tsdown --watch",
|
|
21
26
|
"lint": "biome check .",
|
|
22
|
-
"
|
|
27
|
+
"clean": "rimraf dist"
|
|
23
28
|
}
|
|
24
29
|
}
|
package/tsdown.config.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineConfig } from 'tsdown'
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
entry: {
|
|
5
|
+
index: './src/index.ts',
|
|
6
|
+
},
|
|
7
|
+
format: 'esm',
|
|
8
|
+
platform: 'node',
|
|
9
|
+
external: ['@motiadev/core', 'redis', 'uuid'],
|
|
10
|
+
dts: {
|
|
11
|
+
build: true,
|
|
12
|
+
},
|
|
13
|
+
clean: true,
|
|
14
|
+
outDir: 'dist',
|
|
15
|
+
sourcemap: true,
|
|
16
|
+
unbundle: true,
|
|
17
|
+
})
|
package/dist/index.d.ts
DELETED
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,YAAY,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/index.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RedisCronAdapter = void 0;
|
|
4
|
-
var redis_cron_adapter_1 = require("./redis-cron-adapter");
|
|
5
|
-
Object.defineProperty(exports, "RedisCronAdapter", { enumerable: true, get: function () { return redis_cron_adapter_1.RedisCronAdapter; } });
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { CronAdapter, CronLock, CronLockInfo } from '@motiadev/core';
|
|
2
|
-
import { type RedisClientOptions, type RedisClientType } from 'redis';
|
|
3
|
-
import type { RedisCronAdapterOptions } from './types';
|
|
4
|
-
export declare class RedisCronAdapter implements CronAdapter {
|
|
5
|
-
private client;
|
|
6
|
-
private keyPrefix;
|
|
7
|
-
private lockTTL;
|
|
8
|
-
private lockRetryDelay;
|
|
9
|
-
private lockRetryAttempts;
|
|
10
|
-
private instanceId;
|
|
11
|
-
private enableHealthCheck;
|
|
12
|
-
private connected;
|
|
13
|
-
private isExternalClient;
|
|
14
|
-
constructor(redisConnection: RedisClientType | RedisClientOptions, options?: RedisCronAdapterOptions);
|
|
15
|
-
private connect;
|
|
16
|
-
private ensureConnected;
|
|
17
|
-
private makeKey;
|
|
18
|
-
acquireLock(jobName: string, ttl?: number): Promise<CronLock | null>;
|
|
19
|
-
releaseLock(lock: CronLock): Promise<void>;
|
|
20
|
-
renewLock(lock: CronLock, ttl: number): Promise<boolean>;
|
|
21
|
-
isHealthy(): Promise<boolean>;
|
|
22
|
-
shutdown(): Promise<void>;
|
|
23
|
-
getActiveLocks(): Promise<CronLockInfo[]>;
|
|
24
|
-
private scanKeys;
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=redis-cron-adapter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"redis-cron-adapter.d.ts","sourceRoot":"","sources":["../src/redis-cron-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACzE,OAAO,EAAgB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,OAAO,CAAA;AAEnF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA;AAMtD,qBAAa,gBAAiB,YAAW,WAAW;IAClD,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,iBAAiB,CAAQ;IACjC,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,gBAAgB,CAAS;gBAErB,eAAe,EAAE,eAAe,GAAG,kBAAkB,EAAE,OAAO,CAAC,EAAE,uBAAuB;YAuCtF,OAAO;YAWP,eAAe;IAM7B,OAAO,CAAC,OAAO;IAIT,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IA8CpE,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B1C,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAwCxD,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAc7B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBzB,cAAc,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YA2BjC,QAAQ;CAevB"}
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RedisCronAdapter = void 0;
|
|
4
|
-
const redis_1 = require("redis");
|
|
5
|
-
const uuid_1 = require("uuid");
|
|
6
|
-
function isRedisClient(input) {
|
|
7
|
-
return typeof input === 'object' && 'isOpen' in input && 'connect' in input;
|
|
8
|
-
}
|
|
9
|
-
class RedisCronAdapter {
|
|
10
|
-
constructor(redisConnection, options) {
|
|
11
|
-
this.connected = false;
|
|
12
|
-
this.keyPrefix = options?.keyPrefix || 'motia:cron:lock:';
|
|
13
|
-
this.lockTTL = options?.lockTTL || 300000;
|
|
14
|
-
this.lockRetryDelay = options?.lockRetryDelay || 1000;
|
|
15
|
-
this.lockRetryAttempts = options?.lockRetryAttempts || 0;
|
|
16
|
-
this.instanceId = options?.instanceId || `motia-${(0, uuid_1.v4)()}`;
|
|
17
|
-
this.enableHealthCheck = options?.enableHealthCheck ?? true;
|
|
18
|
-
if (isRedisClient(redisConnection)) {
|
|
19
|
-
this.client = redisConnection;
|
|
20
|
-
this.isExternalClient = true;
|
|
21
|
-
this.connected = this.client.isOpen;
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
const config = redisConnection;
|
|
25
|
-
this.isExternalClient = false;
|
|
26
|
-
this.client = (0, redis_1.createClient)(config);
|
|
27
|
-
this.client.on('error', (err) => {
|
|
28
|
-
console.error('[Redis Cron] Client error:', err);
|
|
29
|
-
});
|
|
30
|
-
this.client.on('connect', () => {
|
|
31
|
-
this.connected = true;
|
|
32
|
-
});
|
|
33
|
-
this.client.on('disconnect', () => {
|
|
34
|
-
console.warn('[Redis Cron] Disconnected');
|
|
35
|
-
this.connected = false;
|
|
36
|
-
});
|
|
37
|
-
this.client.on('reconnecting', () => {
|
|
38
|
-
console.log('[Redis Cron] Reconnecting...');
|
|
39
|
-
});
|
|
40
|
-
this.connect();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
async connect() {
|
|
44
|
-
if (!this.connected && !this.client.isOpen) {
|
|
45
|
-
try {
|
|
46
|
-
await this.client.connect();
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
console.error('[Redis Cron] Failed to connect:', error);
|
|
50
|
-
throw error;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
async ensureConnected() {
|
|
55
|
-
if (!this.client.isOpen) {
|
|
56
|
-
await this.connect();
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
makeKey(jobName) {
|
|
60
|
-
return `${this.keyPrefix}${jobName}`;
|
|
61
|
-
}
|
|
62
|
-
async acquireLock(jobName, ttl) {
|
|
63
|
-
await this.ensureConnected();
|
|
64
|
-
const lockTTL = ttl || this.lockTTL;
|
|
65
|
-
const lockId = (0, uuid_1.v4)();
|
|
66
|
-
const key = this.makeKey(jobName);
|
|
67
|
-
const now = Date.now();
|
|
68
|
-
const expiresAt = now + lockTTL;
|
|
69
|
-
const lock = {
|
|
70
|
-
jobName,
|
|
71
|
-
lockId,
|
|
72
|
-
acquiredAt: now,
|
|
73
|
-
expiresAt,
|
|
74
|
-
instanceId: this.instanceId,
|
|
75
|
-
};
|
|
76
|
-
const lockData = JSON.stringify(lock);
|
|
77
|
-
const result = await this.client.set(key, lockData, {
|
|
78
|
-
PX: lockTTL,
|
|
79
|
-
NX: true,
|
|
80
|
-
});
|
|
81
|
-
if (result === 'OK') {
|
|
82
|
-
return lock;
|
|
83
|
-
}
|
|
84
|
-
if (this.lockRetryAttempts > 0) {
|
|
85
|
-
for (let attempt = 0; attempt < this.lockRetryAttempts; attempt++) {
|
|
86
|
-
await new Promise((resolve) => setTimeout(resolve, this.lockRetryDelay));
|
|
87
|
-
const retryResult = await this.client.set(key, lockData, {
|
|
88
|
-
PX: lockTTL,
|
|
89
|
-
NX: true,
|
|
90
|
-
});
|
|
91
|
-
if (retryResult === 'OK') {
|
|
92
|
-
return lock;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
async releaseLock(lock) {
|
|
99
|
-
await this.ensureConnected();
|
|
100
|
-
const key = this.makeKey(lock.jobName);
|
|
101
|
-
const luaScript = `
|
|
102
|
-
local current = redis.call('GET', KEYS[1])
|
|
103
|
-
if not current then
|
|
104
|
-
return 0
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
local lock = cjson.decode(current)
|
|
108
|
-
if lock.lockId == ARGV[1] and lock.instanceId == ARGV[2] then
|
|
109
|
-
return redis.call('DEL', KEYS[1])
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
return 0
|
|
113
|
-
`;
|
|
114
|
-
try {
|
|
115
|
-
await this.client.eval(luaScript, {
|
|
116
|
-
keys: [key],
|
|
117
|
-
arguments: [lock.lockId, lock.instanceId],
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
catch (error) {
|
|
121
|
-
console.error('[Redis Cron] Error releasing lock:', error);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
async renewLock(lock, ttl) {
|
|
125
|
-
await this.ensureConnected();
|
|
126
|
-
const key = this.makeKey(lock.jobName);
|
|
127
|
-
const now = Date.now();
|
|
128
|
-
const expiresAt = now + ttl;
|
|
129
|
-
const renewedLock = {
|
|
130
|
-
...lock,
|
|
131
|
-
expiresAt,
|
|
132
|
-
};
|
|
133
|
-
const luaScript = `
|
|
134
|
-
local current = redis.call('GET', KEYS[1])
|
|
135
|
-
if not current then
|
|
136
|
-
return 0
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
local lock = cjson.decode(current)
|
|
140
|
-
if lock.lockId == ARGV[1] and lock.instanceId == ARGV[2] then
|
|
141
|
-
redis.call('SET', KEYS[1], ARGV[3], 'PX', ARGV[4])
|
|
142
|
-
return 1
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
return 0
|
|
146
|
-
`;
|
|
147
|
-
try {
|
|
148
|
-
const result = await this.client.eval(luaScript, {
|
|
149
|
-
keys: [key],
|
|
150
|
-
arguments: [lock.lockId, lock.instanceId, JSON.stringify(renewedLock), ttl.toString()],
|
|
151
|
-
});
|
|
152
|
-
return result === 1;
|
|
153
|
-
}
|
|
154
|
-
catch (error) {
|
|
155
|
-
console.error('[Redis Cron] Error renewing lock:', error);
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
async isHealthy() {
|
|
160
|
-
if (!this.enableHealthCheck) {
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
try {
|
|
164
|
-
await this.ensureConnected();
|
|
165
|
-
const result = await this.client.ping();
|
|
166
|
-
return result === 'PONG';
|
|
167
|
-
}
|
|
168
|
-
catch {
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
async shutdown() {
|
|
173
|
-
await this.ensureConnected();
|
|
174
|
-
const pattern = `${this.keyPrefix}*`;
|
|
175
|
-
const keys = await this.scanKeys(pattern);
|
|
176
|
-
for (const key of keys) {
|
|
177
|
-
const lockData = await this.client.get(key);
|
|
178
|
-
if (lockData) {
|
|
179
|
-
try {
|
|
180
|
-
const lock = JSON.parse(lockData);
|
|
181
|
-
if (lock.instanceId === this.instanceId) {
|
|
182
|
-
await this.client.del(key);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch (error) {
|
|
186
|
-
console.error('[Redis Cron] Error cleaning up lock during shutdown:', error);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (!this.isExternalClient && this.client.isOpen) {
|
|
191
|
-
await this.client.quit();
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
async getActiveLocks() {
|
|
195
|
-
await this.ensureConnected();
|
|
196
|
-
const pattern = `${this.keyPrefix}*`;
|
|
197
|
-
const keys = await this.scanKeys(pattern);
|
|
198
|
-
const locks = [];
|
|
199
|
-
for (const key of keys) {
|
|
200
|
-
const lockData = await this.client.get(key);
|
|
201
|
-
if (lockData) {
|
|
202
|
-
try {
|
|
203
|
-
const lock = JSON.parse(lockData);
|
|
204
|
-
locks.push({
|
|
205
|
-
jobName: lock.jobName,
|
|
206
|
-
instanceId: lock.instanceId,
|
|
207
|
-
acquiredAt: lock.acquiredAt,
|
|
208
|
-
expiresAt: lock.expiresAt,
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
catch (error) {
|
|
212
|
-
console.error('[Redis Cron] Error parsing lock data:', error);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return locks;
|
|
217
|
-
}
|
|
218
|
-
async scanKeys(pattern) {
|
|
219
|
-
const keys = [];
|
|
220
|
-
let cursor = '0';
|
|
221
|
-
do {
|
|
222
|
-
const result = await this.client.scan(cursor.toString(), {
|
|
223
|
-
MATCH: pattern,
|
|
224
|
-
COUNT: 100,
|
|
225
|
-
});
|
|
226
|
-
cursor = result.cursor;
|
|
227
|
-
keys.push(...result.keys);
|
|
228
|
-
} while (String(cursor) !== '0');
|
|
229
|
-
return keys;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
exports.RedisCronAdapter = RedisCronAdapter;
|
package/dist/types.d.ts
DELETED
package/dist/types.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B"}
|
package/dist/types.js
DELETED