jpype-project / jpype

JPype is cross language bridge to allow Python programs full access to Java class libraries.
http://www.jpype.org
Apache License 2.0
1.12k stars 183 forks source link

JPype and Gunicorn worker; thread not attached #1185

Closed phwhite-coh closed 6 months ago

phwhite-coh commented 7 months ago

Hello, I've got a gunicorn flask app and I am experimenting with different worker models for gunicorn.

Things seem to mainly work using sync workers (--worker-class=sync), but I do seem to be having some random hangs in JayDeBeApi, so I was trying the "gthread" mode instead (--worker-class=gthread). Here, I am able to use JPype on the main thread, but the threads that process the requests have issues.

isJVMStarted() and isThreadAttachedToJVM() always return false and attachThreadToJVM() never returns.

Any suggestions on how to debug this? Or general suggestions on using JPype with Gunicorn?

Thanks!

phwhite-coh commented 7 months ago

Correction: isJVMStarted() returns True from the worker thread, but isThreadAttachedToJVM() returns False, and attachThreadToJVM() never returns.

Thrameos commented 7 months ago

I am not quite sure about what gunicorn is doing. If it is doing spawn or fork then you may have issues as Java VM does not survive that process and thus it will not work. In general, you should never need to attach a thread manually as it is done automatically when you call Java. However given your worker is not connecting then something larger is going on. If you are forking then try switching to spawn and starting the JVM on the worker. There has been similar issues for celery which does process based workers. Unfortunately this limitation is baked into the JVM and is not something this project can address.

phwhite-coh commented 6 months ago

Ok, I figured out the issue. Though I had switched gunicorn to using threads and one worker process (-k gthread -w 1) instead of multiple workers processes (-k sync -w 12), I still was passing the --preload flag, which causes app initialization to happen on a different process than the worker process. So even though I had configured for only a single worker process, this was in addition to the master gunicorn process. And during init I was starting the JVM. So I was able to fix this by removing --preload, to ensure the app was truly only one process.

Thrameos commented 6 months ago

Seems consistent with the usual fork issue. Thanks for the report back. I will close this issue for now.