Refa: improve usability of Node.js/JavaScript code executor (#8979)

### What problem does this PR solve?

Improve usability of Node.js/JavaScript code executor.

### Type of change

- [x] Refactoring

---------

Co-authored-by: Kevin Hu <kevinhu.sh@gmail.com>
Co-authored-by: writinwaters <93570324+writinwaters@users.noreply.github.com>
This commit is contained in:
Yongteng Lei
2025-07-23 09:26:09 +08:00
committed by GitHub
parent f63ad6b725
commit c3b8d8b4ba
5 changed files with 75 additions and 13 deletions

View File

@@ -213,6 +213,42 @@ To add Node.js dependencies:
---
## Usage
### 🐍 A Python example
```python
def main(arg1: str, arg2: str) -> str:
return f"result: {arg1 + arg2}"
```
### 🟨 JavaScript examples
A simple sync function
```javascript
function main({arg1, arg2}) {
return arg1+arg2
}
```
Async funcion with aioxs
```javascript
const axios = require('axios');
async function main() {
try {
const response = await axios.get('https://github.com/infiniflow/ragflow');
return 'Body:' + response.data;
} catch (error) {
return 'Error:' + error.message;
}
}
```
---
## 📋 FAQ
### ❓Sandbox Not Working?

View File

@@ -15,24 +15,29 @@
#
import base64
from core.container import _CONTAINER_EXECUTION_SEMAPHORES
from core.logger import logger
from fastapi import Request
from models.enums import ResultStatus
from models.enums import ResultStatus, SupportLanguage
from models.schemas import CodeExecutionRequest, CodeExecutionResult
from services.execution import execute_code
from services.limiter import limiter
from services.security import analyze_code_security
from core.container import _CONTAINER_EXECUTION_SEMAPHORES
async def healthz_handler():
return {"status": "ok"}
@limiter.limit("5/second")
async def run_code_handler(req: CodeExecutionRequest, request: Request):
logger.info("🟢 Received /run request")
async with _CONTAINER_EXECUTION_SEMAPHORES[req.language]:
code = base64.b64decode(req.code_b64).decode("utf-8")
if req.language == SupportLanguage.NODEJS:
code += "\n\nmodule.exports = { main };"
req.code_b64 = base64.b64encode(code.encode("utf-8")).decode("utf-8")
is_safe, issues = analyze_code_security(code, language=req.language)
if not is_safe:
issue_details = "\n".join([f"Line {lineno}: {issue}" for issue, lineno in issues])

View File

@@ -21,3 +21,4 @@ router = APIRouter()
router.get("/healthz")(healthz_handler)
router.post("/run")(run_code_handler)

View File

@@ -26,7 +26,7 @@ from core.logger import logger
_CONTAINER_QUEUES: dict[SupportLanguage, Queue] = {}
_CONTAINER_LOCK: asyncio.Lock = asyncio.Lock()
_CONTAINER_EXECUTION_SEMAPHORES:dict[SupportLanguage,asyncio.Semaphore] = {}
_CONTAINER_EXECUTION_SEMAPHORES: dict[SupportLanguage, asyncio.Semaphore] = {}
async def init_containers(size: int) -> tuple[int, int]:

View File

@@ -82,20 +82,40 @@ const fs = require('fs');
const path = require('path');
const args = JSON.parse(process.argv[2]);
const mainPath = path.join(__dirname, 'main.js');
function isPromise(value) {
return Boolean(value && typeof value.then === 'function');
}
if (fs.existsSync(mainPath)) {
const { main } = require(mainPath);
const mod = require(mainPath);
const main = typeof mod === 'function' ? mod : mod.main;
if (typeof main !== 'function') {
console.error('Error: main is not a function');
process.exit(1);
}
if (typeof args === 'object' && args !== null) {
main(args).then(result => {
try {
const result = main(args);
if (isPromise(result)) {
result.then(output => {
if (output !== null) {
console.log(output);
}
}).catch(err => {
console.error('Error in async main function:', err);
});
} else {
if (result !== null) {
console.log(result);
}
}).catch(err => {
console.error('Error in main function:', err);
});
}
} catch (err) {
console.error('Error when executing main:', err);
}
} else {
console.error('Error: args is not a valid object:', args);
}