-
Notifications
You must be signed in to change notification settings - Fork 42
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
Support the deprecation of asyncore in python 3.12 #260
Conversation
@Lorak-mmk |
32919c0
to
a9bad78
Compare
ec80814
to
58f3ba1
Compare
FYI, the situation with asyncio on python-3.8 is o.k. One extra failing test We'll need to test more python versions |
I'm setting a goal to this PR (so won't spread too much) CI working for 3.8 - asyncore/libev/asyncio 3.12 - only libev Other python versions aren't mandatory |
Wow, I'm very surprised that it works |
fc7e475
to
ebd44d3
Compare
so at the end I've did much more in this PR followup PRs would be
|
ebd44d3
to
85a7211
Compare
from my POV we can merge this one, once I get a green CI but I still want you to take a look at the actual commit (not the CI ones, they are quite straightforward) |
b93369c
to
48399d6
Compare
#264 seems to be flaky, and not sure exactly why... @Lorak-mmk this one is ready from my POV |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requested some changes. We should probably offer this PR upstream after we merge it,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file has a ConnectionTests
class which is then subclassed (AsyncoreConnectionTests
and LibevConnectionTests
). It would be good if a part of this PR was to add subclasses for other reactors. If that's too much work, a TODO will suffice.
I also wonder if a subclass for each reactor is the best approach - it causes us to run all of them always, no matter what is the value of EVENT_LOOP_MANAGER
, maybe it should be conditional?
One more thing, in case of import error, relevant var is set to None - I don't get why it doesn't cause tests to fail - I don't see any None
checks, and ConnectionTests.setUp
calls self.klass.initialize_reactor()
which should fail - so there is something I don't understand in this code...
# need to run them with specific configuration like `gevent.monkey.patch_all()` or under async functions | ||
unsupported_connection_classes = [GeventConnection, AsyncioConnection, EventletConnection] | ||
# unsupported_connection_classes = [GeventConnection, AsyncioConnection, EventletConnection] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't immediately see why wouldn't AsyncioConnection
work here. Did you try to run this test with it?
Also, is commenting out this line and 3 imports necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Asyncio wasn't working at all when those tests were written, so I didn't introduce it now
As for the comment, I rather not import the unused classes, it was for documenting only, and import of some of them now complicates things
cassandra/io/asyncioreactor.py
Outdated
loop_args = dict() | ||
if sys.version_info[0] == 3 and sys.version_info[1] < 10: | ||
loop_args['loop'] = self._loop | ||
self._write_queue = asyncio.Queue(**loop_args) | ||
self._write_queue_lock = asyncio.Lock(**loop_args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really don't like such conditionals...
This could be solved differently - before 3.10, when loop argument is not provided, current loop is used (fetched during __init__
). So we could put a task that creates those objects on a loop and get the result, something like this (it can most likely be a bit prettier, it's just a PoC):
async def asyncify(f, *args, **kwargs):
return f(*args, **kwargs)
self._write_queue = asyncio.run_coroutine_threadsafe(asyncify(asyncio.Queue)(), self._loop).result()
self.._write_queue_lock = asyncio.run_coroutine_threadsafe(asyncify(asyncio.Lock)(), self._loop).result()
However I'm not really sure it's better than (if python < 3.10) version...
If we stay with if
approach, let's add a TODO to remove it after dropping support for 3.9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like in upstream they removed completely
datastax@e9136f4
which is quite weird, since it's break python 3.8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, missed this one earlier. The params in question were removed in PYTHON-1313. There's more detail in the ticket but in short asyncio will default to the event loop for the current thread since 3.7. And since the asyncio reactor explicitly sets the created loop for the current thread via set_event_loop() immediately after it's creation there didn't appear to be any obvious need to pass it around.
The relevant tests pass on Python 3.8 on our Jenkins instance, but if I've missed something there I'm certainly open to changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, from my own local tests, and tests running on github actions,
python3.8 break totally when those parameters are not passed to the locks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
relevant_warnings
can probably be made empty if we apply my suggestion instead of version-conditional code.
cassandra/cluster.py
Outdated
from cassandra.io.asyncorereactor import AsyncoreConnection as DefaultConnection # NOQA | ||
from cassandra.io.asyncioreactor import AsyncioConnection as DefaultConnection # NOQA |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also think about removing asyncore in a follow up PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no rush on that,
And we can sync with upstream about when todo it, i.e. not to break current users that might have hardcore it
Hey all, just a quick note on upstream plans related to what you guys are working on for this ticket. We're gearing up for a 3.29.0 release which aims to follow our policy of supporting all non-EOL releases at time of release. That means we're aiming to support 3.8 through 3.12 with 3.29.0. The removal of asyncore in 3.12 is being pursued in PYTHON-1366. I had originally intended to make the asyncio reactor the default (replacing asyncore) for 3.29.0 but I'm not convinced the asyncio reactor is stable enough to support that yet. So for 3.29.0 I'm settling on messaging telling users to use one of the third-party event loops for now; asyncio will become the default once we can make it more stable. To that end: if you guys are inclined to contribute any fixes to the asyncio reactor upstream we'd be more than happy to take a look at them. It's probably worthwhile to separate that work from any work around 3.12 compat, though, in order to avoid any confusion of goals. Comments welcome. :) |
I've managed at least to get the asyncio passing all the integration suite Would love to hear what are the other thing you think would be need to title it ready for production (maybe we help in some parts)
Yeah I know I was trying to do multiple things here, but I'll can separate the asyncio only change into an upstream PR.
|
Yes, we probably would need to break it a bit |
48399d6
to
3a5609d
Compare
926ae2d
to
8bf2590
Compare
Hey @fruch , appreciate the follow-up! An update to my previous comment: I've now merged the changes in PYTHON-1366 into the code base. As mentioned above these changes throw exceptions when trying to use asyncore with Python 3.12. These warnings coupled with documentation and messaging around the release should make clear why asyncore isn't supported on Python 3.12 and what the user can do about it (i.e. use another event loop). I decided it was easier to take an incremental approach like this (not failing completely when trying to use asyncore with Python 3.12 while also providing clear instructions) in the hope that it would be less intrusive for our users. Which brings me to your other question: what do we need to see to make asyncio the default? I'm impressed with the work you guys have done to get asyncio passing all the integration tests and would love to incorporate those changes into upstream as well. Other than that I'd like to see how this reactor behaves over time. We typically run "duration tests" with each release that run for several days in order to identify any regressions that only appear over time. I'd like to see an asyncio reactor pass such a test. I'd also like to see some more load testing, just to make sure it won't have any issues if we stress it a bit. I'm not at all opposed to making asyncio the default reactor for future driver releases; with the removal of asyncore in 3.12 that seems like the correct way to go. I just want to do it in a step-wise fashion so that we don't drop a ton of change on our users within a single release. Thanks again! |
I did thought we might be able to default to asyncio only once asyncore isn't available,
Yeah I thought that would helpful to grant trust, we didn't touch those test in this repo yet
that's great, that things are moving fast, having python 3.12 support is very important to us
to conclude, I think we won't be merging those change, and we'll wait for the upstream release (which I hope is just around the corner) as for the asyncio related changes, please see: #271 |
running on python 3.12, we get this error, we should ignore it until eventlet is fixed ``` ImportError while loading conftest '/home/runner/work/python-driver/python-driver/tests/integration/conftest.py'. tests/integration/__init__.py:16: in <module> from cassandra.cluster import Cluster cassandra/cluster.py:103: in init cassandra.cluster from cassandra.io.eventletreactor import EventletConnection cassandra/io/eventletreactor.py:18: in <module> import eventlet .test-venv/lib/python3.12/site-packages/eventlet/__init__.py:17: in <module> from eventlet import convenience .test-venv/lib/python3.12/site-packages/eventlet/convenience.py:7: in <module> from eventlet.green import socket .test-venv/lib/python3.12/site-packages/eventlet/green/socket.py:21: in <module> from eventlet.support import greendns .test-venv/lib/python3.12/site-packages/eventlet/support/greendns.py:45: in <module> from eventlet.green import ssl .test-venv/lib/python3.12/site-packages/eventlet/green/ssl.py:25: in <module> _original_wrap_socket = __ssl.wrap_socket E AttributeError: module 'ssl' has no attribute 'wrap_socket' ``` Ref: eventlet/eventlet#812
this isn't being used anyhow, and breaking support for python 3.12
since asyncore isn't available in python 3.12, we should be gracfully handle it, and enable any other event loop implementions to work
since python 3.12 is deprecating asyncore, we should make asyncio the default fallback event loop when asyncore isn't available asyncio now that it's fixed and we verified it's working (passing the integration suite) in multiple python versions we support (from 3.8 - 3.12)
8bf2590
to
6730c67
Compare
@Lorak-mmk And then I think we should release one last minor release, before syncing with upstream 3.28.0, or 3.29.0 once it would be available |
I left 2 questions in the comments, apart from that looks good to me. However I'd prefer to not release until #271 (comment) is addressed |
since we need to deprecate asyncore which was the default event loop manager, we need to extend the testing of some of the other so we can select a new default