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

python3.11 + Celery + Redis + Gevent -> "returned NULL without setting an exception" #1985

Closed
cunla opened this issue Aug 10, 2023 · 61 comments

Comments

@cunla
Copy link

cunla commented Aug 10, 2023

  • gevent version: 23.7.0 (pypi)
  • Python version: 3.11
  • Operating System: linux

Description:

What are you trying to get done, what has happened, what went wrong, and what did you expect?

Working with celery worker on a container, with redis broker, a failure is happening (see stacktrace below).

Others have experienced the same issue on different circumstances. (See more examples here ). There is also an issue opened on celery.

[2023-08-04 11:10:28,806] [ERROR] [MainThread] [consumer.py:248 - perform_pending_operations()] Pending callback raised: SystemError('<built-in method switch of gevent._gevent_cgreenlet.Greenlet object at 0x7fcdb37de700> returned NULL without setting an exception')
Traceback (most recent call last):
  File "/home/.local/lib/python3.11/site-packages/celery/worker/consumer/consumer.py", line 246, in perform_pending_operations
    self._pending_operations.pop()()
  File "/home/.local/lib/python3.11/site-packages/vine/promises.py", line 160, in __call__
    return self.throw()
           ^^^^^^^^^^^^
  File "/home/.local/lib/python3.11/site-packages/vine/promises.py", line 157, in __call__
    retval = fun(*final_args, **final_kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/.local/lib/python3.11/site-packages/kombu/message.py", line 131, in ack_log_error
    self.ack(multiple=multiple)
  File "/home/.local/lib/python3.11/site-packages/kombu/message.py", line 126, in ack
    self.channel.basic_ack(self.delivery_tag, multiple=multiple)
  File "/home/.local/lib/python3.11/site-packages/kombu/transport/virtual/base.py", line 670, in basic_ack
    self.qos.ack(delivery_tag)
  File "/home/.local/lib/python3.11/site-packages/kombu/transport/redis.py", line 379, in ack
    self._remove_from_indices(delivery_tag).execute()
  File "/home/.local/lib/python3.11/site-packages/redis/client.py", line 2120, in execute
    return conn.retry.call_with_retry(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/.local/lib/python3.11/site-packages/redis/retry.py", line 46, in call_with_retry
    return do()
           ^^^^
  File "/home/.local/lib/python3.11/site-packages/redis/client.py", line 2121, in <lambda>
    lambda: execute(conn, stack, raise_on_error),
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/.local/lib/python3.11/site-packages/redis/client.py", line 1975, in _execute_transaction
    self.parse_response(connection, "_")
  File "/home/.local/lib/python3.11/site-packages/redis/client.py", line 2060, in parse_response
    result = Redis.parse_response(self, connection, command_name, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/.local/lib/python3.11/site-packages/redis/client.py", line 1286, in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/.local/lib/python3.11/site-packages/redis/connection.py", line 882, in read_response
    response = self._parser.read_response(disable_decoding=disable_decoding)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/.local/lib/python3.11/site-packages/redis/connection.py", line 349, in read_response
    result = self._read_response(disable_decoding=disable_decoding)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/.local/lib/python3.11/site-packages/redis/connection.py", line 359, in _read_response
    raw = self._buffer.readline()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/.local/lib/python3.11/site-packages/redis/connection.py", line 262, in readline
    self._read_from_socket()
  File "/home/.local/lib/python3.11/site-packages/redis/connection.py", line 212, in _read_from_socket
    data = self._sock.recv(socket_read_size)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/.local/lib/python3.11/site-packages/gevent/_socketcommon.py", line 666, in recv
    self._wait(self._read_event)
  File "src/gevent/_hub_primitives.py", line 317, in gevent._gevent_c_hub_primitives.wait_on_socket
  File "src/gevent/_hub_primitives.py", line 322, in gevent._gevent_c_hub_primitives.wait_on_socket
  File "src/gevent/_hub_primitives.py", line 304, in gevent._gevent_c_hub_primitives._primitive_wait
  File "src/gevent/_hub_primitives.py", line 46, in gevent._gevent_c_hub_primitives.WaitOperationsGreenlet.wait
  File "src/gevent/_hub_primitives.py", line 46, in gevent._gevent_c_hub_primitives.WaitOperationsGreenlet.wait
  File "src/gevent/_hub_primitives.py", line 55, in gevent._gevent_c_hub_primitives.WaitOperationsGreenlet.wait
  File "src/gevent/_waiter.py", line 154, in gevent._gevent_c_waiter.Waiter.get
  File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_greenlet_primitives.py", line 65, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_gevent_c_greenlet_primitives.pxd", line 35, in gevent._gevent_c_greenlet_primitives._greenlet_switch
  File "src/gevent/_waiter.py", line 122, in gevent._gevent_c_waiter.Waiter.switch
SystemError: <built-in method switch of gevent._gevent_cgreenlet.Greenlet object at 0x7fcdb37de700> returned NULL without setting an exception```
@dwjorgeb
Copy link

Having the same issue on Huey + redis + gevent since upgrading to py3.11.

Someone else (here) had the same error and is not using redis. That seems to point to gevent as culprit.

@jamadden
Copy link
Member

What greenlet version does everyone have installed?

@dwjorgeb
Copy link

What greenlet version does everyone have installed?

gevent==23.7.0
greenlet==2.0.2

@jamadden
Copy link
Member

Because the gevent Greenlet class is compiled from Python code into an extension using Cython, we have two possibilities (assuming we rule out C compiler issues):

  • A Cython bug
  • A greenlet bug

We can rule out the first one by running gevent without its C extensions: set the PURE_PYTHON=1 environment variable before importing anything from gevent. If that makes the problem go away, then it's an issue with Cython.

We could also test with greenlet 3 and see if that makes a difference. It's a drop-in replacement for greenlet 2, so you can just pip install it. My instinct suggests it's a greenlet issue.

That's about all I can suggest until I have a reproducible test case. (I don't know when I will have time to dive into the greenlet code and go speculatively hunt bugs.)

@zyv
Copy link

zyv commented Aug 11, 2023

We tried it already with Greenlet 3, but the problem still occurs. So just switching to Greenlet 3 unfortunately will not work.

@zyv
Copy link

zyv commented Aug 11, 2023

Another note: there was a CPython issue of similar sort, and it was closed as miscompilation by GCC4 was blamed - python/cpython#94825.

@hoefling
Copy link

I started getting this error after upgrading to Python 3.11 (celery==5.3.1, gevent==23.7.0, greenlet==2.0.2, but also reproducible with 3.0.0a1), but a bit different stacktrace:

Exception ignored in:
<function AsyncResult.__del__ at 0x7f07761cb2e0>
Traceback (most recent call last):
  File "/venv/lib/python3.11/site-packages/celery/result.py", line 392, in __del__
self.backend.remove_pending_result(self)
  File "/venv/lib/python3.11/site-packages/celery/backends/asynchronous.py", line 208, in remove_pending_result
self.on_result_fulfilled(result)
  File "/venv/lib/python3.11/site-packages/celery/backends/asynchronous.py", line 216, in on_result_fulfilled
self.result_consumer.cancel_for(result.id)
  File "/venv/lib/python3.11/site-packages/celery/backends/redis.py", line 176, in cancel_for
self._pubsub.unsubscribe(key)
  File "/venv/lib/python3.11/site-packages/redis/client.py", line 1659, in unsubscribe
return self.execute_command("UNSUBSCRIBE", *args)
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/redis/client.py", line 1469, in execute_command
self.connection = self.connection_pool.get_connection(
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/redis/connection.py", line 1457, in get_connection
connection.connect()
  File "/venv/lib/python3.11/site-packages/redis/connection.py", line 699, in connect
sock = self.retry.call_with_retry(
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/redis/retry.py", line 46, in call_with_retry
return do()
       ^^^^
  File "/venv/lib/python3.11/site-packages/redis/connection.py", line 700, in <lambda>
lambda: self._connect(), lambda error: self.disconnect(error)
        ^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/redis/connection.py", line 970, in _connect
for res in socket.getaddrinfo(
           ^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/gevent/_socketcommon.py", line 247, in getaddrinfo
addrlist = get_hub().resolver.getaddrinfo(host, port, family, type, proto, flags)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/gevent/resolver/thread.py", line 63, in getaddrinfo
return self.pool.apply(_socket.getaddrinfo, args, kwargs)
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/gevent/pool.py", line 161, in apply
return self.spawn(func, *args, **kwds).get()
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "src/gevent/event.py", line 329, in gevent._gevent_cevent.AsyncResult.get
  File "src/gevent/event.py", line 356, in gevent._gevent_cevent.AsyncResult.get
  File "src/gevent/_abstract_linkable.py", line 487, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core
  File "src/gevent/_abstract_linkable.py", line 490, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core
  File "src/gevent/_abstract_linkable.py", line 442, in gevent._gevent_c_abstract_linkable.AbstractLinkable._AbstractLinkable__wait_to_be_notified
  File "src/gevent/_abstract_linkable.py", line 455, in gevent._gevent_c_abstract_linkable.AbstractLinkable._switch_to_hub
gevent.exceptions.InvalidSwitchError:
Invalid switch into AsyncResult.wait(): None
Traceback (most recent call last):
  File "src/gevent/_waiter.py", line 122, in gevent._gevent_c_waiter.Waiter.switch
SystemError: <built-in method switch of gevent._gevent_cgreenlet.Greenlet object at 0x7f076ee52340> returned NULL without setting an exception
<built-in method switch of gevent._gevent_cgreenlet.Greenlet object at 0x7f076ee52340> failed with SystemError
Unrecoverable error: SystemError('<built-in method switch of gevent._gevent_cgreenlet.Greenlet object at 0x7f076ee52340> returned NULL without setting an exception')
Traceback (most recent call last):
  File "/venv/lib/python3.11/site-packages/celery/worker/worker.py", line 203, in start
    self.blueprint.start(self)
  File "/venv/lib/python3.11/site-packages/celery/bootsteps.py", line 116, in start
    step.start(parent)
  File "/venv/lib/python3.11/site-packages/celery/bootsteps.py", line 365, in start
    return self.obj.start()
           ^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/celery/worker/consumer/consumer.py", line 332, in start
    blueprint.start(self)
  File "/venv/lib/python3.11/site-packages/celery/bootsteps.py", line 116, in start
    step.start(parent)
  File "/venv/lib/python3.11/site-packages/celery/worker/consumer/consumer.py", line 628, in start
    c.loop(*c.loop_args())
  File "/venv/lib/python3.11/site-packages/celery/worker/loops.py", line 130, in synloop
    connection.drain_events(timeout=2.0)
  File "/venv/lib/python3.11/site-packages/kombu/connection.py", line 316, in drain_events
    return self.transport.drain_events(self.connection, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/kombu/transport/virtual/base.py", line 971, in drain_events
    get(self._deliver, timeout=timeout)
  File "/venv/lib/python3.11/site-packages/kombu/transport/redis.py", line 581, in get
    events = self.poller.poll(timeout)
             ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/kombu/utils/eventio.py", line 279, in poll
    read, write, error = _selectf(
                         ^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/gevent/select.py", line 199, in select
    return result.select(rlist, wlist, timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/gevent/select.py", line 136, in select
    event.wait(timeout=timeout)
  File "src/gevent/event.py", line 163, in gevent._gevent_cevent.Event.wait
  File "src/gevent/_abstract_linkable.py", line 521, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait
  File "src/gevent/_abstract_linkable.py", line 487, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core
  File "src/gevent/_abstract_linkable.py", line 490, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core
  File "src/gevent/_abstract_linkable.py", line 442, in gevent._gevent_c_abstract_linkable.AbstractLinkable._AbstractLinkable__wait_to_be_notified
  File "src/gevent/_abstract_linkable.py", line 451, in gevent._gevent_c_abstract_linkable.AbstractLinkable._switch_to_hub
  File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_greenlet_primitives.py", line 65, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_gevent_c_greenlet_primitives.pxd", line 35, in gevent._gevent_c_greenlet_primitives._greenlet_switch
  File "src/gevent/_waiter.py", line 122, in gevent._gevent_c_waiter.Waiter.switch
SystemError: <built-in method switch of gevent._gevent_cgreenlet.Greenlet object at 0x7f076ee52340> returned NULL without setting an exception
Error on stopping Pool: This operation would block forever
	Hub: <Hub '' at 0x7f07738710d0 epoll default pending=0 ref=0 fileno=4 resolver=<gevent.resolver.thread.Resolver at 0x7f076f7a02d0 pool=<ThreadPool at 0x7f076f6bbae0 tasks=0 size=1 maxsize=10 hub=<Hub at 0x7f07738710d0 thread_ident=0x7f0778df5b48>>> threadpool=<ThreadPool at 0x7f076f6bbae0 tasks=0 size=1 maxsize=10 hub=<Hub at 0x7f07738710d0 thread_ident=0x7f0778df5b48>> thread_ident=0x7f0778df5b48>
	Handles:
[]
Traceback (most recent call last):
  File "/venv/lib/python3.11/site-packages/celery/bootsteps.py", line 148, in send_all
    fun(parent, *args)
  File "/venv/lib/python3.11/site-packages/celery/bootsteps.py", line 369, in stop
    return self.obj.stop()
           ^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/celery/concurrency/base.py", line 120, in stop
    self.on_stop()
  File "/venv/lib/python3.11/site-packages/celery/concurrency/gevent.py", line 101, in on_stop
    self._pool.join()
  File "/venv/lib/python3.11/site-packages/gevent/pool.py", line 430, in join
    result = self._empty_event.wait(timeout=timeout)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "src/gevent/event.py", line 163, in gevent._gevent_cevent.Event.wait
  File "src/gevent/_abstract_linkable.py", line 521, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait
  File "src/gevent/_abstract_linkable.py", line 487, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core
  File "src/gevent/_abstract_linkable.py", line 490, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core
  File "src/gevent/_abstract_linkable.py", line 442, in gevent._gevent_c_abstract_linkable.AbstractLinkable._AbstractLinkable__wait_to_be_notified
  File "src/gevent/_abstract_linkable.py", line 451, in gevent._gevent_c_abstract_linkable.AbstractLinkable._switch_to_hub
  File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_greenlet_primitives.py", line 65, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_gevent_c_greenlet_primitives.pxd", line 35, in gevent._gevent_c_greenlet_primitives._greenlet_switch
gevent.exceptions.LoopExit: This operation would block forever
	Hub: <Hub '' at 0x7f07738710d0 epoll default pending=0 ref=0 fileno=4 resolver=<gevent.resolver.thread.Resolver at 0x7f076f7a02d0 pool=<ThreadPool at 0x7f076f6bbae0 tasks=0 size=1 maxsize=10 hub=<Hub at 0x7f07738710d0 thread_ident=0x7f0778df5b48>>> threadpool=<ThreadPool at 0x7f076f6bbae0 tasks=0 size=1 maxsize=10 hub=<Hub at 0x7f07738710d0 thread_ident=0x7f0778df5b48>> thread_ident=0x7f0778df5b48>
	Handles:
[]

@hoefling
Copy link

I'll try to come up with a repro if nobody beats me to it

@SmallPineApp1e
Copy link

SmallPineApp1e commented Aug 24, 2023

here is my using library version:

gevent==22.10.2
greenlet==2.0.2

when I use Python3.11 running in Docker, it will be hit this SystemError in random time. and This error cannot be occurred stably, it confused me a long time.

Because I want to upgrade my python version from 3.7 to 3.11, and I must upgrade the greenlet and gevent version, but they can not run stably in 3.11.

here is the stacktrace:

Traceback (most recent call last):
  File "./start.py", line 44, in <module>
  File "./base/server.py", line 144, in start
  File "src/gevent/greenlet.py", line 1065, in gevent._gevent_cgreenlet.joinall
  File "src/gevent/greenlet.py", line 1075, in gevent._gevent_cgreenlet.joinall
  File "src/gevent/_hub_primitives.py", line 250, in gevent._gevent_c_hub_primitives.wait_on_objects
  File "src/gevent/_hub_primitives.py", line 287, in gevent._gevent_c_hub_primitives.wait_on_objects
  File "src/gevent/_hub_primitives.py", line 185, in gevent._gevent_c_hub_primitives._WaitIterator.__next__
  File "src/gevent/_hub_primitives.py", line 176, in gevent._gevent_c_hub_primitives._WaitIterator.__next__
  File "src/gevent/_waiter.py", line 195, in gevent._gevent_c_waiter.MultipleWaiter.get
  File "src/gevent/_waiter.py", line 154, in gevent._gevent_c_waiter.Waiter.get
  File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_greenlet_primitives.py", line 65, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_gevent_c_greenlet_primitives.pxd", line 35, in gevent._gevent_c_greenlet_primitives._greenlet_switch
  File "src/gevent/_waiter.py", line 122, in gevent._gevent_c_waiter.Waiter.switch
SystemError: <built-in method switch of gevent._gevent_cgreenlet.Greenlet object at 0x7f05aeb12520> returned NULL without setting an exception

hop someone can help to solve this or provide some ideas I can try, thanks! :(

@SmallPineApp1e
Copy link

SmallPineApp1e commented Aug 24, 2023

I found an stable reoccurred exception, When the requests library raise this exception in one coroutine, the program will be shutdown abnormally and occur the SystemError above.

  • requests version:requests==2.31.0
  • urllib3 version:urllib3==2.0.2

Here is the stacktrace:

Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/requests/api.py", line 73, in get
    return request("get", url, params=params, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/api.py", line 59, in request
    return session.request(method=method, url=url, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/adapters.py", line 486, in send
    resp = conn.urlopen(
           ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/connectionpool.py", line 790, in urlopen
    response = self._make_request(
               ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/connectionpool.py", line 536, in _make_request
    response = conn.getresponse()
              ^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/connection.py", line 454, in getresponse
    httplib_response = super().getresponse()
                       ^^^^^^^
RuntimeError: super(): __class__ cell not found

@pipozzz
Copy link

pipozzz commented Aug 25, 2023

Same issue with python 3.11 gevent 23.7.0 and redis 5.0.0

@amks1
Copy link

amks1 commented Aug 27, 2023

Same issue, but on Flask with uwsgi and unrelated to redis.
Here's what I got in glitchtip:

SystemError:<built-in method switch of gevent._gevent_cgreenlet.Greenlet object at 0x7efe7c27ba60> returned NULL without setting an exception
File "src/gevent/greenlet.py", line 833, in gevent._gevent_cgreenlet.Greenlet.join
File "src/gevent/greenlet.py", line 859, in gevent._gevent_cgreenlet.Greenlet.join
File "src/gevent/greenlet.py", line 848, in gevent._gevent_cgreenlet.Greenlet.join
File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_greenlet_primitives.py", line 65, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_gevent_c_greenlet_primitives.pxd", line 35, in gevent._gevent_c_greenlet_primitives._greenlet_switch
File "src/gevent/_waiter.py", line 122, in gevent._gevent_c_waiter.Waiter.switch

gevent version: 23.7.0
greenlet version: 2.0.2
Python version: 3.11.2

@kkszysiu
Copy link

Hey guys,

Readding my comment from #1987 as that one was closed, but may be helpful for some people

Hey guys, seems like it started to happen for me as well after I upgraded urllib3 to 1.26.16, after I downgraded it back to urllib3[secure]==1.26.12 the issue is no longer happening.

Thanks!

@cristifalcas
Copy link

Still happening to me after downgrading urllib3

@jamadden
Copy link
Member

jamadden commented Sep 1, 2023

I haven't been able to come up with a reproducer for this, despite my best efforts. But I've found and fixed some other issues that might be related. gevent 23.8.0 and greenlet 3.0rc1 have those changes. They are building and releasing now. When possible, please give those versions a try.

Pay close attention to the standard error output. There were some places in the C code that could silently swallow exceptions --- they have to swallow exceptions by design, because it's not safe to raise them (much the same way that exceptions from __del__ aren't raised, just printed). More of those should result in writing a traceback to standard error, so you might see some new errors being printed.

And of course, if anyone has a standalone reproducer, please share it.

@danmilon
Copy link

danmilon commented Sep 4, 2023

I think the gevent version with related fixes is 23.9.0?

@dmbaggett
Copy link

dmbaggett commented Sep 6, 2023

Still seeing this on macOS with these versions:

greenlet==3.0.0rc1
gevent==23.9.0.post1
requests==2.31.0
urllib3==1.26.16

The exact exception I'm seeing is

  File "src/gevent/_waiter.py", line 122, in gevent._gevent_c_waiter.Waiter.switch
  greenlet returned NULL with no exception set

For testing purposes I patched greenlet.cpp to raise an exception in green_switch when it detects a NULL return value with !PyErr_Ocurred():

  PyErr_Format(PyExc_SystemError, "greenlet returned NULL with no exception set");

This at least allows the main thread to keep running so I could see what the last thing that ran was. With some greenlet tracing I added enabled I see this as the last greenlet to run:

2023-09-06 13:16:51.594791z P:16790 G:0x2fc2cd120 [server] [GREENLET] switching out of <Greenlet at 0x2fc2cd120: _unshorten_one_url_in_batch('https://uX.ct.sendgrid.net/ls/click?upn=5jG, ParseResult(scheme='https', netloc='uX.ct.se, {}, unshorten_all_urls=False)> [throw] [duration: 0.0000] [waiting: 0.4210 running: 0.0107 total: 0.4317] [pending greenlets = 0, active greenlets = 51]

stack trace for above greenlet:

2023-09-06 13:16:51.594791z P:16790 G:0x2fc2cd120 [server] [GREENLET]   
^-- gevent/_socketcommon.py:640,
 gevent/_socketcommon.py:590
 util/connection.py:85, 
urllib3/connection.py:174,
urllib3/connection.py:363, 
urllib3/connectionpool.py:1053, 
urllib3/connectionpool.py:403, 
urllib3/connectionpool.py:714, 
requests/adapters.py:486, 
requests/sessions.py:703, 
requests/sessions.py:266, 
url_tools/unshorten.py:251, 
url_tools/unshorten.py:147

When it happens to me, the last greenlet always seems to be in urllib3, trying to connect.

@jamadden
Copy link
Member

jamadden commented Sep 6, 2023

@dmbaggett Since you have the ability to compile and run greenlet with a scenario that crashes, can you please compile and run greenlet (and ideally gevent) with assertions enabled? e.g., something like CFLAGS="-UNDEBUG" pip install .?

This enables numerous assertions that may result in a crash closer to the source of the problem. The core file produced by such a crash could be extremely helpful to examine (ulimit -c unlimited), if you are able to share it. At least the C backtrace could be helpful.

@dmbaggett
Copy link

Seeing this:

Assertion failed: (rhs), function operator<<=, file greenlet.cpp, line 867

But I can't seem to get a core dump. I have

% ulimit -c
unlimited

But maybe there is some SIP issue with core dumps in recent macOS versions? No clue.

Anyway, I'm going to try running under lldb so I can at least give you a C stack trace.

@dmbaggett
Copy link

dmbaggett commented Sep 6, 2023

    frame #0: 0x000000019ca08764 libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x000000019ca3fc28 libsystem_pthread.dylib`pthread_kill + 288
    frame #2: 0x000000019c94dae8 libsystem_c.dylib`abort + 180
    frame #3: 0x000000019c94ce44 libsystem_c.dylib`__assert_rtn + 272
  * frame #4: 0x000000010068bcd0 _greenlet.cpython-311-darwin.so`operator<<=(lhs=<unavailable>, rhs=<unavailable>) at greenlet.cpp:0:1
    frame #5: 0x000000010068ec64 _greenlet.cpython-311-darwin.so`greenlet::Greenlet::g_switch_finish(this=0x0000000104bec3f0, err=<unavailable>) at greenlet.cpp:1575:16
    frame #6: 0x000000010068a554 _greenlet.cpython-311-darwin.so`greenlet::UserGreenlet::g_switch(this=<unavailable>) at greenlet.cpp:1093:41
    frame #7: 0x000000010068c598 _greenlet.cpython-311-darwin.so`green_switch(self=0x00000002cb0bff60, args=(None,), kwargs=<unavailable>) at greenlet.cpp:2202:57
    frame #8: 0x0000000100096e44 python`cfunction_call(func='0x2cb0bbe20', args=<unavailable>, kwargs=<unavailable>) at methodobject.c:542:18
    frame #9: 0x0000000101fe0d70 _gevent_c_waiter.cpython-311-darwin.so`__Pyx_PyObject_FastCallDict [inlined] __Pyx_PyObject_Call(func='0x2cb0bbe20', arg=(None,), kw='0x00000000') at _waiter.c:7439:14
    frame #10: 0x0000000101fe0d44 _gevent_c_waiter.cpython-311-darwin.so`__Pyx_PyObject_FastCallDict [inlined] __Pyx_PyObject_FastCall_fallback(func='0x2cb0bbe20', args=<unavailable>, nargs=1, kwargs='0x00000000') at PyObjectFastCall_impl_f56785463fe72f9b5217660053d8014bb459e229.h:11:14
    frame #11: 0x0000000101fe0d00 _gevent_c_waiter.cpython-311-darwin.so`__Pyx_PyObject_FastCallDict(func='0x2cb0bbe20', args=<unavailable>, _nargs=<unavailable>, kwargs='No value') at PyObjectFastCall_impl_f56785463fe72f9b5217660053d8014bb459e229.h:79:12
    frame #12: 0x0000000101fe2a6c _gevent_c_waiter.cpython-311-darwin.so`__pyx_pw_6gevent_16_gevent_c_waiter_6Waiter_11switch at _waiter.c:3894:23
    frame #13: 0x0000000101fe2930 _gevent_c_waiter.cpython-311-darwin.so`__pyx_pw_6gevent_16_gevent_c_waiter_6Waiter_11switch(__pyx_v_self='0x2cafa61b0', __pyx_v_value=<unavailable>) at _waiter.c:3718:13
    frame #14: 0x000000010004e8e0 python`method_vectorcall [inlined] _PyObject_VectorcallTstate(tstate=0x00000001003d6d88, callable='0x101ee1e50', args='0x16fdfd540', nargsf=<unavailable>, kwnames='0x00000000') at pycore_call.h:92:11
    frame #15: 0x000000010004e8b8 python`method_vectorcall(method=<unavailable>, args='0x2cae8b0b8', nargsf=<unavailable>, kwnames='0x00000000') at classobject.c:89:18
    frame #16: 0x0000000101f043d4 corecext.cpython-311-darwin.so`gevent_call(loop=0x0000000104b25ee0, cb=0x00000002cb01f9c0) at callbacks.c:182:14
    frame #17: 0x0000000101f3d114 corecext.cpython-311-darwin.so`__pyx_f_6gevent_5libev_8corecext_4loop__run_callbacks(__pyx_v_self=0x0000000104b25ee0) at corecext.c:8591:7
    frame #18: 0x0000000101f09458 corecext.cpython-311-darwin.so`gevent_loop_run_callbacks(__pyx_v_loop=<unavailable>) at corecext.c:21050:15
    frame #19: 0x0000000101f048f4 corecext.cpython-311-darwin.so`gevent_run_callbacks(_loop=<unavailable>, watcher=<unavailable>, revents=<unavailable>) at callbacks.c:225:14
    frame #20: 0x0000000101f06090 corecext.cpython-311-darwin.so`ev_invoke_pending(loop=0x0000000101f50488) at ev.c:3770:11
    frame #21: 0x0000000101f065f4 corecext.cpython-311-darwin.so`ev_run(loop=0x0000000101f50488, flags=0) at ev.c:4063:11
    frame #22: 0x0000000101f1663c corecext.cpython-311-darwin.so`__pyx_pw_6gevent_5libev_8corecext_4loop_15run at corecext.c:10117:9
    frame #23: 0x0000000101f165d8 corecext.cpython-311-darwin.so`__pyx_pw_6gevent_5libev_8corecext_4loop_15run(__pyx_v_self=<unavailable>, __pyx_args=<unavailable>, __pyx_nargs=<unavailable>, __pyx_kwds=<unavailable>) at corecext.c:10067:13
    frame #24: 0x000000010004c1e4 python`PyObject_Vectorcall [inlined] _PyObject_VectorcallTstate(tstate=0x00000001003d6d88, callable='0x101b4df20', args=<unavailable>, nargsf=<unavailable>, kwnames=<unavailable>) at pycore_call.h:92:11
    frame #25: 0x000000010004c1bc python`PyObject_Vectorcall(callable='0x101b4df20', args=<unavailable>, nargsf=<unavailable>, kwnames=<unavailable>) at call.c:299:12
    frame #26: 0x000000010012d0d8 python`_PyEval_EvalFrameDefault(tstate=<unavailable>, frame=0x0000000100668020, throwflag=<unavailable>) at ceval.c:0
    frame #27: 0x00000001001246e0 python`_PyEval_Vector [inlined] _PyEval_EvalFrame(tstate=0x00000001003d6d88, frame=0x0000000100668020, throwflag=0) at pycore_ceval.h:73:16
    frame #28: 0x00000001001246d0 python`_PyEval_Vector(tstate=0x00000001003d6d88, func=<unavailable>, locals=<unavailable>, args=<unavailable>, argcount=<unavailable>, kwnames=<unavailable>) at ceval.c:6439:24
    frame #29: 0x000000010004e85c python`method_vectorcall [inlined] _PyObject_VectorcallTstate(tstate=0x00000001003d6d88, callable='0x101dee480', args='0x16fdfda68', nargsf=1, kwnames='0x00000000') at pycore_call.h:92:11
    frame #30: 0x000000010004e830 python`method_vectorcall(method=<unavailable>, args='python`_PyRuntime + 58984', nargsf=<unavailable>, kwnames='0x00000000') at classobject.c:67:20
    frame #31: 0x0000000100687a30 _greenlet.cpython-311-darwin.so`greenlet::UserGreenlet::inner_bootstrap(this=0x0000000104bec3f0, origin_greenlet=0x000000016fdfdc60, _run=0x000000016fdfdbf8) at greenlet.cpp:1325:45
    frame #32: 0x0000000100687024 _greenlet.cpython-311-darwin.so`greenlet::UserGreenlet::g_initialstub(this=0x0000000104bec3f0, mark=<unavailable>) at greenlet.cpp:1225:15
    frame #33: 0x000000010068a438 _greenlet.cpython-311-darwin.so`greenlet::UserGreenlet::g_switch(this=0x0000000104bec3f0) at greenlet.cpp:1058:36
    frame #34: 0x0000000102fa1b64 _gevent_c_abstract_linkable.cpython-311-darwin.so`__pyx_f_6gevent_27_gevent_c_abstract_linkable_16AbstractLinkable__wait_core(__pyx_v_self=0x000000017d3d7880, __pyx_v_timeout=<unavailable>, __pyx_optional_args=<unavailable>) at _abstract_linkable.c:8597:27
    frame #35: 0x0000000102fa2394 _gevent_c_abstract_linkable.cpython-311-darwin.so`__pyx_f_6gevent_27_gevent_c_abstract_linkable_16AbstractLinkable__wait(__pyx_v_self=0x000000017d3d7880, __pyx_optional_args=<unavailable>) at _abstract_linkable.c:9051:15
    frame #36: 0x0000000102fcda68 _gevent_cevent.cpython-311-darwin.so`__pyx_pw_6gevent_14_gevent_cevent_5Event_15wait [inlined] __pyx_pf_6gevent_14_gevent_cevent_5Event_14wait(__pyx_v_self=0x000000017d3d7880, __pyx_v_timeout=<unavailable>) at event.c:4210:15
    frame #37: 0x0000000102fcda4c _gevent_cevent.cpython-311-darwin.so`__pyx_pw_6gevent_14_gevent_cevent_5Event_15wait(__pyx_v_self='0x17d3d7880', __pyx_args=<unavailable>, __pyx_nargs=0, __pyx_kwds=<unavailable>) at event.c:4177:13
    frame #38: 0x000000010004c1e4 python`PyObject_Vectorcall [inlined] _PyObject_VectorcallTstate(tstate=0x00000001003d6d88, callable='0x102bcecf0', args=<unavailable>, nargsf=<unavailable>, kwnames=<unavailable>) at pycore_call.h:92:11
    frame #39: 0x000000010004c1bc python`PyObject_Vectorcall(callable='0x102bcecf0', args=<unavailable>, nargsf=<unavailable>, kwnames=<unavailable>) at call.c:299:12
    frame #40: 0x000000010012d0d8 python`_PyEval_EvalFrameDefault(tstate=<unavailable>, frame=0x00000001005c40e8, throwflag=<unavailable>) at ceval.c:0
    frame #41: 0x00000001001245b0 python`PyEval_EvalCode [inlined] _PyEval_EvalFrame(tstate=0x00000001003d6d88, frame=0x00000001005c4020, throwflag=0) at pycore_ceval.h:73:16
    frame #42: 0x00000001001245a0 python`PyEval_EvalCode [inlined] _PyEval_Vector(tstate=0x00000001003d6d88, func=0x0000000101aa65c0, locals=0x00000001019f5ac0, args='0x00000000', argcount=0, kwnames='0x00000000') at ceval.c:6439:24
    frame #43: 0x00000001001245a0 python`PyEval_EvalCode(co='0x10221d000', globals=0x00000001019f5ac0, locals=0x00000001019f5ac0) at ceval.c:1154:21
    frame #44: 0x0000000100177670 python`run_mod [inlined] run_eval_code_obj(tstate=0x00000001003d6d88, co=0x000000010221d000, globals=0x00000001019f5ac0, locals=0x00000001019f5ac0) at pythonrun.c:1712:9
    frame #45: 0x000000010017763c python`run_mod(mod=0x00000001021ab9c8, filename='/Users/dmb/inky-main/ink-drop/addinserver/inky_analysis_server.py', globals=0x00000001019f5ac0, locals=0x00000001019f5ac0, flags=<unavailable>, arena=<unavailable>) at pythonrun.c:1733:19
    frame #46: 0x0000000100175b64 python`_PyRun_SimpleFileObject [inlined] pyrun_file(fp=0x00000001f7aca820, filename='/Users/dmb/inky-main/ink-drop/addinserver/inky_analysis_server.py', start=257, globals=0x00000001019f5ac0, locals=0x00000001019f5ac0, closeit=1, flags=0x000000016fdfe268) at pythonrun.c:1628:15
    frame #47: 0x0000000100175b00 python`_PyRun_SimpleFileObject(fp=0x00000001f7aca820, filename='/Users/dmb/inky-main/ink-drop/addinserver/inky_analysis_server.py', closeit=1, flags=0x000000016fdfe268) at pythonrun.c:440:13
    frame #48: 0x00000001001755ec python`_PyRun_AnyFileObject(fp=0x00000001f7aca820, filename='/Users/dmb/inky-main/ink-drop/addinserver/inky_analysis_server.py', closeit=1, flags=0x000000016fdfe268) at pythonrun.c:79:15
    frame #49: 0x00000001001948b0 python`Py_RunMain [inlined] pymain_run_file_obj(program_name='python', filename='/Users/dmb/inky-main/ink-drop/addinserver/inky_analysis_server.py', skip_source_first_line=0) at main.c:360:15
    frame #50: 0x0000000100194874 python`Py_RunMain [inlined] pymain_run_file(config=0x00000001003bcdd0) at main.c:379:15
    frame #51: 0x0000000100194850 python`Py_RunMain [inlined] pymain_run_python(exitcode=0x000000016fdfe23c) at main.c:601:21
    frame #52: 0x0000000100194524 python`Py_RunMain at main.c:680:5
    frame #53: 0x0000000100194c60 python`pymain_main(args=0x000000016fdfe5a0) at main.c:710:12
    frame #54: 0x0000000100194d00 python`Py_BytesMain(argc=<unavailable>, argv=<unavailable>) at main.c:734:12
    frame #55: 0x000000019c6e7f28 dyld`start + 2236

@dmbaggett
Copy link

I have a core file. How should I get it to you?

@jamadden
Copy link
Member

jamadden commented Sep 6, 2023

@dmbaggett That is so helpful, thank you!

Assertion failed: (rhs), function operator<<=, file greenlet.cpp, line 867
frame #4: 0x000000010068bcd0 _greenlet.cpython-311-darwin.sooperator<<=(lhs=, rhs=) at greenlet.cpp:0:1 frame #5: 0x000000010068ec64 _greenlet.cpython-311-darwin.sogreenlet::Greenlet::g_switch_finish(this=0x0000000104bec3f0, err=<unavailable>) at greenlet.cpp:1575:16
frame #6: 0x000000010068a554 _greenlet.cpython-311-darwin.sogreenlet::UserGreenlet::g_switch(this=) at greenlet.cpp:1093:41 frame #7: 0x000000010068c598 _greenlet.cpython-311-darwin.sogreen_switch(self=0x00000002cb0bff60, args=(None,), kwargs=<unavailable>) at greenlet.cpp:2202:57

That...is...wow. Totally unexpected. I have no idea how that could happen (hence the assert!) but obviously it is. That gives me a good clue to start chasing down.

I have a core file. How should I get it to you?

I appreciate that! Presumably it's very large? My macOS core files come out around 1.1GB gzip compressed, which makes them annoying to move around. Because you were able to get the C stack trace and the assertion failure, the core file is a bit less important, and I'm not sure what exactly I would look for in it right now. Unless you already have a way that's very convenient and easy for you to share large files, let me go ahead and see what I can do with the information you've already provided before we worry about moving cores around.

Thank you again!

@dmbaggett
Copy link

dmbaggett commented Sep 6, 2023

@jamadden Yes, the core file is huge. I can put it up via a link but I'd rather share it privately. Does github support direct messages so I can send you a URL? Just LMK if you want it. Thanks for investigating; I have to admit that I find the gevent code very hard to understand and debug.

@jamadden
Copy link
Member

jamadden commented Sep 6, 2023

Does github support direct messages so I can send you a URL?

Not to my knowledge, but you could DM me at twitter (@ossmkitty) or send me an email.

@klarose
Copy link

klarose commented Sep 6, 2023

Could always use gpg or something to encrypt the link with jamadden's public key

@dmbaggett
Copy link

dmbaggett commented Sep 6, 2023

Trying to get my web server to actually serve this 1.4GB file... I could FedEx you a CD [Edit: DVD]? (I kid.)

@dmbaggett
Copy link

Also very weird; Python printed this:

XXX lineno: 350, opcode: 150

...which seems to come from this section of ceval.c:

        opcode = _Py_OPCODE(*next_instr);
        fprintf(stderr, "XXX lineno: %d, opcode: %d\n",
                _PyInterpreterFrame_GetLine(frame),  opcode);
        _PyErr_SetString(tstate, PyExc_SystemError, "unknown opcode");
        goto error;

Unfortunately I cannot tell when or from where that was printed -- i.e., what code had the unknown opcode.

Possibly related to python/cpython#97002 which was closed with the comment "I finally found the root issue, which is that a poorly-timed GC collection just before tracing the resumption of a generator can cause two duplicate frame objects to be created, which corrupts the VM's internal state in all sorts of fun ways."

@jamadden
Copy link
Member

jamadden commented Sep 7, 2023

My working theory also involves tracing and/or garbage collection happening at inopportune times 😄

I have been able to contrive scenarios that result in triggering either the assertion you saw or different assertions. I don't know if they're close enough to the actual scenario you're hitting to do any good, but I have been able to fix the scenarios I've found so far.

This greenlet build has a few rounds of fixes in it. When it finishes, GHA will show the artifacts for it, which will include installable greenlet wheels for macOS and Linux systems. If you're able to test those in your situation and see what happens, that would be awesome. (The macOS wheels won't be built with debug assertions enabled, unfortunately, so it would be even better if you could build the same commit with debugging enabled.)

I'm continuing to trace through the code looking for other ways unexpected situations can arise.

@jamadden
Copy link
Member

I have no idea if it's related, but as soon as I updated greenlet to v3.0rc2, I got this which I've never encountered before:
SystemError:you can call uwsgi api function only from the main callable

As far as I can tell, that should be unrelated --- or at the most, there's been a lurking bug in the WSGI application that this happened to expose (this time). That's something that uWSGI checks internally when you call an API. Because uWSGI works on an "implicit" request basis, each API call checks a thread-local (I think greenlet local when running uWSGI with gevent) variable to see if there is a current request being handled. If there isn't, uWSGI raises this error. So this code is getting run from outside the scope of a uWSGI request (hence there's nothing to close).

The changes in rc2 boil down to two simple classes of changes:

  • The first and largest class of change was additional testing, especially of error cases or corner cases, and making sure those error handlers do something useful. That shouldn't have resulted in any observable changes (unless you were hitting one of the error cases and relying on the old error handling; but (a) most of those errors should have been vanishingly unlikely; and (b) most of the error handling was broken or incomplete, so who knows if the process would have even kept going or crashed).
  • The second class of change is more subtle, and is in about three or four lines scattered around. This group of changes very slightly altered the exact ordering of when a garbage collection might kick in (if one is going to be started at all), and hence exactly when any __del__ or weakref callbacks might get called in the event of cyclic garbage. I think most places result in having an opportunity for GC slightly sooner, but some might slightly defer an opportunity for GC.

If that second case, garbage collection happening slightly differently, is what's affecting the WSGI application, I think I would consider that a bug in the WSGI application. Just as in normal Python, garbage collection can occur at arbitrary times and in arbitrary threads or arbitrary greenlets. So trying to close a request inside GC isn't safe, with or without gevent.

If that's what's happening, the uWSGI log ought to show "[BUG] current_wsgi_req NOT FOUND !!!".

@dmbaggett
Copy link

Wow @jamadden, nice work! I will test with the new code. What git branch should I use now to build from source?

@jamadden
Copy link
Member

There's a 3.0rc2 tag, or you can use the main branch. (The changes in the main branch since rc2 are just mechanical refactoring, moving stuff around. No semantic changes.)

@amks1
Copy link

amks1 commented Sep 11, 2023

I have no idea if it's related, but as soon as I updated greenlet to v3.0rc2, I got this which I've never encountered before:
SystemError:you can call uwsgi api function only from the main callable

As far as I can tell, that should be unrelated

Sorry about that and yes, you're right. I reverted greenlet back to 2.0.2 and the problem still occurs. It must be that some other library got updated when I rebuilt my container. Serves me right for not freezing the versions in requirements. 😒

@dmbaggett
Copy link

Reporting back: I've been testing with 3.0rc2 for a few days now and have not seen any issues.

@jamadden
Copy link
Member

Thank you, that's very good to hear. While running stress tests, I did find one more crasher that I fixed in greenlet 3.0rc3. It occurred at process termination time under very specific circumstances; if you were going to see it, you probably would have by now (assuming you've run one than one process over the last few days 😄 ).

So I think we can consider this fixed now. The most recent release of gevent (23.9.1) bumps the required greenlet dep for CPython 3.11 and 3.12, so installing it will automatically Do The Right Thing to avoid the issue. (I know, I know, and I don't like releasing final versions that have a dependency on an RC either, but I'm still hoping to be able to figure out the tracing thing under Python 3.12 before Python 3.12 is officially released. Either way, greenlet 3.0 will go final when Python 3.12 does, and I'll release a new version of gevent that depends on it ASAP.)

Thank you, everyone, for your patience and assistance with this issue.

@dmbaggett
Copy link

Amazing work -- thanks @jamadden!

@hugo-reveni
Copy link

hugo-reveni commented Sep 14, 2023

Thanks a lot @jamadden for the tireless research! Congratulations!

@dmbaggett
Copy link

dmbaggett commented Sep 15, 2023

@jamadden I think we still have an issue. :(

When I run my load test for a long time my code is getting into a mode where the server is accepting queries but seems to not be able actually do anything. I'll need to to a lot more investigating to see where it's getting stuck, but one very suspicious aspect here is that I run a garbage collection greenlet that does a gc.collect() every 60 seconds, and the hangs correlate to gc.collect having just run.

I'm running greenlet with -O0 and -UNDEBUG but I'm not seeing any assertions or really anything unusual getting printed.

Unfortunately it takes a long time for this to randomly happen so it might be more productive to try to force this to happen with one of your test harneses. Try running a separate greenlet that collects and maybe we'll get lucky and you'll reproduce it locally.

I'll keep researching here.

@dmbaggett
Copy link

Update on this: I have been running for around 20 hours with PURE_PYTHON=1 and it hasn't locked up. I've also been able to reproduce it a few more times with gevent running without PURE_PYTHON=1 and I no longer believe it's necessarily correlated with the GC greenlet running a collection.

@dmbaggett
Copy link

dmbaggett commented Sep 18, 2023

I finally managed to get a stack trace showing where the greenlet get stuck:

2023-09-17 23:00:15.531974z P:7821 G:0x38f65ab60 [analysis-server] [GREENLET] ^-- gevent/thread.py:112, ldclient/rwlock.py:20, ldclient/init.py:109, addinserver/feature_flags.py:95, addinserver/analysis.py:4372, addinserver/analysis.py:3794, addinserver/inky_analysis_server.py:3865, addinserver/inky_analysis_server.py:3096, addinserver/inky_analysis_server.py:2701, web/application.py:495, web/application.py:517, web/application.py:271, web/application.py:280, web/application.py:278, web/application.py:703, web/application.py:278, web/application.py:278, web/application.py:686, web/application.py:278, web/application.py:278, web/application.py:686, web/application.py:278, web/application.py:278, web/application.py:703, web/application.py:278, web/application.py:278, web/application.py:686, web/application.py:278, web/application.py:290, web/application.py:319, gevent/pywsgi.py:1053, gevent/pywsgi.py:1107, gevent/pywsgi.py:804, gevent/pywsgi.py:574, gevent/pywsgi.py:1700, gevent/server.py:210, gevent/baseserver.py:34

It's getting stuck waiting for a lock in the launch darkly client. Here is the relevant code:

def get():
"""Returns the shared SDK client instance, using the current global configuration.

To use the SDK as a singleton, first make sure you have called :func:`ldclient.set_sdk_key()` or
:func:`ldclient.set_config()` at startup time. Then ``get()`` will return the same shared
:class:`ldclient.client.LDClient` instance each time. The client will be initialized if it has
not been already.

If you need to create multiple client instances with different configurations, instead of this
singleton approach you can call the :class:`ldclient.client.LDClient` constructor directly instead.

:rtype: ldclient.client.LDClient
"""
global __config
global __client
global __lock
try:
    __lock.rlock()
    if __client:
        return __client
finally:
    __lock.runlock()

try:
    __lock.lock()
    if not __client:
        log.info("Initializing LaunchDarkly Client " + version.VERSION)
        __client = LDClient(config=__config, start_wait=start_wait)
    return __client
finally:
    __lock.unlock()

I'm using a rather old version of launchdarkly-server-sdk (6.10.2) but it's a pure python package so it still seems problematic that its locking code can hang a greenlet. The underlying implementation is:

    self._read_ready = threading.Condition(threading.Lock())

But on second thought I guess this code implies there is no timeout, so the Condition will block forever if the lock is never released -- so if some other greenlet dies without releasing the lock this would explain the behavior we're seeing here. (Why is the finally clause not running, though?)

@jamadden I would say ignore this until I can debug further and determine it's actually a greenlet/gevent issue.

@dmbaggett
Copy link

Hmm, I noticed this, which seems very odd:

redis.exceptions.TimeoutError: Timeout reading from socket

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/dmb/install/osx/3.11/lib/python3.11/site-packages/redis/connection.py", line 559, in connect
sock = self._connect()
^^^^^^^^^^^^^^^
File "/Users/dmb/install/osx/3.11/lib/python3.11/site-packages/redis/connection.py", line 615, in _connect
raise err
File "/Users/dmb/install/osx/3.11/lib/python3.11/site-packages/redis/connection.py", line 603, in _connect
sock.connect(socket_address)
File "/Users/dmb/install/osx/3.11/lib/python3.11/site-packages/gevent/_socketcommon.py", line 590, in connect
self._internal_connect(address)
File "/Users/dmb/install/osx/3.11/lib/python3.11/site-packages/gevent/_socketcommon.py", line 640, in _internal_connect
self._wait(self._write_event)
File "src/gevent/_hub_primitives.py", line 317, in gevent._gevent_c_hub_primitives.wait_on_socket
File "src/gevent/_hub_primitives.py", line 322, in gevent._gevent_c_hub_primitives.wait_on_socket
File "src/gevent/_hub_primitives.py", line 313, in gevent._gevent_c_hub_primitives._primitive_wait
File "src/gevent/_hub_primitives.py", line 314, in gevent._gevent_c_hub_primitives._primitive_wait
File "src/gevent/_hub_primitives.py", line 46, in gevent._gevent_c_hub_primitives.WaitOperationsGreenlet.wait
File "src/gevent/_hub_primitives.py", line 46, in gevent._gevent_c_hub_primitives.WaitOperationsGreenlet.wait
File "src/gevent/_hub_primitives.py", line 55, in gevent._gevent_c_hub_primitives.WaitOperationsGreenlet.wait
File "src/gevent/_waiter.py", line 154, in gevent._gevent_c_waiter.Waiter.get
File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_greenlet_primitives.py", line 65, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_gevent_c_greenlet_primitives.pxd", line 35, in gevent._gevent_c_greenlet_primitives._greenlet_switch
TimeoutError: timed out

greenlet_switch geting a TimeoutError?

@jamadden
Copy link
Member

That's normal. Uncaught exceptions are thrown to parent greenlets as a result of switch().

@dmbaggett
Copy link

Further update: same result with the latest launch darkly SDK. However, when I force the use of _AtomicSemaphore in gevent/lock.py the problem seems to go away. Of course, this could be luck and timing. I will keep my tests running.

@dmbaggett
Copy link

dmbaggett commented Sep 19, 2023

I'm starting to believe this is a real gevent issue. I've had two tests running since yesterday morning on two different machines and have not seen any hangs. The only change I've made is

+if PURE_PYTHON or True:

in src/gevent/lock.py

I'll keep these load tests running for the rest of the week.

@dmbaggett
Copy link

dmbaggett commented Sep 22, 2023

I have not seen any hangs since applying the one-line patch above so I think this a real gevent issue. I wonder if something has changed with Cython since a comment in lock.py says that it's relying on Cython's not releasing the GIL.

@kkszysiu
Copy link

So what's up with this issue now?
Should it be patched in gevent?

@dmbaggett
Copy link

FWIW I'm seeing different behavior under Python 3.12 than I did under Python 3.11 so I'm really not sure what to think at this point. Seems like we need to do some more testing.

@dmbaggett
Copy link

dmbaggett commented Sep 29, 2023

To elaborate: I've upgraded our stack to 3.12 and haven't seen any problems under gevent 23.9.1 and greenlet 3.0.0rc3 under load testing. Seems like a bad interaction between gevent and something in 3.11. (I have not tried 3.10 or 3.9, to be fair with the latest greenlet/gevent.)

@zyv
Copy link

zyv commented Sep 29, 2023

So, interestingly we are also affected by segfaults due to garbage collector invalidating objects between threads in Python 3.11 in Sentry Profiler: getsentry/sentry-python#2386 . I wonder if this stuff has the same nature as the problems that we suffered with Gevent - it would great if this is all fixed in Python 3.12.

@dmbaggett
Copy link

@zyv After all of @jamadden 's fixes I did not actually see crashes even under 3.11 -- the remaining symptom I saw over long-term testing was very specific I/O-bound greenlets just getting stuck forever. Not seeing anything of the sort under 3.12 and I've been wanting to move to 3.12 anyway given that it supports Python stack traces in linux perf.

@dmbaggett
Copy link

I suppose the nogil release of Python (3.13? 3.14? 3.15?) will blow everything up again for us all...

github-actions bot added a commit to MaRDI4NFDI/open-interfaces that referenced this issue Oct 9, 2023
Bumps [greenlet](https://github.com/python-greenlet/greenlet) from 2.0.2
to 3.0.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/python-greenlet/greenlet/blob/master/CHANGES.rst">greenlet's
changelog</a>.</em></p>
<blockquote>
<h1>3.0.0 (2023-10-02)</h1>
<ul>
<li>No changes from 3.0rc3 aside from the version number.</li>
</ul>
<h1>3.0.0rc3 (2023-09-12)</h1>
<ul>
<li>Fix an intermittent error during process termination on some
platforms (GCC/Linux/libstdc++).</li>
</ul>
<h1>3.0.0rc2 (2023-09-09)</h1>
<ul>
<li>Fix some potential bugs (assertion failures and memory leaks) in
previously-untested error handling code. In some cases, this means
that the process will execute a controlled <code>abort()</code> after
severe
trouble when previously the process might have continued for some
time with a corrupt state. It is unlikely those errors occurred in
practice.</li>
<li>Fix some assertion errors and potential bugs with re-entrant
switches.</li>
<li>Fix a potential crash when certain compilers compile greenlet with
high levels of optimization. The symptom would be that switching to
a greenlet for the first time immediately crashes.</li>
<li>Fix a potential crash when the callable object passed to the
greenlet constructor (or set as the <code>greenlet.run</code> attribute)
has
a destructor attached to it that switches. Typically, triggering
this issue would require an unlikely subclass of
<code>greenlet.greenlet</code>.</li>
<li>Python 3.11+: Fix rare switching errors that could occur when a
garbage collection was triggered during the middle of a switch, and
Python-level code in <code>__del__</code> or weakref callbacks switched
to a
different greenlet and ultimately switched back to the original
greenlet. This often manifested as a <code>SystemError</code>:
&quot;switch
returned NULL without an exception set.&quot;</li>
</ul>
<p>For context on the fixes, see <code>gevent issue
[#1985](https://github.com/python-greenlet/greenlet/issues/1985)
&lt;https://github.com/gevent/gevent/issues/1985&gt;</code>_.</p>
<h1>3.0.0rc1 (2023-09-01)</h1>
<ul>
<li>Windows wheels are linked statically to the C runtime in an effort
to prevent import errors on systems without the correct C runtime
installed. It's not clear if this will make the situation better or
worse, so please share your experiences in <code>issue 346
&lt;https://github.com/python-greenlet/greenlet/issues/346&gt;</code>_.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/ef510e4b1a862800e77bc8e290769d688f691b9e"><code>ef510e4</code></a>
Preparing release 3.0.0</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/8b24b4d2122c101efbe98a1d08dc02ffd3899826"><code>8b24b4d</code></a>
Updating change log.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/79f63518ae53488c0acc19e9a1bfd740fc47149e"><code>79f6351</code></a>
Back to development: 3.0.0rc4</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/715128a4df7f93b247ce03a202e6d892a288e9b2"><code>715128a</code></a>
Preparing release 3.0.0rc3</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/f2ecf0c01a2f9524198be1f3220985de8eb5f0ff"><code>f2ecf0c</code></a>
D'oh, tstate is used under Py 3.11+. UNUSED breaks compilation on
windows.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/745181099a6d62bec05d443bae14c7b4dcd0a56a"><code>7451810</code></a>
Finish refactoring to separate files.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/748a9e064f42a04e208c7c32e1316b44ced18db9"><code>748a9e0</code></a>
Fix an intermittent error during process termination on
GCC/Linux/libstdc++.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/cec93b106247e16ef6003175a15f113baf1d4285"><code>cec93b1</code></a>
Move BrokenGreenlet to its own file.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/0b108b39224093ccfbad7f948532167afbd55ff8"><code>0b108b3</code></a>
Move UserGreenlet code to its own file.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/215d0c98dcbefd68357c90e86c526b00026171c8"><code>215d0c9</code></a>
Moving Greenlet, module globals and thread state destruction to their
own files.</li>
<li>Additional commits viewable in <a
href="https://github.com/python-greenlet/greenlet/compare/2.0.2...3.0.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=greenlet&package-manager=pip&previous-version=2.0.2&new-version=3.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
rababerladuseladim pushed a commit to robert-koch-institut/mex-drop that referenced this issue Oct 11, 2023
Bumps [greenlet](https://github.com/python-greenlet/greenlet) from 2.0.2
to 3.0.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/python-greenlet/greenlet/blob/master/CHANGES.rst">greenlet's
changelog</a>.</em></p>
<blockquote>
<h1>3.0.0 (2023-10-02)</h1>
<ul>
<li>No changes from 3.0rc3 aside from the version number.</li>
</ul>
<h1>3.0.0rc3 (2023-09-12)</h1>
<ul>
<li>Fix an intermittent error during process termination on some
platforms (GCC/Linux/libstdc++).</li>
</ul>
<h1>3.0.0rc2 (2023-09-09)</h1>
<ul>
<li>Fix some potential bugs (assertion failures and memory leaks) in
previously-untested error handling code. In some cases, this means
that the process will execute a controlled <code>abort()</code> after
severe
trouble when previously the process might have continued for some
time with a corrupt state. It is unlikely those errors occurred in
practice.</li>
<li>Fix some assertion errors and potential bugs with re-entrant
switches.</li>
<li>Fix a potential crash when certain compilers compile greenlet with
high levels of optimization. The symptom would be that switching to
a greenlet for the first time immediately crashes.</li>
<li>Fix a potential crash when the callable object passed to the
greenlet constructor (or set as the <code>greenlet.run</code> attribute)
has
a destructor attached to it that switches. Typically, triggering
this issue would require an unlikely subclass of
<code>greenlet.greenlet</code>.</li>
<li>Python 3.11+: Fix rare switching errors that could occur when a
garbage collection was triggered during the middle of a switch, and
Python-level code in <code>__del__</code> or weakref callbacks switched
to a
different greenlet and ultimately switched back to the original
greenlet. This often manifested as a <code>SystemError</code>:
&quot;switch
returned NULL without an exception set.&quot;</li>
</ul>
<p>For context on the fixes, see <code>gevent issue
[#1985](https://github.com/python-greenlet/greenlet/issues/1985)
&lt;https://github.com/gevent/gevent/issues/1985&gt;</code>_.</p>
<h1>3.0.0rc1 (2023-09-01)</h1>
<ul>
<li>Windows wheels are linked statically to the C runtime in an effort
to prevent import errors on systems without the correct C runtime
installed. It's not clear if this will make the situation better or
worse, so please share your experiences in <code>issue 346
&lt;https://github.com/python-greenlet/greenlet/issues/346&gt;</code>_.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/ef510e4b1a862800e77bc8e290769d688f691b9e"><code>ef510e4</code></a>
Preparing release 3.0.0</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/8b24b4d2122c101efbe98a1d08dc02ffd3899826"><code>8b24b4d</code></a>
Updating change log.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/79f63518ae53488c0acc19e9a1bfd740fc47149e"><code>79f6351</code></a>
Back to development: 3.0.0rc4</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/715128a4df7f93b247ce03a202e6d892a288e9b2"><code>715128a</code></a>
Preparing release 3.0.0rc3</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/f2ecf0c01a2f9524198be1f3220985de8eb5f0ff"><code>f2ecf0c</code></a>
D'oh, tstate is used under Py 3.11+. UNUSED breaks compilation on
windows.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/745181099a6d62bec05d443bae14c7b4dcd0a56a"><code>7451810</code></a>
Finish refactoring to separate files.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/748a9e064f42a04e208c7c32e1316b44ced18db9"><code>748a9e0</code></a>
Fix an intermittent error during process termination on
GCC/Linux/libstdc++.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/cec93b106247e16ef6003175a15f113baf1d4285"><code>cec93b1</code></a>
Move BrokenGreenlet to its own file.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/0b108b39224093ccfbad7f948532167afbd55ff8"><code>0b108b3</code></a>
Move UserGreenlet code to its own file.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/215d0c98dcbefd68357c90e86c526b00026171c8"><code>215d0c9</code></a>
Moving Greenlet, module globals and thread state destruction to their
own files.</li>
<li>Additional commits viewable in <a
href="https://github.com/python-greenlet/greenlet/compare/2.0.2...3.0.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=greenlet&package-manager=pip&previous-version=2.0.2&new-version=3.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
BenMMcLean pushed a commit to TechlauncherFireApp/backend that referenced this issue Oct 26, 2023
Bumps [greenlet](https://github.com/python-greenlet/greenlet) from 2.0.2
to 3.0.1.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/python-greenlet/greenlet/blob/master/CHANGES.rst">greenlet's
changelog</a>.</em></p>
<blockquote>
<h1>3.0.1 (2023-10-25)</h1>
<ul>
<li>Fix a potential crash on Python 3.8 at interpreter shutdown time.
This was a regression from earlier 3.0.x releases. Reported by Matt
Wozniski in <code>issue 376
&lt;https://github.com/python-greenlet/greenlet/issues/376&gt;</code>_.</li>
</ul>
<h1>3.0.0 (2023-10-02)</h1>
<ul>
<li>No changes from 3.0rc3 aside from the version number.</li>
</ul>
<h1>3.0.0rc3 (2023-09-12)</h1>
<ul>
<li>Fix an intermittent error during process termination on some
platforms (GCC/Linux/libstdc++).</li>
</ul>
<h1>3.0.0rc2 (2023-09-09)</h1>
<ul>
<li>Fix some potential bugs (assertion failures and memory leaks) in
previously-untested error handling code. In some cases, this means
that the process will execute a controlled <code>abort()</code> after
severe
trouble when previously the process might have continued for some
time with a corrupt state. It is unlikely those errors occurred in
practice.</li>
<li>Fix some assertion errors and potential bugs with re-entrant
switches.</li>
<li>Fix a potential crash when certain compilers compile greenlet with
high levels of optimization. The symptom would be that switching to
a greenlet for the first time immediately crashes.</li>
<li>Fix a potential crash when the callable object passed to the
greenlet constructor (or set as the <code>greenlet.run</code> attribute)
has
a destructor attached to it that switches. Typically, triggering
this issue would require an unlikely subclass of
<code>greenlet.greenlet</code>.</li>
<li>Python 3.11+: Fix rare switching errors that could occur when a
garbage collection was triggered during the middle of a switch, and
Python-level code in <code>__del__</code> or weakref callbacks switched
to a
different greenlet and ultimately switched back to the original
greenlet. This often manifested as a <code>SystemError</code>:
&quot;switch
returned NULL without an exception set.&quot;</li>
</ul>
<p>For context on the fixes, see <code>gevent issue
[#1985](https://github.com/python-greenlet/greenlet/issues/1985)
&lt;https://github.com/gevent/gevent/issues/1985&gt;</code>_.</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/77a9a2952b166b83011f5c3ebeb6ad2d6370bbfa"><code>77a9a29</code></a>
Preparing release 3.0.1</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/11b1b758f5b3a43eb2e0a5499047ddef2517e3ec"><code>11b1b75</code></a>
CI: Use 3.12 final instead of -dev.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/76b4ac08969f24c3a87a389f8bd37807547be6ce"><code>76b4ac0</code></a>
Wheels: We're forcing the platform tag for universal2, not the api tag
(which...</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/4751fbe89d247a7082ebc76bd7b88b649c9e8f0a"><code>4751fbe</code></a>
Fix <a
href="https://redirect.github.com/python-greenlet/greenlet/issues/376">#376</a></li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/309575a62b9853bc3b6367225e388a65796e9c7c"><code>309575a</code></a>
Centralize use of psutil.Process.uss; deal gracefully when it is not
available.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/313d06b0eac0541ad6bde3cb0e3effc0a9e6b5ce"><code>313d06b</code></a>
Remove test status badge from README. It was confusing.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/660a66f339c61b2572ea6237cc042bde356419b1"><code>660a66f</code></a>
Back to development: 3.0.1</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/ef510e4b1a862800e77bc8e290769d688f691b9e"><code>ef510e4</code></a>
Preparing release 3.0.0</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/8b24b4d2122c101efbe98a1d08dc02ffd3899826"><code>8b24b4d</code></a>
Updating change log.</li>
<li><a
href="https://github.com/python-greenlet/greenlet/commit/79f63518ae53488c0acc19e9a1bfd740fc47149e"><code>79f6351</code></a>
Back to development: 3.0.0rc4</li>
<li>Additional commits viewable in <a
href="https://github.com/python-greenlet/greenlet/compare/2.0.2...3.0.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=greenlet&package-manager=pip&previous-version=2.0.2&new-version=3.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this issue Oct 29, 2023
Switch to wheel.mk.

3.0.1 (2023-10-25)
==================

- Fix a potential crash on Python 3.8 at interpreter shutdown time.
  This was a regression from earlier 3.0.x releases. Reported by Matt
  Wozniski in `issue 376 <https://github.com/python-greenlet/greenlet/issues/376>`_.



3.0.0 (2023-10-02)
==================

- No changes from 3.0rc3 aside from the version number.


3.0.0rc3 (2023-09-12)
=====================

- Fix an intermittent error during process termination on some
  platforms (GCC/Linux/libstdc++).


3.0.0rc2 (2023-09-09)
=====================

- Fix some potential bugs (assertion failures and memory leaks) in
  previously-untested error handling code. In some cases, this means
  that the process will execute a controlled ``abort()`` after severe
  trouble when previously the process might have continued for some
  time with a corrupt state. It is unlikely those errors occurred in
  practice.
- Fix some assertion errors and potential bugs with re-entrant
  switches.
- Fix a potential crash when certain compilers compile greenlet with
  high levels of optimization. The symptom would be that switching to
  a greenlet for the first time immediately crashes.
- Fix a potential crash when the callable object passed to the
  greenlet constructor (or set as the ``greenlet.run`` attribute) has
  a destructor attached to it that switches. Typically, triggering
  this issue would require an unlikely subclass of
  ``greenlet.greenlet``.
- Python 3.11+: Fix rare switching errors that could occur when a
  garbage collection was triggered during the middle of a switch, and
  Python-level code in ``__del__`` or weakref callbacks switched to a
  different greenlet and ultimately switched back to the original
  greenlet. This often manifested as a ``SystemError``: "switch
  returned NULL without an exception set."

For context on the fixes, see `gevent issue #1985
<https://github.com/gevent/gevent/issues/1985>`_.

3.0.0rc1 (2023-09-01)
=====================

- Windows wheels are linked statically to the C runtime in an effort
  to prevent import errors on systems without the correct C runtime
  installed. It's not clear if this will make the situation better or
  worse, so please share your experiences in `issue 346
  <https://github.com/python-greenlet/greenlet/issues/346>`_.

  Note that this only applies to the binary wheels found on PyPI.
  Building greenlet from source defaults to the shared library. Set
  the environment variable ``GREENLET_STATIC_RUNTIME=1`` at build time
  to change that.
- Build binary wheels for Python 3.12 on macOS.
- Fix compiling greenlet on a debug build of CPython 3.12. There is
  `one known issue
  <https://github.com/python-greenlet/greenlet/issues/368>`_ that
  leads to an interpreter crash on debug builds.
- Python 3.12: Fix walking the frame stack of suspended greenlets.
  Previously accessing ``glet.gr_frame.f_back`` would crash due to
  `changes in CPython's undocumented internal frame handling <https://github.com/python/cpython/commit/1e197e63e21f77b102ff2601a549dda4b6439455>`_.

Platforms
---------
- Now, greenlet *may* compile and work on Windows ARM64 using
  llvm-mingw, but this is untested and unsupported. See `PR
  <https://github.com/python-greenlet/greenlet/pull/224>`_ by Adrian
  Vladu.
- Now, greenlet *may* compile and work on LoongArch64 Linux systems,
  but this is untested and unsupported. See `PR 257
  <https://github.com/python-greenlet/greenlet/pull/257/files>`_ by merore.

Known Issues
------------

- There may be (very) subtle issues with tracing on Python 3.12, which
  has redesigned the entire tracing infrastructure.

3.0.0a1 (2023-06-21)
====================

- Build binary wheels for S390x Linux. See `PR 358
  <https://github.com/python-greenlet/greenlet/pull/358>`_ from Steven
  Silvester.
- Fix a rare crash on shutdown seen in uWSGI deployments. See `issue
  330 <https://github.com/python-greenlet/greenlet/issues/330>`_ and `PR 356
  <https://github.com/python-greenlet/greenlet/pull/356>`_ from Andrew
  Wason.
- Make the platform-specific low-level C/assembly snippets stop using
  the ``register`` storage class. Newer versions of standards remove
  this storage class, and it has been generally ignored by many
  compilers for some time. See `PR 347
  <https://github.com/python-greenlet/greenlet/pull/347>`_ from Khem
  Raj.
- Add initial support for Python 3.12. See `issue
  <https://github.com/python-greenlet/greenlet/issues/323>`_ and `PR
  <https://github.com/python-greenlet/greenlet/pull/327>`_; thanks go
  to (at least) Michael Droettboom, Andreas Motl, Thomas A Caswell,
  raphaelauv, Hugo van Kemenade, Mark Shannon, and Petr Viktorin.
- Remove support for end-of-life Python versions, including Python
  2.7, Python 3.5 and Python 3.6.
- Require a compiler that supports ``noinline`` directives. See
  `issue 271
  <https://github.com/python-greenlet/greenlet/issues/266>`_.
- Require a compiler that supports C++11.
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

No branches or pull requests