nvent 0.4.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/LICENSE +21 -0
- package/README.md +389 -0
- package/dist/module.d.mts +193 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +974 -0
- package/dist/runtime/app/components/ConfirmDialog.d.vue.ts +33 -0
- package/dist/runtime/app/components/ConfirmDialog.vue +121 -0
- package/dist/runtime/app/components/ConfirmDialog.vue.d.ts +33 -0
- package/dist/runtime/app/components/FlowDiagram.d.vue.ts +64 -0
- package/dist/runtime/app/components/FlowDiagram.vue +338 -0
- package/dist/runtime/app/components/FlowDiagram.vue.d.ts +64 -0
- package/dist/runtime/app/components/FlowNodeCard.d.vue.ts +29 -0
- package/dist/runtime/app/components/FlowNodeCard.vue +156 -0
- package/dist/runtime/app/components/FlowNodeCard.vue.d.ts +29 -0
- package/dist/runtime/app/components/FlowRunOverview.d.vue.ts +9 -0
- package/dist/runtime/app/components/FlowRunOverview.vue +291 -0
- package/dist/runtime/app/components/FlowRunOverview.vue.d.ts +9 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.d.vue.ts +14 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.vue +60 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.vue.d.ts +14 -0
- package/dist/runtime/app/components/FlowRunTimeline.d.vue.ts +12 -0
- package/dist/runtime/app/components/FlowRunTimeline.vue +127 -0
- package/dist/runtime/app/components/FlowRunTimeline.vue.d.ts +12 -0
- package/dist/runtime/app/components/FlowScheduleDialog.d.vue.ts +16 -0
- package/dist/runtime/app/components/FlowScheduleDialog.vue +226 -0
- package/dist/runtime/app/components/FlowScheduleDialog.vue.d.ts +16 -0
- package/dist/runtime/app/components/FlowSchedulesList.d.vue.ts +12 -0
- package/dist/runtime/app/components/FlowSchedulesList.vue +99 -0
- package/dist/runtime/app/components/FlowSchedulesList.vue.d.ts +12 -0
- package/dist/runtime/app/components/JobScheduling.d.vue.ts +6 -0
- package/dist/runtime/app/components/JobScheduling.vue +203 -0
- package/dist/runtime/app/components/JobScheduling.vue.d.ts +6 -0
- package/dist/runtime/app/components/ListItem.d.vue.ts +23 -0
- package/dist/runtime/app/components/ListItem.vue +70 -0
- package/dist/runtime/app/components/ListItem.vue.d.ts +23 -0
- package/dist/runtime/app/components/QueueConfigDetails.d.vue.ts +45 -0
- package/dist/runtime/app/components/QueueConfigDetails.vue +412 -0
- package/dist/runtime/app/components/QueueConfigDetails.vue.d.ts +45 -0
- package/dist/runtime/app/components/StatCounter.d.vue.ts +9 -0
- package/dist/runtime/app/components/StatCounter.vue +25 -0
- package/dist/runtime/app/components/StatCounter.vue.d.ts +9 -0
- package/dist/runtime/app/components/TimelineList.d.vue.ts +7 -0
- package/dist/runtime/app/components/TimelineList.vue +210 -0
- package/dist/runtime/app/components/TimelineList.vue.d.ts +7 -0
- package/dist/runtime/app/components/nhealth/component-router.d.vue.ts +46 -0
- package/dist/runtime/app/components/nhealth/component-router.vue +26 -0
- package/dist/runtime/app/components/nhealth/component-router.vue.d.ts +46 -0
- package/dist/runtime/app/components/nhealth/component-shell.d.vue.ts +24 -0
- package/dist/runtime/app/components/nhealth/component-shell.vue +89 -0
- package/dist/runtime/app/components/nhealth/component-shell.vue.d.ts +24 -0
- package/dist/runtime/app/composables/useAnalyzedFlows.d.ts +14 -0
- package/dist/runtime/app/composables/useAnalyzedFlows.js +7 -0
- package/dist/runtime/app/composables/useComponentRouter.d.ts +38 -0
- package/dist/runtime/app/composables/useComponentRouter.js +240 -0
- package/dist/runtime/app/composables/useFlowRunTimeline.d.ts +15 -0
- package/dist/runtime/app/composables/useFlowRunTimeline.js +66 -0
- package/dist/runtime/app/composables/useFlowRuns.d.ts +11 -0
- package/dist/runtime/app/composables/useFlowRuns.js +31 -0
- package/dist/runtime/app/composables/useFlowRunsInfinite.d.ts +24 -0
- package/dist/runtime/app/composables/useFlowRunsInfinite.js +123 -0
- package/dist/runtime/app/composables/useFlowRunsPolling.d.ts +8 -0
- package/dist/runtime/app/composables/useFlowRunsPolling.js +26 -0
- package/dist/runtime/app/composables/useFlowState.d.ts +125 -0
- package/dist/runtime/app/composables/useFlowState.js +211 -0
- package/dist/runtime/app/composables/useFlowWebSocket.d.ts +27 -0
- package/dist/runtime/app/composables/useFlowWebSocket.js +205 -0
- package/dist/runtime/app/composables/useFlowsNavigation.d.ts +10 -0
- package/dist/runtime/app/composables/useFlowsNavigation.js +57 -0
- package/dist/runtime/app/composables/useQueueJobs.d.ts +20 -0
- package/dist/runtime/app/composables/useQueueJobs.js +20 -0
- package/dist/runtime/app/composables/useQueueUpdates.d.ts +26 -0
- package/dist/runtime/app/composables/useQueueUpdates.js +122 -0
- package/dist/runtime/app/composables/useQueues.d.ts +43 -0
- package/dist/runtime/app/composables/useQueues.js +26 -0
- package/dist/runtime/app/composables/useQueuesLive.d.ts +19 -0
- package/dist/runtime/app/composables/useQueuesLive.js +143 -0
- package/dist/runtime/app/pages/flows/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/flows/index.vue +645 -0
- package/dist/runtime/app/pages/flows/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/index.vue +34 -0
- package/dist/runtime/app/pages/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/index.vue +229 -0
- package/dist/runtime/app/pages/queues/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/job.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/job.vue +262 -0
- package/dist/runtime/app/pages/queues/job.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/jobs.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/jobs.vue +291 -0
- package/dist/runtime/app/pages/queues/jobs.vue.d.ts +3 -0
- package/dist/runtime/app/plugins/vueflow.client.d.ts +6 -0
- package/dist/runtime/app/plugins/vueflow.client.js +15 -0
- package/dist/runtime/constants.d.ts +11 -0
- package/dist/runtime/constants.js +11 -0
- package/dist/runtime/python/get_config.py +64 -0
- package/dist/runtime/schema.d.ts +37 -0
- package/dist/runtime/schema.js +20 -0
- package/dist/runtime/server/api/_flows/[name]/clear-history.delete.d.ts +10 -0
- package/dist/runtime/server/api/_flows/[name]/clear-history.delete.js +44 -0
- package/dist/runtime/server/api/_flows/[name]/runs.get.d.ts +7 -0
- package/dist/runtime/server/api/_flows/[name]/runs.get.js +53 -0
- package/dist/runtime/server/api/_flows/[name]/schedule.post.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/schedule.post.js +57 -0
- package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.js +42 -0
- package/dist/runtime/server/api/_flows/[name]/schedules.get.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/schedules.get.js +48 -0
- package/dist/runtime/server/api/_flows/[name]/start.post.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/start.post.js +9 -0
- package/dist/runtime/server/api/_flows/index.get.d.ts +6 -0
- package/dist/runtime/server/api/_flows/index.get.js +5 -0
- package/dist/runtime/server/api/_flows/ws.d.ts +60 -0
- package/dist/runtime/server/api/_flows/ws.js +183 -0
- package/dist/runtime/server/api/_queues/[name]/job/[id].get.d.ts +2 -0
- package/dist/runtime/server/api/_queues/[name]/job/[id].get.js +9 -0
- package/dist/runtime/server/api/_queues/[name]/job/index.get.d.ts +2 -0
- package/dist/runtime/server/api/_queues/[name]/job/index.get.js +18 -0
- package/dist/runtime/server/api/_queues/index.get.d.ts +2 -0
- package/dist/runtime/server/api/_queues/index.get.js +63 -0
- package/dist/runtime/server/api/_queues/ws.d.ts +48 -0
- package/dist/runtime/server/api/_queues/ws.js +200 -0
- package/dist/runtime/server/events/adapters/fileAdapter.d.ts +2 -0
- package/dist/runtime/server/events/adapters/fileAdapter.js +382 -0
- package/dist/runtime/server/events/adapters/memoryAdapter.d.ts +2 -0
- package/dist/runtime/server/events/adapters/memoryAdapter.js +171 -0
- package/dist/runtime/server/events/adapters/redis/redisAdapter.d.ts +2 -0
- package/dist/runtime/server/events/adapters/redis/redisAdapter.js +348 -0
- package/dist/runtime/server/events/adapters/redis/redisPubSubGateway.d.ts +29 -0
- package/dist/runtime/server/events/adapters/redis/redisPubSubGateway.js +82 -0
- package/dist/runtime/server/events/eventBus.d.ts +20 -0
- package/dist/runtime/server/events/eventBus.js +35 -0
- package/dist/runtime/server/events/eventStoreFactory.d.ts +19 -0
- package/dist/runtime/server/events/eventStoreFactory.js +44 -0
- package/dist/runtime/server/events/streamNames.d.ts +17 -0
- package/dist/runtime/server/events/streamNames.js +17 -0
- package/dist/runtime/server/events/types.d.ts +63 -0
- package/dist/runtime/server/events/types.js +0 -0
- package/dist/runtime/server/events/wiring/flowWiring.d.ts +33 -0
- package/dist/runtime/server/events/wiring/flowWiring.js +406 -0
- package/dist/runtime/server/events/wiring/registry.d.ts +10 -0
- package/dist/runtime/server/events/wiring/registry.js +24 -0
- package/dist/runtime/server/plugins/00.event-store.d.ts +13 -0
- package/dist/runtime/server/plugins/00.event-store.js +16 -0
- package/dist/runtime/server/plugins/00.ws-lifecycle.d.ts +5 -0
- package/dist/runtime/server/plugins/00.ws-lifecycle.js +66 -0
- package/dist/runtime/server/plugins/flow-management.d.ts +13 -0
- package/dist/runtime/server/plugins/flow-management.js +65 -0
- package/dist/runtime/server/plugins/queue-management.d.ts +2 -0
- package/dist/runtime/server/plugins/queue-management.js +27 -0
- package/dist/runtime/server/plugins/state-cleanup.d.ts +11 -0
- package/dist/runtime/server/plugins/state-cleanup.js +93 -0
- package/dist/runtime/server/plugins/worker-management.d.ts +2 -0
- package/dist/runtime/server/plugins/worker-management.js +33 -0
- package/dist/runtime/server/queue/adapters/bullmq.d.ts +17 -0
- package/dist/runtime/server/queue/adapters/bullmq.js +164 -0
- package/dist/runtime/server/queue/queueFactory.d.ts +3 -0
- package/dist/runtime/server/queue/queueFactory.js +10 -0
- package/dist/runtime/server/queue/types.d.ts +47 -0
- package/dist/runtime/server/queue/types.js +0 -0
- package/dist/runtime/server/state/adapters/redis.d.ts +2 -0
- package/dist/runtime/server/state/adapters/redis.js +42 -0
- package/dist/runtime/server/state/stateFactory.d.ts +3 -0
- package/dist/runtime/server/state/stateFactory.js +17 -0
- package/dist/runtime/server/state/types.d.ts +23 -0
- package/dist/runtime/server/state/types.js +0 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/defineQueueConfig.d.ts +154 -0
- package/dist/runtime/server/utils/defineQueueConfig.js +2 -0
- package/dist/runtime/server/utils/defineQueueWorker.d.ts +10 -0
- package/dist/runtime/server/utils/defineQueueWorker.js +17 -0
- package/dist/runtime/server/utils/useEventManager.d.ts +15 -0
- package/dist/runtime/server/utils/useEventManager.js +26 -0
- package/dist/runtime/server/utils/useEventStore.d.ts +20 -0
- package/dist/runtime/server/utils/useEventStore.js +119 -0
- package/dist/runtime/server/utils/useFlowEngine.d.ts +9 -0
- package/dist/runtime/server/utils/useFlowEngine.js +44 -0
- package/dist/runtime/server/utils/useLogs.d.ts +41 -0
- package/dist/runtime/server/utils/useLogs.js +74 -0
- package/dist/runtime/server/utils/useQueue.d.ts +31 -0
- package/dist/runtime/server/utils/useQueue.js +24 -0
- package/dist/runtime/server/utils/useServerLogger.d.ts +42 -0
- package/dist/runtime/server/utils/useServerLogger.js +54 -0
- package/dist/runtime/server/utils/wsPeerManager.d.ts +34 -0
- package/dist/runtime/server/utils/wsPeerManager.js +23 -0
- package/dist/runtime/server/worker/adapter.d.ts +4 -0
- package/dist/runtime/server/worker/adapter.js +65 -0
- package/dist/runtime/server/worker/runner/node.d.ts +27 -0
- package/dist/runtime/server/worker/runner/node.js +196 -0
- package/dist/runtime/types.d.ts +132 -0
- package/dist/types.d.mts +3 -0
- package/package.json +75 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useRuntimeConfig } from "#imports";
|
|
2
|
+
import { consola } from "consola";
|
|
3
|
+
const LOG_LEVELS = {
|
|
4
|
+
debug: 0,
|
|
5
|
+
info: 1,
|
|
6
|
+
warn: 2,
|
|
7
|
+
error: 3
|
|
8
|
+
};
|
|
9
|
+
const loggerCache = /* @__PURE__ */ new Map();
|
|
10
|
+
export function useServerLogger(scope) {
|
|
11
|
+
const rc = useRuntimeConfig();
|
|
12
|
+
const debugConfig = rc?.queue?.debug;
|
|
13
|
+
const configLevel = debugConfig?.level || process.env.NQ_DEBUG_LEVEL || "info";
|
|
14
|
+
const globalLevelNum = configLevel === "silent" ? Infinity : LOG_LEVELS[configLevel] ?? LOG_LEVELS.info;
|
|
15
|
+
const scopeKey = scope.replace(/[^a-z0-9]/gi, "_").toLowerCase();
|
|
16
|
+
const envKey = `NQ_DEBUG_${scopeKey.toUpperCase()}`;
|
|
17
|
+
const isScopeDebugEnabled = debugConfig?.[scopeKey] === true || process.env[envKey] === "1";
|
|
18
|
+
let scopedConsola = loggerCache.get(scope);
|
|
19
|
+
if (!scopedConsola) {
|
|
20
|
+
scopedConsola = consola.withTag(scope);
|
|
21
|
+
loggerCache.set(scope, scopedConsola);
|
|
22
|
+
}
|
|
23
|
+
const logger = scopedConsola;
|
|
24
|
+
function isEnabled(level) {
|
|
25
|
+
const levelNum = LOG_LEVELS[level];
|
|
26
|
+
if (isScopeDebugEnabled && level === "debug") {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
return levelNum >= globalLevelNum;
|
|
30
|
+
}
|
|
31
|
+
function log(level, message, context) {
|
|
32
|
+
if (!isEnabled(level)) return;
|
|
33
|
+
if (context && Object.keys(context).length > 0) {
|
|
34
|
+
logger[level](message, context);
|
|
35
|
+
} else {
|
|
36
|
+
logger[level](message);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
debug: (message, context) => log("debug", message, context),
|
|
41
|
+
info: (message, context) => log("info", message, context),
|
|
42
|
+
warn: (message, context) => log("warn", message, context),
|
|
43
|
+
error: (message, context) => log("error", message, context),
|
|
44
|
+
log,
|
|
45
|
+
isEnabled,
|
|
46
|
+
consola: logger
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function isDebugEnabled() {
|
|
50
|
+
const rc = useRuntimeConfig();
|
|
51
|
+
const debugConfig = rc?.queue?.debug;
|
|
52
|
+
const level = debugConfig?.level || process.env.NQ_DEBUG_LEVEL;
|
|
53
|
+
return level === "debug" || Object.keys(debugConfig || {}).some((key) => key !== "level");
|
|
54
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Peer Manager
|
|
3
|
+
*
|
|
4
|
+
* Tracks active WebSocket connections for graceful shutdown during HMR.
|
|
5
|
+
* Auto-imported in Nitro server context.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Register a peer to be tracked for graceful shutdown
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerWsPeer(peer: any): void;
|
|
11
|
+
/**
|
|
12
|
+
* Unregister a peer (called when connection closes normally)
|
|
13
|
+
*/
|
|
14
|
+
export declare function unregisterWsPeer(peer: any): void;
|
|
15
|
+
/**
|
|
16
|
+
* Get all currently active WebSocket peers
|
|
17
|
+
*/
|
|
18
|
+
export declare function getActivePeers(): any[];
|
|
19
|
+
/**
|
|
20
|
+
* Check if server is currently shutting down
|
|
21
|
+
*/
|
|
22
|
+
export declare function isServerShuttingDown(): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Set the shutdown state
|
|
25
|
+
*/
|
|
26
|
+
export declare function setShuttingDown(state: boolean): void;
|
|
27
|
+
/**
|
|
28
|
+
* Clear all tracked peers
|
|
29
|
+
*/
|
|
30
|
+
export declare function clearAllPeers(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Get the count of active peers
|
|
33
|
+
*/
|
|
34
|
+
export declare function getActivePeerCount(): number;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const activePeers = /* @__PURE__ */ new Set();
|
|
2
|
+
let isShuttingDown = false;
|
|
3
|
+
export function registerWsPeer(peer) {
|
|
4
|
+
activePeers.add(peer);
|
|
5
|
+
}
|
|
6
|
+
export function unregisterWsPeer(peer) {
|
|
7
|
+
activePeers.delete(peer);
|
|
8
|
+
}
|
|
9
|
+
export function getActivePeers() {
|
|
10
|
+
return Array.from(activePeers);
|
|
11
|
+
}
|
|
12
|
+
export function isServerShuttingDown() {
|
|
13
|
+
return isShuttingDown;
|
|
14
|
+
}
|
|
15
|
+
export function setShuttingDown(state) {
|
|
16
|
+
isShuttingDown = state;
|
|
17
|
+
}
|
|
18
|
+
export function clearAllPeers() {
|
|
19
|
+
activePeers.clear();
|
|
20
|
+
}
|
|
21
|
+
export function getActivePeerCount() {
|
|
22
|
+
return activePeers.size;
|
|
23
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Worker } from 'bullmq';
|
|
2
|
+
import { type NodeHandler } from './runner/node.js';
|
|
3
|
+
export declare function closeAllWorkers(): Promise<void>;
|
|
4
|
+
export declare function registerTsWorker(queueName: string, jobName: string, handler: NodeHandler, opts?: any): Promise<Worker<any, any, string>>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Worker } from "bullmq";
|
|
2
|
+
import { createBullMQProcessor } from "./runner/node.js";
|
|
3
|
+
import { useRuntimeConfig, useServerLogger } from "#imports";
|
|
4
|
+
const registeredWorkers = /* @__PURE__ */ new Map();
|
|
5
|
+
const logger = useServerLogger("worker-adapter");
|
|
6
|
+
export async function closeAllWorkers() {
|
|
7
|
+
const closePromises = [];
|
|
8
|
+
for (const [queueName, info] of registeredWorkers.entries()) {
|
|
9
|
+
closePromises.push(
|
|
10
|
+
info.worker.close().catch((err) => {
|
|
11
|
+
if (err.code !== "EPIPE" && !err.message?.includes("Connection is closed")) {
|
|
12
|
+
logger.warn("Error closing worker for queue", { queueName, error: err });
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
await Promise.allSettled(closePromises);
|
|
18
|
+
registeredWorkers.clear();
|
|
19
|
+
logger.info("[closeAllWorkers] All workers closed");
|
|
20
|
+
}
|
|
21
|
+
export async function registerTsWorker(queueName, jobName, handler, opts) {
|
|
22
|
+
let info = registeredWorkers.get(queueName);
|
|
23
|
+
if (info) {
|
|
24
|
+
logger.info(`[registerTsWorker] Adding handler for job "${jobName}" to existing worker for queue "${queueName}"`);
|
|
25
|
+
info.handlers.set(jobName, handler);
|
|
26
|
+
return info.worker;
|
|
27
|
+
}
|
|
28
|
+
logger.info(`[registerTsWorker] Creating new worker for queue: ${queueName}`);
|
|
29
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
30
|
+
handlers.set(jobName, handler);
|
|
31
|
+
const dispatcher = async (job) => {
|
|
32
|
+
const handler2 = handlers.get(job.name);
|
|
33
|
+
if (!handler2) {
|
|
34
|
+
const error = `[Worker] No handler registered for job "${job.name}" on queue "${queueName}". Available handlers: ${Array.from(handlers.keys()).join(", ")}`;
|
|
35
|
+
logger.error(error);
|
|
36
|
+
throw new Error(error);
|
|
37
|
+
}
|
|
38
|
+
const processor = createBullMQProcessor(handler2, queueName);
|
|
39
|
+
return processor(job);
|
|
40
|
+
};
|
|
41
|
+
const rc = useRuntimeConfig();
|
|
42
|
+
const connection = rc?.queue?.queue?.redis;
|
|
43
|
+
const shouldPause = opts?.autorun === false;
|
|
44
|
+
const worker = new Worker(queueName, dispatcher, { connection, ...opts || {} });
|
|
45
|
+
if (shouldPause) {
|
|
46
|
+
await worker.pause();
|
|
47
|
+
logger.info(`[registerTsWorker] Worker for queue "${queueName}" created but paused (autorun: false)`);
|
|
48
|
+
} else {
|
|
49
|
+
logger.info(`[registerTsWorker] Worker for queue "${queueName}" created and running`);
|
|
50
|
+
}
|
|
51
|
+
worker.on("error", (err) => {
|
|
52
|
+
logger.error(`[Worker] Error in worker for queue "${queueName}":`, err);
|
|
53
|
+
});
|
|
54
|
+
worker.on("failed", (job, err) => {
|
|
55
|
+
logger.error(`[Worker] Job failed in worker for queue "${queueName}":`, {
|
|
56
|
+
jobId: job?.id,
|
|
57
|
+
jobName: job?.name,
|
|
58
|
+
error: err.message,
|
|
59
|
+
stack: err.stack
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
info = { worker, handlers };
|
|
63
|
+
registeredWorkers.set(queueName, info);
|
|
64
|
+
return worker;
|
|
65
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Job as BullJob } from 'bullmq';
|
|
2
|
+
import { useFlowEngine } from '#imports';
|
|
3
|
+
export interface RunLogger {
|
|
4
|
+
log: (level: 'debug' | 'info' | 'warn' | 'error', msg: string, meta?: any) => void;
|
|
5
|
+
}
|
|
6
|
+
export interface RunState {
|
|
7
|
+
get<T = any>(key: string): Promise<T | null>;
|
|
8
|
+
set<T = any>(key: string, value: T, opts?: {
|
|
9
|
+
ttl?: number;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
delete(key: string): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export interface RunContext {
|
|
14
|
+
jobId?: string;
|
|
15
|
+
queue?: string;
|
|
16
|
+
flowId?: string;
|
|
17
|
+
flowName?: string;
|
|
18
|
+
stepName?: string;
|
|
19
|
+
stepId?: string;
|
|
20
|
+
attempt?: number;
|
|
21
|
+
logger: RunLogger;
|
|
22
|
+
state: RunState;
|
|
23
|
+
flow: ReturnType<typeof useFlowEngine>;
|
|
24
|
+
}
|
|
25
|
+
export declare function buildContext(partial?: Partial<RunContext>): RunContext;
|
|
26
|
+
export type NodeHandler = (input: any, ctx: RunContext) => Promise<any>;
|
|
27
|
+
export declare function createBullMQProcessor(handler: NodeHandler, queueName: string): (job: BullJob) => Promise<any>;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { getStateProvider } from "../../state/stateFactory.js";
|
|
3
|
+
import { useRuntimeConfig, useLogs, useFlowEngine, useEventManager, useServerLogger } from "#imports";
|
|
4
|
+
const logger = useServerLogger("node-runner");
|
|
5
|
+
const defaultState = {
|
|
6
|
+
async get() {
|
|
7
|
+
return null;
|
|
8
|
+
},
|
|
9
|
+
async set() {
|
|
10
|
+
},
|
|
11
|
+
async delete() {
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function scopeKey(baseKey, flowId) {
|
|
15
|
+
if (!flowId) return baseKey;
|
|
16
|
+
return `flow:${flowId}:${baseKey}`;
|
|
17
|
+
}
|
|
18
|
+
export function buildContext(partial) {
|
|
19
|
+
const state = partial?.state || (() => {
|
|
20
|
+
try {
|
|
21
|
+
const state2 = getStateProvider();
|
|
22
|
+
const rc = useRuntimeConfig();
|
|
23
|
+
const cleanupCfg = rc?.queue?.state?.cleanup || { strategy: "never" };
|
|
24
|
+
return {
|
|
25
|
+
async get(key) {
|
|
26
|
+
return state2.get(scopeKey(key, partial?.flowId));
|
|
27
|
+
},
|
|
28
|
+
async set(key, value, opts) {
|
|
29
|
+
const ttl = opts?.ttl ?? (cleanupCfg?.strategy === "ttl" ? cleanupCfg?.ttlMs : void 0);
|
|
30
|
+
return state2.set(scopeKey(key, partial?.flowId), value, ttl ? { ttl } : void 0);
|
|
31
|
+
},
|
|
32
|
+
async delete(key) {
|
|
33
|
+
return state2.delete(scopeKey(key, partial?.flowId));
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
} catch {
|
|
37
|
+
return defaultState;
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
const logger2 = partial?.logger || (() => {
|
|
41
|
+
const logs = useLogs();
|
|
42
|
+
return {
|
|
43
|
+
log: (level, msg, meta) => {
|
|
44
|
+
const mergedMeta = { ...meta || {} };
|
|
45
|
+
void logs.publishLog(level, msg, mergedMeta, { queue: partial?.queue, jobId: partial?.jobId, flowId: partial?.flowId });
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
const baseFlowEngine = useFlowEngine();
|
|
50
|
+
const flow = {
|
|
51
|
+
...baseFlowEngine,
|
|
52
|
+
emit: async (trigger, payload = {}) => {
|
|
53
|
+
const enrichedPayload = {
|
|
54
|
+
...payload,
|
|
55
|
+
flowId: payload.flowId || partial?.flowId,
|
|
56
|
+
flowName: payload.flowName || partial?.flowName
|
|
57
|
+
};
|
|
58
|
+
return baseFlowEngine.emit(trigger, enrichedPayload);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
jobId: partial?.jobId,
|
|
63
|
+
queue: partial?.queue,
|
|
64
|
+
flowId: partial?.flowId,
|
|
65
|
+
flowName: partial?.flowName,
|
|
66
|
+
stepName: partial?.stepName,
|
|
67
|
+
stepId: partial?.stepId,
|
|
68
|
+
attempt: partial?.attempt,
|
|
69
|
+
logger: logger2,
|
|
70
|
+
state,
|
|
71
|
+
flow
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function createBullMQProcessor(handler, queueName) {
|
|
75
|
+
return async function processor(job) {
|
|
76
|
+
if (job.data?.__scheduledFlowStart) {
|
|
77
|
+
const { __flowName, __flowInput } = job.data;
|
|
78
|
+
try {
|
|
79
|
+
const { startFlow } = useFlowEngine();
|
|
80
|
+
const result2 = await startFlow(__flowName, __flowInput || {});
|
|
81
|
+
return {
|
|
82
|
+
scheduled: true,
|
|
83
|
+
flowId: result2.flowId,
|
|
84
|
+
flowName: __flowName
|
|
85
|
+
};
|
|
86
|
+
} catch (err) {
|
|
87
|
+
logger.error("[scheduled-flow] Failed to start flow:", err);
|
|
88
|
+
throw err;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const eventMgr = useEventManager();
|
|
92
|
+
const rc = useRuntimeConfig();
|
|
93
|
+
const autoScope = rc?.queue?.state?.autoScope || "always";
|
|
94
|
+
const providedFlow = job.data?.flowId;
|
|
95
|
+
const flowId = providedFlow || (autoScope === "always" ? randomUUID() : void 0);
|
|
96
|
+
const attempt = (job.attemptsMade || 0) + 1;
|
|
97
|
+
const maxAttempts = job.opts?.attempts || 1;
|
|
98
|
+
const isFinalAttempt = attempt >= maxAttempts;
|
|
99
|
+
const stepRunId = `${String(flowId || job.id)}__${job.name}__attempt-${attempt}`;
|
|
100
|
+
const flowName = job.data?.flowName || "unknown";
|
|
101
|
+
const ctx = buildContext({
|
|
102
|
+
jobId: job.id,
|
|
103
|
+
queue: queueName,
|
|
104
|
+
flowId,
|
|
105
|
+
flowName,
|
|
106
|
+
stepName: job.name,
|
|
107
|
+
stepId: stepRunId,
|
|
108
|
+
attempt
|
|
109
|
+
});
|
|
110
|
+
const attemptLogger = {
|
|
111
|
+
log: (level, msg, meta) => {
|
|
112
|
+
const enriched = { ...meta || {}, stepName: job.name, attempt, stepRunId, flowName };
|
|
113
|
+
ctx.logger.log(level, msg, enriched);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
try {
|
|
117
|
+
await eventMgr.publishBus({
|
|
118
|
+
type: "step.started",
|
|
119
|
+
runId: flowId || "unknown",
|
|
120
|
+
flowName,
|
|
121
|
+
stepName: job.name,
|
|
122
|
+
stepId: stepRunId,
|
|
123
|
+
attempt,
|
|
124
|
+
data: { jobId: job.id, name: job.name, queue: queueName }
|
|
125
|
+
});
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
let result;
|
|
129
|
+
try {
|
|
130
|
+
const workerInput = job.data?.input !== void 0 ? job.data.input : job.data;
|
|
131
|
+
result = await handler(workerInput, { ...ctx, logger: attemptLogger });
|
|
132
|
+
} catch (err) {
|
|
133
|
+
logger.error(`[worker] Job failed: ${job.name} (${job.id})`, {
|
|
134
|
+
queue: queueName,
|
|
135
|
+
flowId,
|
|
136
|
+
flowName,
|
|
137
|
+
stepName: job.name,
|
|
138
|
+
error: err?.message || String(err),
|
|
139
|
+
stack: err?.stack
|
|
140
|
+
});
|
|
141
|
+
const willRetry = !isFinalAttempt;
|
|
142
|
+
try {
|
|
143
|
+
await eventMgr.publishBus({
|
|
144
|
+
type: "step.failed",
|
|
145
|
+
runId: flowId || "unknown",
|
|
146
|
+
flowName,
|
|
147
|
+
stepName: job.name,
|
|
148
|
+
stepId: stepRunId,
|
|
149
|
+
attempt,
|
|
150
|
+
data: {
|
|
151
|
+
error: String(err?.message || err),
|
|
152
|
+
stack: err?.stack
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
if (willRetry) {
|
|
158
|
+
try {
|
|
159
|
+
await eventMgr.publishBus({
|
|
160
|
+
type: "step.retry",
|
|
161
|
+
runId: flowId || "unknown",
|
|
162
|
+
flowName,
|
|
163
|
+
stepName: job.name,
|
|
164
|
+
stepId: stepRunId,
|
|
165
|
+
attempt,
|
|
166
|
+
data: {
|
|
167
|
+
stepName: job.name,
|
|
168
|
+
queue: queueName,
|
|
169
|
+
error: String(err?.message || err),
|
|
170
|
+
stack: err?.stack,
|
|
171
|
+
attempt,
|
|
172
|
+
maxAttempts,
|
|
173
|
+
nextAttempt: attempt + 1
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
} catch {
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
throw err;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const eventMgr2 = useEventManager();
|
|
183
|
+
await eventMgr2.publishBus({
|
|
184
|
+
type: "step.completed",
|
|
185
|
+
runId: flowId || "unknown",
|
|
186
|
+
flowName,
|
|
187
|
+
stepName: job.name,
|
|
188
|
+
stepId: stepRunId,
|
|
189
|
+
attempt,
|
|
190
|
+
data: { result }
|
|
191
|
+
});
|
|
192
|
+
} catch {
|
|
193
|
+
}
|
|
194
|
+
return result;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { WorkerOptions as BullmqWorkerOptions } from 'bullmq'
|
|
2
|
+
import type z from 'zod'
|
|
3
|
+
import type colors from 'tailwindcss/colors'
|
|
4
|
+
import type { JobSchemaArray, JobSchema } from './schema'
|
|
5
|
+
|
|
6
|
+
type NeutralColor = 'slate' | 'gray' | 'zinc' | 'neutral' | 'stone'
|
|
7
|
+
export type Color = Exclude<keyof typeof colors, 'inherit' | 'current' | 'transparent' | 'black' | 'white' | NeutralColor> | NeutralColor
|
|
8
|
+
|
|
9
|
+
export type Jobs = z.infer<typeof JobSchemaArray>
|
|
10
|
+
export type Job = z.infer<typeof JobSchema>
|
|
11
|
+
|
|
12
|
+
export type WorkerOptions = Omit<BullmqWorkerOptions, 'connection' | 'useWorkerThreads'>
|
|
13
|
+
|
|
14
|
+
export type WorkerConfig = Record<string, WorkerOptions>
|
|
15
|
+
|
|
16
|
+
export type QueueData = {
|
|
17
|
+
name: string
|
|
18
|
+
origin: 'remote' | 'local'
|
|
19
|
+
active: boolean
|
|
20
|
+
jobs: JobCounts
|
|
21
|
+
worker: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Declarations for worker authoring helpers available via auto-imports at runtime
|
|
25
|
+
// These declarations make TS happy in worker files and tests.
|
|
26
|
+
export declare function defineQueueWorker(processor: (...args: any[]) => any): any
|
|
27
|
+
export declare function defineQueueConfig(cfg: any): any
|
|
28
|
+
|
|
29
|
+
// v0.4 Event Schema
|
|
30
|
+
export type EventType = 'flow.start' | 'flow.completed' | 'flow.failed' | 'step.started' | 'step.completed' | 'step.failed' | 'step.retry' | 'log' | 'emit' | 'state'
|
|
31
|
+
|
|
32
|
+
export interface BaseEvent {
|
|
33
|
+
id?: string // Redis stream ID (auto-generated, not present for ingress events)
|
|
34
|
+
ts?: string // ISO timestamp (auto-generated, not present for ingress events)
|
|
35
|
+
type: EventType
|
|
36
|
+
runId: string // Flow run UUID
|
|
37
|
+
flowName: string // Flow definition name
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface StepEvent extends BaseEvent {
|
|
41
|
+
stepName: string
|
|
42
|
+
stepId: string
|
|
43
|
+
attempt: number
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface FlowStartEvent extends BaseEvent {
|
|
47
|
+
type: 'flow.start'
|
|
48
|
+
data?: {
|
|
49
|
+
input?: any
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface FlowCompletedEvent extends BaseEvent {
|
|
54
|
+
type: 'flow.completed'
|
|
55
|
+
data?: {
|
|
56
|
+
result?: any
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface FlowFailedEvent extends BaseEvent {
|
|
61
|
+
type: 'flow.failed'
|
|
62
|
+
data?: {
|
|
63
|
+
error?: string
|
|
64
|
+
stack?: string
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface StepStartedEvent extends StepEvent {
|
|
69
|
+
type: 'step.started'
|
|
70
|
+
data?: {
|
|
71
|
+
input?: any
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface StepCompletedEvent extends StepEvent {
|
|
76
|
+
type: 'step.completed'
|
|
77
|
+
data?: {
|
|
78
|
+
result?: any
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface StepFailedEvent extends StepEvent {
|
|
83
|
+
type: 'step.failed'
|
|
84
|
+
data?: {
|
|
85
|
+
error?: string
|
|
86
|
+
stack?: string
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface StepRetryEvent extends StepEvent {
|
|
91
|
+
type: 'step.retry'
|
|
92
|
+
data?: {
|
|
93
|
+
stepName: string
|
|
94
|
+
queue: string
|
|
95
|
+
error?: string
|
|
96
|
+
stack?: string
|
|
97
|
+
attempt: number
|
|
98
|
+
maxAttempts: number
|
|
99
|
+
nextAttempt: number
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface LogEvent extends StepEvent {
|
|
104
|
+
type: 'log'
|
|
105
|
+
data: {
|
|
106
|
+
level: 'debug' | 'info' | 'warn' | 'error'
|
|
107
|
+
message: string
|
|
108
|
+
[key: string]: any
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface EmitEvent extends StepEvent {
|
|
113
|
+
type: 'emit'
|
|
114
|
+
data: {
|
|
115
|
+
topic: string
|
|
116
|
+
payload: any
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface StateEvent extends StepEvent {
|
|
121
|
+
type: 'state'
|
|
122
|
+
data: {
|
|
123
|
+
operation: 'get' | 'set' | 'delete'
|
|
124
|
+
scope?: string
|
|
125
|
+
key: string
|
|
126
|
+
value?: any
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export type FlowEvent = FlowStartEvent | FlowCompletedEvent | FlowFailedEvent | StepStartedEvent | StepCompletedEvent | StepFailedEvent | StepRetryEvent | LogEvent | EmitEvent | StateEvent
|
|
131
|
+
|
|
132
|
+
export type EventRecord = FlowEvent
|
package/dist/types.d.mts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nvent",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Nuxt queue service based on Bullmq",
|
|
5
|
+
"repository": "DevJoghurt/nuxt-queue",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/types.d.mts",
|
|
11
|
+
"import": "./dist/module.mjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/module.mjs",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "yarn dev:prepare && nuxt-module-build build",
|
|
20
|
+
"dev": "nuxi dev playground",
|
|
21
|
+
"dev:build": "nuxi build playground",
|
|
22
|
+
"dev:preview": "nuxi preview playground",
|
|
23
|
+
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
24
|
+
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
|
|
25
|
+
"test": "vitest",
|
|
26
|
+
"lint": "eslint --ext .ts,.js,.mjs,.cjs,.vue .",
|
|
27
|
+
"cleanup": "rimraf dist*/ **/node_modules .nuxt* playground/.data",
|
|
28
|
+
"bumpp": "bumpp"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@babel/parser": "^7.28.5",
|
|
32
|
+
"@iconify-json/devicon": "^1.2.46",
|
|
33
|
+
"@iconify-json/heroicons": "1.2.3",
|
|
34
|
+
"@iconify-json/lucide": "^1.2.72",
|
|
35
|
+
"@nuxt/kit": "4.2.1",
|
|
36
|
+
"@vue-flow/background": "^1.3.2",
|
|
37
|
+
"@vue-flow/controls": "^1.1.3",
|
|
38
|
+
"@vue-flow/core": "^1.47.0",
|
|
39
|
+
"@vue-flow/minimap": "^1.5.4",
|
|
40
|
+
"bullmq": "^5.63.0",
|
|
41
|
+
"chokidar": "^4.0.3",
|
|
42
|
+
"defu": "^6.1.4",
|
|
43
|
+
"globby": "15.0.0",
|
|
44
|
+
"ioredis": "^5.8.2",
|
|
45
|
+
"json-editor-vue": "^0.18.1",
|
|
46
|
+
"magicast": "^0.5.1",
|
|
47
|
+
"mlly": "^1.8.0",
|
|
48
|
+
"node-ts": "8.0.8",
|
|
49
|
+
"nuxt": "4.2.1",
|
|
50
|
+
"pathe": "^2.0.3",
|
|
51
|
+
"perfect-debounce": "^2.0.0",
|
|
52
|
+
"pkg-types": "^2.3.0",
|
|
53
|
+
"semver": "^7.7.3",
|
|
54
|
+
"zod": "^4.1.12"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@nuxt/devtools": "^3.0.1",
|
|
58
|
+
"@nuxt/eslint-config": "^1.10.0",
|
|
59
|
+
"@nuxt/module-builder": "^1.0.2",
|
|
60
|
+
"@nuxt/schema": "4.2.1",
|
|
61
|
+
"@nuxt/test-utils": "^3.20.1",
|
|
62
|
+
"@nuxt/ui": "4.1.0",
|
|
63
|
+
"@types/node": "^24.10.0",
|
|
64
|
+
"bumpp": "10.3.1",
|
|
65
|
+
"changelogen": "^0.6.2",
|
|
66
|
+
"eslint": "^9.39.1",
|
|
67
|
+
"nuxi": "^3.30.0",
|
|
68
|
+
"nuxt-mcp": "0.2.6",
|
|
69
|
+
"rimraf": "^6.1.0",
|
|
70
|
+
"typescript": "latest",
|
|
71
|
+
"vitest": "^4.0.7",
|
|
72
|
+
"vue-tsc": "^3.1.3"
|
|
73
|
+
},
|
|
74
|
+
"packageManager": "yarn@4.10.3"
|
|
75
|
+
}
|