Skip to content
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

FIX Check if future is done before trying to set a result on it #4837

Merged
merged 4 commits into from
Jun 6, 2024

Conversation

hoodmane
Copy link
Member

@hoodmane hoodmane commented Jun 4, 2024

Otherwise, future raises invalid state error. Question: should we try to avoid getting to the point where we call this in the first place??

cc @CNSeniorious000 this fixes the invalid state errors on pyodide/micropip#111

Description

@hoodmane hoodmane force-pushed the invalid-state-future branch 2 times, most recently from b71af4e to 9b8f5cc Compare June 4, 2024 16:51
@CNSeniorious000
Copy link
Member

So where we called this

@hoodmane hoodmane force-pushed the invalid-state-future branch from 27f2129 to 337517a Compare June 4, 2024 17:15
@hoodmane
Copy link
Member Author

hoodmane commented Jun 4, 2024

It's a bit complicated, I haven't sifted through the full control flow. Here's the full traceback, but it's hard to find anything micropip related there. Presumably we cancelled a Future and then it later got sent a result from the browser event loop. We need to throw it away if we're already done.

Traceback
$PyObject_CallOneArg @ VM137 pyodide.asm.wasm-02a1db6a:1
$create_promise_handles_result_helper @ VM137 pyodide.asm.wasm-02a1db6a:1
onFulfilled @ VM129 pyodide.asm.js:1938
processTicksAndRejections @ node:internal/process/task_queues:95
Promise.then (async)
JsvObject_CallMethod @ VM129 pyodide.asm.js:2369
$JsvObject_CallMethodId @ VM137 pyodide.asm.wasm-02a1db6a:1
$wrap_promise @ VM137 pyodide.asm.wasm-02a1db6a:1
$Js2Py_func_default_call_result @ VM137 pyodide.asm.wasm-02a1db6a:1
$Js2PyConverter_convert @ VM137 pyodide.asm.wasm-02a1db6a:1
$JsMethod_Vectorcall_impl @ VM137 pyodide.asm.wasm-02a1db6a:1
$JsMethod_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_EvalFrameDefault @ VM137 pyodide.asm.wasm-02a1db6a:1
$gen_send_ex2 @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyGen_am_send @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyIter_Send @ VM137 pyodide.asm.wasm-02a1db6a:1
$task_step_impl @ VM137 pyodide.asm.wasm-02a1db6a:1
$task_step @ VM137 pyodide.asm.wasm-02a1db6a:1
$TaskStepMethWrapper_call @ VM137 pyodide.asm.wasm-02a1db6a:1
_PyEM_TrampolineCall_JS @ VM129 pyodide.asm.js:7851
$_PyObject_MakeTpCall @ VM137 pyodide.asm.wasm-02a1db6a:1
$context_run @ VM137 pyodide.asm.wasm-02a1db6a:1
$cfunction_vectorcall_FASTCALL_KEYWORDS @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyVectorcall_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyObject_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_EvalFrameDefault @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_Vector @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyFunction_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$_pyproxy_apply @ VM137 pyodide.asm.wasm-02a1db6a:1
callPyObjectKwargs @ VM129 pyodide.asm.js:4265
Module.callPyObjectMaybePromising @ VM129 pyodide.asm.js:4325
wrapper @ VM129 pyodide.asm.js:1859
processImmediate @ node:internal/timers:478
callbackTrampoline @ node:internal/async_hooks:130
Immediate (async)
init @ node:internal/inspector_async_hook:25
emitInitNative @ node:internal/async_hooks:202
emitInitScript @ node:internal/async_hooks:505
initAsyncResource @ node:internal/timers:160
Immediate @ node:internal/timers:624
setImmediate @ node:timers:306
scheduleCallbackImmediate @ VM129 pyodide.asm.js:6443
scheduleCallback @ VM129 pyodide.asm.js:6453
JsvFunction_CallBound @ VM129 pyodide.asm.js:2447
$JsMethod_Vectorcall_impl @ VM137 pyodide.asm.wasm-02a1db6a:1
$JsMethod_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_EvalFrameDefault @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_Vector @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyFunction_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$method_vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyVectorcall_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyObject_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_EvalFrameDefault @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_Vector @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyFunction_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_VectorcallMethod @ VM137 pyodide.asm.wasm-02a1db6a:1
$task_call_step_soon @ VM137 pyodide.asm.wasm-02a1db6a:1
$_asyncio_Task___init__ @ VM137 pyodide.asm.wasm-02a1db6a:1
$type_call @ VM137 pyodide.asm.wasm-02a1db6a:1
_PyEM_TrampolineCall_JS @ VM129 pyodide.asm.js:7851
$_PyObject_MakeTpCall @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_EvalFrameDefault @ VM137 pyodide.asm.wasm-02a1db6a:1
$gen_send_ex2 @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyGen_am_send @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyIter_Send @ VM137 pyodide.asm.wasm-02a1db6a:1
$task_step_impl @ VM137 pyodide.asm.wasm-02a1db6a:1
$task_step @ VM137 pyodide.asm.wasm-02a1db6a:1
$task_wakeup @ VM137 pyodide.asm.wasm-02a1db6a:1
_PyEM_TrampolineCall_JS @ VM129 pyodide.asm.js:7851
$cfunction_vectorcall_O @ VM137 pyodide.asm.wasm-02a1db6a:1
$context_run @ VM137 pyodide.asm.wasm-02a1db6a:1
$cfunction_vectorcall_FASTCALL_KEYWORDS @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyVectorcall_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyObject_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_EvalFrameDefault @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_Vector @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyFunction_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$_pyproxy_apply @ VM137 pyodide.asm.wasm-02a1db6a:1
callPyObjectKwargs @ VM129 pyodide.asm.js:4265
Module.callPyObjectMaybePromising @ VM129 pyodide.asm.js:4325
wrapper @ VM129 pyodide.asm.js:1859
processImmediate @ node:internal/timers:478
callbackTrampoline @ node:internal/async_hooks:130
Immediate (async)
init @ node:internal/inspector_async_hook:25
emitInitNative @ node:internal/async_hooks:202
emitInitScript @ node:internal/async_hooks:505
initAsyncResource @ node:internal/timers:160
Immediate @ node:internal/timers:624
setImmediate @ node:timers:306
scheduleCallbackImmediate @ VM129 pyodide.asm.js:6443
scheduleCallback @ VM129 pyodide.asm.js:6453
JsvFunction_CallBound @ VM129 pyodide.asm.js:2447
$JsMethod_Vectorcall_impl @ VM137 pyodide.asm.wasm-02a1db6a:1
$JsMethod_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_EvalFrameDefault @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_Vector @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyFunction_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$method_vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyVectorcall_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyObject_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Call @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_EvalFrameDefault @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_Vector @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyFunction_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_VectorcallMethod @ VM137 pyodide.asm.wasm-02a1db6a:1
$future_schedule_callbacks @ VM137 pyodide.asm.wasm-02a1db6a:1
$_asyncio_Future_set_result @ VM137 pyodide.asm.wasm-02a1db6a:1
$method_vectorcall_FASTCALL_KEYWORDS_METHOD @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_EvalFrameDefault @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyEval_Vector @ VM137 pyodide.asm.wasm-02a1db6a:1
$_PyFunction_Vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$method_vectorcall @ VM137 pyodide.asm.wasm-02a1db6a:1
$PyObject_CallOneArg @ VM137 pyodide.asm.wasm-02a1db6a:1
$create_promise_handles_result_helper @ VM137 pyodide.asm.wasm-02a1db6a:1
onFulfilled @ VM129 pyodide.asm.js:1938
processTicksAndRejections @ node:internal/process/task_queues:95

@CNSeniorious000
Copy link
Member

CNSeniorious000 commented Jun 4, 2024

Presumably we cancelled a Future and then it later got sent a result from the browser event loop.

It's probably fetch, because it is native JavaScript async function which don't check the cancel state when scheduled.

from js import fetch

async def f():
    while True:
        await fetch("/")

from asyncio import *

f = ensure_future(f())

f.cancel()

Running this and you will see a similar asyncio.exceptions.InvalidStateError: invalid state warning in the devtools console.

@hoodmane
Copy link
Member Author

hoodmane commented Jun 4, 2024

Thanks for the test case.

src/core/jsproxy.c Outdated Show resolved Hide resolved
@hoodmane hoodmane force-pushed the invalid-state-future branch from c9629d3 to 35fb788 Compare June 5, 2024 14:19
@hoodmane hoodmane added this to the 0.26.1 milestone Jun 5, 2024
@hoodmane hoodmane force-pushed the invalid-state-future branch from d3ea1b4 to 05b839e Compare June 6, 2024 02:17
Otherwise, future raises invalid state error.
Question: should we try to avoid getting to the point where we call this in the
first place??
@hoodmane hoodmane force-pushed the invalid-state-future branch from 1f7c86d to 18398b7 Compare June 6, 2024 02:22
@hoodmane hoodmane merged commit 43cce6e into pyodide:main Jun 6, 2024
35 of 37 checks passed
@hoodmane hoodmane deleted the invalid-state-future branch June 6, 2024 04:56
hoodmane added a commit to hoodmane/pyodide that referenced this pull request Jun 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants