Using deprecated DirectStart interface.
Known pipe types:
glxGraphicsPipe
(all display modules loaded.)
CREATE
DONE
BEFORE
If I run the same code but with vanilla task, the exception is correctly reported :
Using deprecated DirectStart interface.
Known pipe types:
glxGraphicsPipe
(all display modules loaded.)
CREATE
DONE
BEFORE
Traceback (most recent call last):
File "tests/test_async_ex.py", line 12, in test
raise Exception()
Exception
:task(error): Exception occurred in PythonTask ex_test
Traceback (most recent call last):
File "tests/test_async_ex.py", line 24, in
base.run()
File "/usr/share/panda3d/direct/showbase/ShowBase.py", line 3319, in run
self.taskMgr.run()
File "/usr/share/panda3d/direct/task/Task.py", line 541, in run
self.step()
File "/usr/share/panda3d/direct/task/Task.py", line 495, in step
self.mgr.poll()
File "tests/test_async_ex.py", line 12, in test
raise Exception()
Exception
Thanks for testing! It’s getting weird again : with an official build of Panda3D the exception is raised, but with my own build of Panda3D, based on 1.10.8 but with double precision floats and a couple of cherry-picked bugfixes, the exception is not reported… Same behaviour on Linux and macOS, so it’s not a compiler issue this time.
(Also there are almost no notification dumped, even with spam level)
With asyncio, if a task is killed due to an exception, the other tasks in the loop keep running.
Come to think of it, this is probably what you do want to see in a log file if such a failure happens in a distributed game, so maybe we should just keep this one in in opt-4 level builds.
Yes, that was actually my implicit assumption, uncaught exception should always be reported. Otherwise, especially in a distributed app, part of the game could suddenly stop working without any indication that something when wrong and caused one of the tasks to be killed. And that would be a nightmare to troubleshoot.
Weirdly it seems that with latest Panda3D master, even though you fix is indeed present in PythonTask destructor, the exception is still not reported (and the task keep running).
The output is again (and the program never stops) :
Using deprecated DirectStart interface.
Known pipe types:
glxGraphicsPipe
(all display modules loaded.)
CREATE
DONE
BEFORE
I’ve got another strange occurrence, due to a mistake in my code, a worker task is raising an exception (It’s an AttributeError, but I don’t believe it matters). After a few failed execution of the worker, I suddenly got these line and the whole program ended :
:task(error): PythonTask ShapeObject.patch_task exception was never retrieved:
SystemError: PyEval_EvalFrameEx returned NULL without setting an error
:task(error): PythonTask ShapeObject.patch_task exception was never retrieved:
SystemError: PyEval_EvalFrameEx returned NULL without setting an error
(And it seems the traceback related to the exception is printed before the :task(error): )
With 1.10.9 the worker keeps crashing as expected but I never get the above error nor the program stops.
The actual Python version is 3.8.5 and NDEBUG is not defined (–optimize=3), the version is 1.11.0 (571946739ecb3c9140afa1e5a64da26b3b849a65)
Here is the log with notify-level-event spam and notify-level-task spam
:task(spam): Adding PythonTask eventManager with sort 0 to chain default with current_sort -2147483647
CREATE
:task(debug): Adding PythonTask ex_test
:event(debug): Throwing event TaskManager-addTask(PythonTask)
:task(spam): Adding PythonTask ex_test with sort 0 to chain default with current_sort -2147483647
DONE
:task(spam): Servicing PythonTask resetPrevTransform in MainThread Main
:task(spam): Done servicing PythonTask resetPrevTransform in MainThread Main
:task(spam): Servicing PythonTask dataLoop in MainThread Main
:task(spam): Done servicing PythonTask dataLoop in MainThread Main
:task(spam): Servicing PythonTask eventManager in MainThread Main
:task(spam): Done servicing PythonTask eventManager in MainThread Main
:task(spam): Servicing PythonTask ex_test in MainThread Main
BEFORE
:task(debug): PythonTask ex_test received exception from coroutine.
:task(spam): AsyncTaskManager TaskManager task chain default; 9 tasks: cleanup_task(PythonTask ex_test, 1, 1)
:event(debug): Throwing event TaskManager-removeTask(PythonTask)
:task(spam): Done servicing PythonTask ex_test in MainThread Main
:task(spam): Servicing PythonTask ivalLoop in MainThread Main
:task(spam): Done servicing PythonTask ivalLoop in MainThread Main
:task(spam): Servicing PythonTask collisionLoop in MainThread Main
:task(spam): Done servicing PythonTask collisionLoop in MainThread Main
:task(spam): Servicing PythonTask garbageCollectStates in MainThread Main
:task(spam): Done servicing PythonTask garbageCollectStates in MainThread Main
:task(spam): Servicing PythonTask igLoop in MainThread Main
:event(debug): Throwing event window-event(glxGraphicsWindow)
:event(spam): Throwing event NewFrame()
:task(spam): Done servicing PythonTask igLoop in MainThread Main
:task(spam): Servicing PythonTask audioLoop in MainThread Main
:task(spam): Done servicing PythonTask audioLoop in MainThread Main
:task(spam): AsyncTaskManager TaskManager task chain default; 8 tasks: next epoch
:task(spam): No more tasks on sleeping queue.
:task(spam): Servicing PythonTask resetPrevTransform in MainThread Main
:task(spam): Done servicing PythonTask resetPrevTransform in MainThread Main
:task(spam): Servicing PythonTask dataLoop in MainThread Main
:task(spam): Done servicing PythonTask dataLoop in MainThread Main
:task(spam): Servicing PythonTask eventManager in MainThread Main
:task(spam): Done servicing PythonTask eventManager in MainThread Main
And for comparison, the same log with Panda3D 1.10.9 :
:task(spam): Adding PythonTask eventManager with sort 0 to chain default with current_sort -2147483647
CREATE
:task(debug): Adding PythonTask ex_test
:event(debug): Throwing event TaskManager-addTask(PythonTask)
:task(spam): Adding PythonTask ex_test with sort 0 to chain default with current_sort -2147483647
DONE
:task(spam): Servicing PythonTask resetPrevTransform in MainThread Main
:task(spam): Done servicing PythonTask resetPrevTransform in MainThread Main
:task(spam): Servicing PythonTask dataLoop in MainThread Main
:task(spam): Done servicing PythonTask dataLoop in MainThread Main
:task(spam): Servicing PythonTask eventManager in MainThread Main
:task(spam): Done servicing PythonTask eventManager in MainThread Main
:task(spam): Servicing PythonTask ex_test in MainThread Main
BEFORE
:task(debug): PythonTask ex_test received Exception from coroutine.
:task(spam): AsyncTaskManager TaskManager task chain default; 9 tasks: cleanup_task(PythonTask ex_test, 1, 1)
:event(debug): Throwing event TaskManager-removeTask(PythonTask)
:task(spam): Done servicing PythonTask ex_test in MainThread Main
:task(spam): Servicing PythonTask ivalLoop in MainThread Main
:task(spam): Done servicing PythonTask ivalLoop in MainThread Main
:task(spam): Servicing PythonTask collisionLoop in MainThread Main
:task(spam): Done servicing PythonTask collisionLoop in MainThread Main
:task(spam): Servicing PythonTask garbageCollectStates in MainThread Main
:task(spam): Done servicing PythonTask garbageCollectStates in MainThread Main
:task(spam): Servicing PythonTask igLoop in MainThread Main
:event(debug): Throwing event window-event(glxGraphicsWindow)
:event(spam): Throwing event NewFrame()
:task(spam): Done servicing PythonTask igLoop in MainThread Main
:task(spam): Servicing PythonTask audioLoop in MainThread Main
:task(spam): Done servicing PythonTask audioLoop in MainThread Main
:task(spam): AsyncTaskManager TaskManager task chain default; 8 tasks: next epoch
:task(spam): No more tasks on sleeping queue.
:task(spam): Servicing PythonTask resetPrevTransform in MainThread Main
:task(spam): Done servicing PythonTask resetPrevTransform in MainThread Main
:task(spam): Servicing PythonTask dataLoop in MainThread Main
:task(spam): Done servicing PythonTask dataLoop in MainThread Main
:task(spam): Servicing PythonTask eventManager in MainThread Main
:task(error): PythonTask ex_test exception was never retrieved:
Traceback (most recent call last):
File "tests/test_async_ex.py", line 13, in test_async
raise Exception()
Exception
:task(spam): Done servicing PythonTask eventManager in MainThread Main
Thanks, it seems to fix the first issue in all the case.
Alas this one still occurs, but the condition to make it happens still eludes me, but I think I’m getting close to the actual scenario:
If I raise an exception at a given point in my code before I set some data that is needed by the parent task that spawned the task, in one dev-commit of my tree I get the SystemError: PyEval_EvalFrameEx returned NULL without setting an error, and if I switch to a later dev-commit (after some clean up of the task management), the SystemError does not appear, but also the manual exception does not appear either, only a follow-up exception is shown as the task did not complete its work and the data is not available.
On the other hand, if I raise an exception after setting the data that is needed by the parent task, I get as expected that exception in the log with the PythonTask ShapeObject.patch_task exception was never retrieved error.
So it seems the first exception is lost or hidden by the upper one. I’m trying to replicate this using a simple example, but I believe there is still one missing part that I need to reproduce the problem.