-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to define timeouts #112
Comments
After a lot of fiddeling around, I seem to not get it work in any way. What follows is the most intuitive way I'd envision it to work. However, that doesn't work, because it seems that by the time The main Python thread is blocked by the long-running and blocking JavaScript process. I.e. the script is only looping through the tasks once the script finished. Do you have any idea whether this is solvable or whether changes to the source of STPyV8 must be made? import asyncio
import STPyV8
async def run_js(custom_js_code: str, timeout_ms: int):
engine_storage = { "engine": None }
async def timeout_task():
print("Timeout task started")
await asyncio.sleep(timeout_ms / 1000)
print("Timeout task completed")
def script_task():
print("Script task started")
with STPyV8.JSIsolate():
with STPyV8.JSContext():
engine_storage["engine"] = STPyV8.JSEngine()
script = engine_storage["engine"].compile(custom_js_code)
result = script.run()
del engine_storage["engine"]
print("Script task completed")
return result
timeout_task_future = asyncio.create_task(timeout_task())
script_task_future = asyncio.create_task(asyncio.to_thread(script_task))
tasks = [timeout_task_future, script_task_future]
done, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
# Get result from the first completed task
for task in done:
if task.exception():
print(f"Task ended with exception: {task.exception()}")
else:
if (task == timeout_task_future):
# Terminate all isolate threads if timeout was reached first
engine_storage["engine"].terminateAllThreads()
del engine_storage["engine"]
elif task == script_task_future:
# Handle script output
print(f"Task result {task.result()}")
custom_js = """
// sleep for 5 seconds
var start = Date.now();
while(Date.now() - start < 5000);
"""
timeout = 1000
async def main():
await run_js(custom_js, timeout)
asyncio.run(main()) |
AFAIK the only reliable way to do that would be to spawn a watchdog thread which invokes v8::Isolate::TerminateExecution from that thread on timeout. Moreover it must be a thread as it's not safe to call from a signal handler. I am quite busy at the moment but I will try to take a look at it and to figure out if a feasible way to do that through the STPyV8 API exists. Thanks! |
First of all, thank you for this work.
Is there an official way to define a timeout of the JavaScript running in
.eval()
? I want to prevent malicious code to run for longer than a specific amount of time.I dug through the tests and source code. The only way I see it done is to
CEngine::TerminateAllThreads
if the task takes too long.Thanks
The text was updated successfully, but these errors were encountered: