feat: bash exec and queue exported as API
This commit is contained in:
parent
aa6df63025
commit
b5979cf25b
38
apps/demo-nextjs-app-router/app/api/script/route.tsx
Normal file
38
apps/demo-nextjs-app-router/app/api/script/route.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import {
|
||||
executeScript,
|
||||
getQueueStats,
|
||||
} from "../../../services/bashExecService";
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { scriptPath, args } = body;
|
||||
|
||||
if (!scriptPath) {
|
||||
return NextResponse.json(
|
||||
{ error: "Script path is required" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const result = await executeScript({
|
||||
scriptPath,
|
||||
args,
|
||||
});
|
||||
|
||||
return NextResponse.json(result);
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoint to get queue statistics
|
||||
export async function GET() {
|
||||
try {
|
||||
const stats = getQueueStats();
|
||||
return NextResponse.json(stats);
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
79
apps/demo-nextjs-app-router/services/bashExecService.ts
Normal file
79
apps/demo-nextjs-app-router/services/bashExecService.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import { execa } from "execa";
|
||||
import PQueue from "p-queue";
|
||||
|
||||
// Configure the queue with a concurrency limit
|
||||
const scriptQueue = new PQueue({ concurrency: 5 });
|
||||
|
||||
export type ScriptParams = {
|
||||
scriptPath: string;
|
||||
args?: string[];
|
||||
onProgress?: (data: string) => void;
|
||||
};
|
||||
|
||||
export type ScriptResult = {
|
||||
success: boolean;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes a bash script with queue management
|
||||
*/
|
||||
export async function executeScript(
|
||||
params: ScriptParams,
|
||||
): Promise<ScriptResult> {
|
||||
// Add the script execution to the queue
|
||||
const result = await scriptQueue.add(async () => {
|
||||
try {
|
||||
// Execute the bash script
|
||||
const { stdout, stderr } = await execa(
|
||||
"bash",
|
||||
[params.scriptPath, ...(params.args || [])],
|
||||
{
|
||||
buffer: true, // Changed to true to ensure we get the complete output
|
||||
},
|
||||
);
|
||||
|
||||
// If onProgress is provided, we can use it to stream script output
|
||||
if (params.onProgress && stdout) {
|
||||
params.onProgress(stdout.toString());
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
stdout: stdout ? stdout.toString() : "",
|
||||
stderr: stderr ? stderr.toString() : "",
|
||||
};
|
||||
} catch (error: any) {
|
||||
// Handle script execution errors
|
||||
return {
|
||||
success: false,
|
||||
stdout: error.stdout ? error.stdout.toString() : "",
|
||||
stderr: error.stderr ? error.stderr.toString() : "",
|
||||
error: error.message || "Failed to execute script",
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return result as ScriptResult;
|
||||
}
|
||||
|
||||
// Get current queue size and pending tasks
|
||||
export function getQueueStats() {
|
||||
return {
|
||||
size: scriptQueue.size,
|
||||
pending: scriptQueue.pending,
|
||||
isPaused: scriptQueue.isPaused,
|
||||
};
|
||||
}
|
||||
|
||||
// Pause the queue (no further tasks will be executed until resumed)
|
||||
export function pauseQueue() {
|
||||
scriptQueue.pause();
|
||||
}
|
||||
|
||||
// Resume the queue
|
||||
export function resumeQueue() {
|
||||
scriptQueue.start();
|
||||
}
|
||||
32
package-lock.json
generated
32
package-lock.json
generated
@ -36,6 +36,7 @@
|
||||
"next": "^14.2.5",
|
||||
"open": "^10.0.3",
|
||||
"ora": "^8.0.1",
|
||||
"p-queue": "^8.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"regenerator-runtime": "0.13.7",
|
||||
@ -26910,6 +26911,26 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-queue": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.0.tgz",
|
||||
"integrity": "sha512-mxLDbbGIBEXTJL0zEx8JIylaj3xQ7Z/7eEVjcF9fJX4DBiH9oqe+oahYnlKKxm0Ci9TlWTyhSHgygxMxjIB2jw==",
|
||||
"dependencies": {
|
||||
"eventemitter3": "^5.0.1",
|
||||
"p-timeout": "^6.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-queue/node_modules/eventemitter3": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
||||
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
|
||||
},
|
||||
"node_modules/p-reduce": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz",
|
||||
@ -26932,6 +26953,17 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/p-timeout": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz",
|
||||
"integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==",
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
|
||||
@ -56,6 +56,7 @@
|
||||
"next": "^14.2.5",
|
||||
"open": "^10.0.3",
|
||||
"ora": "^8.0.1",
|
||||
"p-queue": "^8.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"regenerator-runtime": "0.13.7",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user