queue-inspector-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +148 -0
- package/dist/backends/asynq-proto.d.ts +16 -0
- package/dist/backends/asynq-proto.js +144 -0
- package/dist/backends/asynq-proto.js.map +1 -0
- package/dist/backends/asynq.d.ts +45 -0
- package/dist/backends/asynq.js +183 -0
- package/dist/backends/asynq.js.map +1 -0
- package/dist/backends/bullmq.d.ts +46 -0
- package/dist/backends/bullmq.js +279 -0
- package/dist/backends/bullmq.js.map +1 -0
- package/dist/backends/index.d.ts +19 -0
- package/dist/backends/index.js +57 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/lua/deleteTask.lua +41 -0
- package/dist/backends/lua/removeJob.lua +346 -0
- package/dist/backends/lua/reprocessJob.lua +113 -0
- package/dist/backends/lua/runTask.lua +39 -0
- package/dist/backends/lua.d.ts +18 -0
- package/dist/backends/lua.js +18 -0
- package/dist/backends/lua.js.map +1 -0
- package/dist/backends/scripting.d.ts +14 -0
- package/dist/backends/scripting.js +34 -0
- package/dist/backends/scripting.js.map +1 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/format.d.ts +16 -0
- package/dist/format.js +49 -0
- package/dist/format.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/redis.d.ts +13 -0
- package/dist/redis.js +30 -0
- package/dist/redis.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +105 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { BackendError, } from "../types.js";
|
|
2
|
+
import { decodePayload, isoFromMillis, truncate } from "../format.js";
|
|
3
|
+
import { scanKeys } from "../redis.js";
|
|
4
|
+
import { attachScripts } from "./scripting.js";
|
|
5
|
+
// State names as BullMQ itself uses them. "waiting" is the `wait` list;
|
|
6
|
+
// "prioritized" and "waiting-children" only hold jobs when priorities or flows
|
|
7
|
+
// are used, but are reported for completeness.
|
|
8
|
+
const STATES = [
|
|
9
|
+
"waiting",
|
|
10
|
+
"active",
|
|
11
|
+
"delayed",
|
|
12
|
+
"prioritized",
|
|
13
|
+
"waiting-children",
|
|
14
|
+
"paused",
|
|
15
|
+
"completed",
|
|
16
|
+
"failed",
|
|
17
|
+
];
|
|
18
|
+
// Which Redis structure backs each state, and how the state maps to a key suffix.
|
|
19
|
+
const LIST_STATES = {
|
|
20
|
+
waiting: "wait",
|
|
21
|
+
active: "active",
|
|
22
|
+
paused: "paused",
|
|
23
|
+
};
|
|
24
|
+
const ZSET_STATES = {
|
|
25
|
+
delayed: "delayed",
|
|
26
|
+
prioritized: "prioritized",
|
|
27
|
+
"waiting-children": "waiting-children",
|
|
28
|
+
completed: "completed",
|
|
29
|
+
failed: "failed",
|
|
30
|
+
};
|
|
31
|
+
// Terminal sets are shown most-recent-first; scheduling sets soonest-first.
|
|
32
|
+
const REVERSED_ZSETS = new Set(["completed", "failed"]);
|
|
33
|
+
// The classic wait-list marker id; never a real job.
|
|
34
|
+
const MARKER = "0";
|
|
35
|
+
const JOB_FIELDS = [
|
|
36
|
+
"name",
|
|
37
|
+
"data",
|
|
38
|
+
"opts",
|
|
39
|
+
"timestamp",
|
|
40
|
+
"delay",
|
|
41
|
+
"processedOn",
|
|
42
|
+
"finishedOn",
|
|
43
|
+
"atm",
|
|
44
|
+
"failedReason",
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* Adapter for queues managed by BullMQ (github.com/taskforcesh/bullmq).
|
|
48
|
+
*
|
|
49
|
+
* Key layout, verified against a running BullMQ worker:
|
|
50
|
+
* bull:<q>:meta HASH queue metadata (version, paused)
|
|
51
|
+
* bull:<q>:wait / :active / :paused LIST of job ids
|
|
52
|
+
* bull:<q>:delayed / :prioritized / ZSET of job ids
|
|
53
|
+
* :completed / :failed
|
|
54
|
+
* bull:<q>:<id> HASH { name, data, opts, timestamp,
|
|
55
|
+
* atm, failedReason, ... }
|
|
56
|
+
* Mutations run BullMQ's own vendored scripts; see ./lua and ./scripting.ts.
|
|
57
|
+
*/
|
|
58
|
+
export class BullmqBackend {
|
|
59
|
+
redis;
|
|
60
|
+
prefix;
|
|
61
|
+
name = "bullmq";
|
|
62
|
+
states = STATES;
|
|
63
|
+
scripts;
|
|
64
|
+
constructor(redis, prefix = "bull") {
|
|
65
|
+
this.redis = redis;
|
|
66
|
+
this.prefix = prefix;
|
|
67
|
+
this.scripts = attachScripts(redis);
|
|
68
|
+
}
|
|
69
|
+
key(queue, suffix) {
|
|
70
|
+
return `${this.prefix}:${queue}:${suffix}`;
|
|
71
|
+
}
|
|
72
|
+
jobKey(queue, id) {
|
|
73
|
+
return `${this.prefix}:${queue}:${id}`;
|
|
74
|
+
}
|
|
75
|
+
async detectQueues() {
|
|
76
|
+
const metaKeys = await scanKeys(this.redis, `${this.prefix}:*:meta`);
|
|
77
|
+
const head = `${this.prefix}:`;
|
|
78
|
+
const names = metaKeys
|
|
79
|
+
.map((k) => k.slice(head.length, k.length - ":meta".length))
|
|
80
|
+
.filter(Boolean);
|
|
81
|
+
return [...new Set(names)].sort();
|
|
82
|
+
}
|
|
83
|
+
async assertQueue(queue) {
|
|
84
|
+
const exists = await this.redis.exists(this.key(queue, "meta"));
|
|
85
|
+
if (!exists) {
|
|
86
|
+
throw new BackendError(`bullmq queue "${queue}" was not found`, "queue_not_found");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async stats(queue) {
|
|
90
|
+
await this.assertQueue(queue);
|
|
91
|
+
const counts = {};
|
|
92
|
+
for (const state of STATES) {
|
|
93
|
+
if (state in LIST_STATES) {
|
|
94
|
+
counts[state] = await this.redis.llen(this.key(queue, LIST_STATES[state]));
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
counts[state] = await this.redis.zcard(this.key(queue, ZSET_STATES[state]));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return counts;
|
|
101
|
+
}
|
|
102
|
+
assertState(state) {
|
|
103
|
+
if (!STATES.includes(state)) {
|
|
104
|
+
throw new BackendError(`unknown bullmq state "${state}"; expected one of ${STATES.join(", ")}`, "invalid_state");
|
|
105
|
+
}
|
|
106
|
+
return state;
|
|
107
|
+
}
|
|
108
|
+
async idsForState(queue, state, page) {
|
|
109
|
+
const stop = page.offset + page.limit - 1;
|
|
110
|
+
if (state in LIST_STATES) {
|
|
111
|
+
const ids = await this.redis.lrange(this.key(queue, LIST_STATES[state]), page.offset, stop);
|
|
112
|
+
return ids.filter((id) => id !== MARKER);
|
|
113
|
+
}
|
|
114
|
+
const key = this.key(queue, ZSET_STATES[state]);
|
|
115
|
+
return REVERSED_ZSETS.has(state)
|
|
116
|
+
? this.redis.zrevrange(key, page.offset, stop)
|
|
117
|
+
: this.redis.zrange(key, page.offset, stop);
|
|
118
|
+
}
|
|
119
|
+
async listJobs(queue, rawState, page) {
|
|
120
|
+
await this.assertQueue(queue);
|
|
121
|
+
const state = this.assertState(rawState);
|
|
122
|
+
const ids = await this.idsForState(queue, state, page);
|
|
123
|
+
const summaries = [];
|
|
124
|
+
for (const id of ids) {
|
|
125
|
+
const hash = await this.readHash(queue, id);
|
|
126
|
+
if (hash)
|
|
127
|
+
summaries.push(this.toSummary(id, state, hash));
|
|
128
|
+
}
|
|
129
|
+
return summaries;
|
|
130
|
+
}
|
|
131
|
+
async getJob(queue, id) {
|
|
132
|
+
await this.assertQueue(queue);
|
|
133
|
+
const hash = await this.readHash(queue, id);
|
|
134
|
+
if (!hash)
|
|
135
|
+
return null;
|
|
136
|
+
const state = await this.resolveState(queue, id);
|
|
137
|
+
const decoded = decodePayload(Buffer.from(hash.data ?? "", "utf8"));
|
|
138
|
+
const timestamps = {
|
|
139
|
+
enqueuedAt: isoFromMillis(num(hash.timestamp)),
|
|
140
|
+
processedAt: isoFromMillis(num(hash.processedOn)),
|
|
141
|
+
finishedAt: isoFromMillis(num(hash.finishedOn)),
|
|
142
|
+
};
|
|
143
|
+
if (state === "delayed") {
|
|
144
|
+
const base = num(hash.timestamp) ?? 0;
|
|
145
|
+
const delay = num(hash.delay) ?? 0;
|
|
146
|
+
timestamps.processAt = isoFromMillis(base + delay);
|
|
147
|
+
}
|
|
148
|
+
const summary = this.toSummary(id, state, hash);
|
|
149
|
+
return {
|
|
150
|
+
...summary,
|
|
151
|
+
queue,
|
|
152
|
+
backend: this.name,
|
|
153
|
+
fullError: hash.failedReason || null,
|
|
154
|
+
timestamps,
|
|
155
|
+
...decoded,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async readHash(queue, id) {
|
|
159
|
+
const values = await this.redis.hmget(this.jobKey(queue, id), ...JOB_FIELDS);
|
|
160
|
+
if (values.every((v) => v === null))
|
|
161
|
+
return null;
|
|
162
|
+
const record = {};
|
|
163
|
+
JOB_FIELDS.forEach((field, i) => {
|
|
164
|
+
record[field] = values[i] ?? null;
|
|
165
|
+
});
|
|
166
|
+
return {
|
|
167
|
+
name: record.name ?? "",
|
|
168
|
+
data: record.data ?? "",
|
|
169
|
+
opts: record.opts ?? "",
|
|
170
|
+
timestamp: record.timestamp,
|
|
171
|
+
delay: record.delay,
|
|
172
|
+
processedOn: record.processedOn,
|
|
173
|
+
finishedOn: record.finishedOn,
|
|
174
|
+
atm: record.atm,
|
|
175
|
+
failedReason: record.failedReason,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
toSummary(id, state, hash) {
|
|
179
|
+
return {
|
|
180
|
+
id,
|
|
181
|
+
type: hash.name,
|
|
182
|
+
state,
|
|
183
|
+
enqueuedAt: isoFromMillis(num(hash.timestamp)),
|
|
184
|
+
attempts: num(hash.atm) ?? 0,
|
|
185
|
+
maxRetries: this.maxRetries(hash.opts),
|
|
186
|
+
lastError: hash.failedReason ? truncate(hash.failedReason) : null,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
maxRetries(optsJson) {
|
|
190
|
+
try {
|
|
191
|
+
const opts = JSON.parse(optsJson);
|
|
192
|
+
return typeof opts.attempts === "number" ? opts.attempts : null;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
isLifo(optsJson) {
|
|
199
|
+
try {
|
|
200
|
+
return Boolean(JSON.parse(optsJson).lifo);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/** Determines a job's current state by membership, mirroring BullMQ's own
|
|
207
|
+
* getState: check the terminal and scheduling sets, then the lists. */
|
|
208
|
+
async resolveState(queue, id) {
|
|
209
|
+
for (const state of ["completed", "failed", "delayed", "prioritized", "waiting-children"]) {
|
|
210
|
+
if ((await this.redis.zscore(this.key(queue, ZSET_STATES[state]), id)) !== null)
|
|
211
|
+
return state;
|
|
212
|
+
}
|
|
213
|
+
for (const state of ["active", "paused", "waiting"]) {
|
|
214
|
+
if ((await this.redis.lpos(this.key(queue, LIST_STATES[state]), id)) !== null)
|
|
215
|
+
return state;
|
|
216
|
+
}
|
|
217
|
+
// Present as a hash but not in any structure: being processed with a lock,
|
|
218
|
+
// or momentarily between states. BullMQ reports this as "active".
|
|
219
|
+
return "active";
|
|
220
|
+
}
|
|
221
|
+
async retryJob(queue, id) {
|
|
222
|
+
await this.assertQueue(queue);
|
|
223
|
+
const hash = await this.readHash(queue, id);
|
|
224
|
+
if (!hash)
|
|
225
|
+
throw new BackendError(`bullmq job "${id}" was not found in queue "${queue}"`, "job_not_found");
|
|
226
|
+
const state = await this.resolveState(queue, id);
|
|
227
|
+
if (state !== "failed" && state !== "completed") {
|
|
228
|
+
throw new BackendError(`bullmq job "${id}" is in state "${state}"; only failed or completed jobs can be retried`, "invalid_state");
|
|
229
|
+
}
|
|
230
|
+
const pushCmd = `${this.isLifo(hash.opts) ? "R" : "L"}PUSH`;
|
|
231
|
+
const propVal = state === "failed" ? "failedReason" : "returnvalue";
|
|
232
|
+
// Keys and args exactly as BullMQ's Scripts.reprocessJob builds them.
|
|
233
|
+
const result = await this.scripts.reprocessJob([
|
|
234
|
+
this.jobKey(queue, id),
|
|
235
|
+
this.key(queue, "events"),
|
|
236
|
+
this.key(queue, state),
|
|
237
|
+
this.key(queue, "wait"),
|
|
238
|
+
this.key(queue, "meta"),
|
|
239
|
+
this.key(queue, "paused"),
|
|
240
|
+
this.key(queue, "active"),
|
|
241
|
+
this.key(queue, "marker"),
|
|
242
|
+
], [id, pushCmd, propVal, state, "0", "0"]);
|
|
243
|
+
switch (result) {
|
|
244
|
+
case 1:
|
|
245
|
+
return { ok: true, message: `bullmq job ${id} moved back to wait in queue "${queue}"` };
|
|
246
|
+
case -1:
|
|
247
|
+
throw new BackendError(`bullmq job "${id}" was not found in queue "${queue}"`, "job_not_found");
|
|
248
|
+
case -3:
|
|
249
|
+
throw new BackendError(`bullmq job "${id}" was not in the ${state} set; its state changed concurrently`, "invalid_state");
|
|
250
|
+
default:
|
|
251
|
+
throw new BackendError(`bullmq retry returned unexpected code ${result}`, "invalid_state");
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
async deleteJob(queue, id) {
|
|
255
|
+
await this.assertQueue(queue);
|
|
256
|
+
const hash = await this.readHash(queue, id);
|
|
257
|
+
if (!hash)
|
|
258
|
+
throw new BackendError(`bullmq job "${id}" was not found in queue "${queue}"`, "job_not_found");
|
|
259
|
+
// removeChildren = 0: never cascade-delete a flow's children from here.
|
|
260
|
+
const result = await this.scripts.removeJob([this.jobKey(queue, id), this.key(queue, "repeat")], [id, 0, `${this.prefix}:${queue}:`]);
|
|
261
|
+
switch (result) {
|
|
262
|
+
case 1:
|
|
263
|
+
return { ok: true, message: `bullmq job ${id} deleted from queue "${queue}"` };
|
|
264
|
+
case 0:
|
|
265
|
+
throw new BackendError(`bullmq job "${id}" is locked (active) and cannot be deleted; let it finish or move it first`, "invalid_state");
|
|
266
|
+
case -8:
|
|
267
|
+
throw new BackendError(`bullmq job "${id}" is a job-scheduler entry and cannot be deleted this way`, "not_allowed");
|
|
268
|
+
default:
|
|
269
|
+
throw new BackendError(`bullmq delete returned unexpected code ${result}`, "invalid_state");
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function num(value) {
|
|
274
|
+
if (value === null || value === "")
|
|
275
|
+
return null;
|
|
276
|
+
const n = Number(value);
|
|
277
|
+
return Number.isFinite(n) ? n : null;
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=bullmq.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bullmq.js","sourceRoot":"","sources":["../../src/backends/bullmq.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Redis } from "ioredis";
|
|
2
|
+
import type { Config } from "../config.js";
|
|
3
|
+
import { type BackendName, type QueueBackend, type QueueRef } from "../types.js";
|
|
4
|
+
export { AsynqBackend } from "./asynq.js";
|
|
5
|
+
export { BullmqBackend } from "./bullmq.js";
|
|
6
|
+
/** Holds the enabled backends and maps a queue name to the backend that owns it. */
|
|
7
|
+
export declare class BackendRegistry {
|
|
8
|
+
private readonly backends;
|
|
9
|
+
constructor(redis: Redis, config: Config);
|
|
10
|
+
list(): QueueBackend[];
|
|
11
|
+
allQueues(): Promise<QueueRef[]>;
|
|
12
|
+
/**
|
|
13
|
+
* Resolves which backend a queue belongs to. When `hint` is given it wins;
|
|
14
|
+
* otherwise the queue is looked up across enabled backends. An ambiguous name
|
|
15
|
+
* (present in more than one backend) is an error the caller must resolve by
|
|
16
|
+
* passing `backend` explicitly.
|
|
17
|
+
*/
|
|
18
|
+
resolve(queue: string, hint?: BackendName): Promise<QueueBackend>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { BackendError } from "../types.js";
|
|
2
|
+
import { AsynqBackend } from "./asynq.js";
|
|
3
|
+
import { BullmqBackend } from "./bullmq.js";
|
|
4
|
+
export { AsynqBackend } from "./asynq.js";
|
|
5
|
+
export { BullmqBackend } from "./bullmq.js";
|
|
6
|
+
/** Holds the enabled backends and maps a queue name to the backend that owns it. */
|
|
7
|
+
export class BackendRegistry {
|
|
8
|
+
backends = new Map();
|
|
9
|
+
constructor(redis, config) {
|
|
10
|
+
for (const name of config.backends) {
|
|
11
|
+
if (name === "asynq")
|
|
12
|
+
this.backends.set(name, new AsynqBackend(redis, config.asynqPrefix));
|
|
13
|
+
if (name === "bullmq")
|
|
14
|
+
this.backends.set(name, new BullmqBackend(redis, config.bullPrefix));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
list() {
|
|
18
|
+
return [...this.backends.values()];
|
|
19
|
+
}
|
|
20
|
+
async allQueues() {
|
|
21
|
+
const refs = [];
|
|
22
|
+
for (const backend of this.list()) {
|
|
23
|
+
for (const name of await backend.detectQueues()) {
|
|
24
|
+
refs.push({ name, backend: backend.name });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return refs;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolves which backend a queue belongs to. When `hint` is given it wins;
|
|
31
|
+
* otherwise the queue is looked up across enabled backends. An ambiguous name
|
|
32
|
+
* (present in more than one backend) is an error the caller must resolve by
|
|
33
|
+
* passing `backend` explicitly.
|
|
34
|
+
*/
|
|
35
|
+
async resolve(queue, hint) {
|
|
36
|
+
if (hint) {
|
|
37
|
+
const backend = this.backends.get(hint);
|
|
38
|
+
if (!backend) {
|
|
39
|
+
throw new BackendError(`backend "${hint}" is not enabled`, "not_allowed");
|
|
40
|
+
}
|
|
41
|
+
return backend;
|
|
42
|
+
}
|
|
43
|
+
const matches = [];
|
|
44
|
+
for (const backend of this.list()) {
|
|
45
|
+
const queues = await backend.detectQueues();
|
|
46
|
+
if (queues.includes(queue))
|
|
47
|
+
matches.push(backend);
|
|
48
|
+
}
|
|
49
|
+
if (matches.length === 1)
|
|
50
|
+
return matches[0];
|
|
51
|
+
if (matches.length === 0) {
|
|
52
|
+
throw new BackendError(`queue "${queue}" was not found in any enabled backend`, "queue_not_found");
|
|
53
|
+
}
|
|
54
|
+
throw new BackendError(`queue "${queue}" exists in multiple backends (${matches.map((m) => m.name).join(", ")}); pass "backend" to choose one`, "invalid_state");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backends/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAsD,MAAM,aAAa,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,oFAAoF;AACpF,MAAM,OAAO,eAAe;IACT,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;IAEjE,YAAY,KAAY,EAAE,MAAc;QACtC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACnC,IAAI,IAAI,KAAK,OAAO;gBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;YAC3F,IAAI,IAAI,KAAK,QAAQ;gBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAED,IAAI;QACF,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,SAAS;QACb,MAAM,IAAI,GAAe,EAAE,CAAC;QAC5B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YAClC,KAAK,MAAM,IAAI,IAAI,MAAM,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;gBAChD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,IAAkB;QAC7C,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,YAAY,CAAC,YAAY,IAAI,kBAAkB,EAAE,aAAa,CAAC,CAAC;YAC5E,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;YAC5C,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC,CAAC,CAAE,CAAC;QAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,YAAY,CAAC,UAAU,KAAK,wCAAwC,EAAE,iBAAiB,CAAC,CAAC;QACrG,CAAC;QACD,MAAM,IAAI,YAAY,CACpB,UAAU,KAAK,kCAAkC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,iCAAiC,EACvH,eAAe,CAChB,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
-- Transcribed verbatim from Asynq (github.com/hibiken/asynq, MIT license),
|
|
2
|
+
-- internal/rdb/inspect.go `deleteTaskCmd`, version v0.25.1. This is the exact
|
|
3
|
+
-- atomic script Inspector.DeleteTask() runs. It removes the task from whichever
|
|
4
|
+
-- state structure holds it, cleans up the uniqueness lock, and deletes the task
|
|
5
|
+
-- hash. Kept as-is so delete behaviour matches the library.
|
|
6
|
+
--
|
|
7
|
+
-- KEYS[1] -> task key (asynq:{<qname>}:t:<task_id>)
|
|
8
|
+
-- KEYS[2] -> all groups set (asynq:{<qname>}:groups)
|
|
9
|
+
-- ARGV[1] -> task id
|
|
10
|
+
-- ARGV[2] -> queue key prefix (asynq:{<qname>}:)
|
|
11
|
+
-- ARGV[3] -> group key prefix (asynq:{<qname>}:g:)
|
|
12
|
+
--
|
|
13
|
+
-- Returns 1 on success, 0 if not found, -1 if the task is active.
|
|
14
|
+
if redis.call("EXISTS", KEYS[1]) == 0 then
|
|
15
|
+
return 0
|
|
16
|
+
end
|
|
17
|
+
local state, group = unpack(redis.call("HMGET", KEYS[1], "state", "group"))
|
|
18
|
+
if state == "active" then
|
|
19
|
+
return -1
|
|
20
|
+
end
|
|
21
|
+
if state == "pending" then
|
|
22
|
+
if redis.call("LREM", ARGV[2] .. state, 0, ARGV[1]) == 0 then
|
|
23
|
+
return redis.error_reply("task is not found in list: " .. tostring(ARGV[2] .. state))
|
|
24
|
+
end
|
|
25
|
+
elseif state == "aggregating" then
|
|
26
|
+
if redis.call("ZREM", ARGV[3] .. group, ARGV[1]) == 0 then
|
|
27
|
+
return redis.error_reply("task is not found in zset: " .. tostring(ARGV[3] .. group))
|
|
28
|
+
end
|
|
29
|
+
if redis.call("ZCARD", ARGV[3] .. group) == 0 then
|
|
30
|
+
redis.call("SREM", KEYS[2], group)
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
if redis.call("ZREM", ARGV[2] .. state, ARGV[1]) == 0 then
|
|
34
|
+
return redis.error_reply("task is not found in zset: " .. tostring(ARGV[2] .. state))
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
local unique_key = redis.call("HGET", KEYS[1], "unique_key")
|
|
38
|
+
if unique_key and unique_key ~= "" and redis.call("GET", unique_key) == ARGV[1] then
|
|
39
|
+
redis.call("DEL", unique_key)
|
|
40
|
+
end
|
|
41
|
+
return redis.call("DEL", KEYS[1])
|