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

Add main_thread_only execmodel #243

Conversation

zmedico
Copy link
Contributor

@zmedico zmedico commented Feb 15, 2024

In order to prevent tasks from running in a non-main thread, wait for the previous task inside _try_send_to_primary_thread, then schedule the next task. Add a main_thread_only execmodel to distinguish this new behavior from the existing thread execmodel, since users of the thread execmodel expect that tasks can run in multiple threads concurrently. If concurrent remote_exec requests are submitted for the main_thread_only execmodel, then the channel will raise a RemoteError with this message:

concurrent remote_exec would cause deadlock for main_thread_only execmodel

In order for main_thread_only users to avoid this error, remote_exec callers must use the returned channel to wait for a task to complete before they call remote_exec again, as demonstrated in test_assert_main_thread_only. Testing of main_thread_only with pytest-xdist has shown that this behavior is compatible with the existing pytest-xdist usage because it never calls remote_exec more than once per gateway.

Closes: #96

@RonnyPfannschmidt
Copy link
Member

How does this behave when multiple tasks are being sent

At first glance it seems like it could break usages

@zmedico
Copy link
Contributor Author

zmedico commented Feb 15, 2024

How does this behave when multiple tasks are being sent

At first glance it seems like it could break usages

I ran the tests localy and it seems to somehow deadlock in this one:
testing/test_gateway.py::TestBasicGateway::test_gateway_status_busy[thread-popen]

It hangs on ch1 = gw.remote_exec("channel.send(1); channel.receive()").

I wonder if there's some way to handle it without a deadlock...

I suppose there's probably some queue.Queue usage that could work here.

@zmedico zmedico marked this pull request as draft February 15, 2024 07:53
@RonnyPfannschmidt
Copy link
Member

That test is a small approximate of the case I mentioned

Basically if the main thread is busy and you send in a task, the wait will break the gateway

@zmedico

This comment was marked as resolved.

@RonnyPfannschmidt
Copy link
Member

Nope, that just hides the issue somewhere that's hard to control

My rough plan was to completely drop exec models to provide async support for execnet via asyncio/trio/curio

@zmedico
Copy link
Contributor Author

zmedico commented Feb 15, 2024

Nope, that just hides the issue somewhere that's hard to control

Can you help me understand what makes it hard to control? Rather than launch a Thread in _local_schedulexec, I would prefer to use a queue.Queue instance to queue an asynchronous call to self._execpool.spawn here. Would a queue make it any easier to control?

My rough plan was to completely drop exec models to provide async support for execnet via asyncio/trio/curio

That seems like an entirely reasonable thing to do (I noticed #150). However, guaranteed scheduling in the main thread as required to solve pytest-dev/pytest-xdist#620 seems like it might be doable given that in my experience the "thread" execmodel nearly provides this guarantee as it is, but maybe I'm being naive due to my lack of familiarity with execnet in general.

@RonnyPfannschmidt
Copy link
Member

@zmedico the key issue here is that it is absolutely valid to run multiple tasks concurrent - so waiting for it to be finished is techically wrong, which is why the test for the rinfo busy fails

unless there is a mechanism to give tagged expectations (for main thread tasks) its unlikel to have it correct

@zmedico
Copy link
Contributor Author

zmedico commented Feb 15, 2024

@zmedico the key issue here is that it is absolutely valid to run multiple tasks concurrent - so waiting for it to be finished is techically wrong, which is why the test for the rinfo busy fails

Thanks for the explanation. So, I suppose the plan would be to add support to tag the expectation when we drop execmodel support.

unless there is a mechanism to give tagged expectations (for main thread tasks) its unlikel to have it correct

In the interim for the elimination of execmodel, I suppose we could add a main_thread execmodel that would only slightly extend the thread execmodel, allowing us to use the main_thread execmodel to tag the expectation.

@RonnyPfannschmidt
Copy link
Member

introducing a main_thread_only model could be a good starting point

@zmedico zmedico force-pushed the fix_issue_95_WorkerPool_Wait_for_previous_task_in_try_send_to_primary_thread branch 3 times, most recently from be707da to 4f69add Compare February 16, 2024 00:31
@zmedico zmedico changed the title WorkerPool: Wait for previous task in _try_send_to_primary_thread Add main_thread_only execmodel Feb 16, 2024
@zmedico zmedico marked this pull request as ready for review February 16, 2024 00:33
@zmedico zmedico force-pushed the fix_issue_95_WorkerPool_Wait_for_previous_task_in_try_send_to_primary_thread branch 3 times, most recently from 6e24bbf to 4f86b2a Compare February 16, 2024 05:58
zmedico added a commit to zmedico/pytest-xdist that referenced this pull request Feb 16, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
proposed in pytest-dev/execnet#243, so this
patch should not be merged until there is a release version of execnet
supporting the main_thread_only execmodel.

Closes: pytest-dev#620
@zmedico
Copy link
Contributor Author

zmedico commented Feb 16, 2024

@RonnyPfannschmidt This main_thread_only implementation seems to work pretty well for me in combination with a pytest-xdist patch that I've created to utilize it. I tend to see a lot of pytest-xdist worker crashes like worker 'gw0' crashed while running ... for one of my projects (I'm using a pytest-rerunfailures workaroud in gentoo/portage#1273), and with these patches I'm not seeing any crashes right now which I was able to trigger locally before.

Copy link
Member

@RonnyPfannschmidt RonnyPfannschmidt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless we find a way to incorporate a timeout or a quick error, the name should indicate its a hack

I'd recommend to add a timeout and erroring when the task can't be started within a reasonable timeframe

There should be a test that validates this error happens after a reasonable timeout

@zmedico

This comment was marked as resolved.

@zmedico zmedico marked this pull request as draft February 17, 2024 03:46
src/execnet/gateway_base.py Outdated Show resolved Hide resolved
@zmedico zmedico force-pushed the fix_issue_95_WorkerPool_Wait_for_previous_task_in_try_send_to_primary_thread branch from 4f86b2a to 53332fd Compare February 17, 2024 04:23
@zmedico zmedico marked this pull request as ready for review February 17, 2024 05:16
@zmedico zmedico force-pushed the fix_issue_95_WorkerPool_Wait_for_previous_task_in_try_send_to_primary_thread branch 2 times, most recently from 180d3ea to e6071f7 Compare February 17, 2024 06:50
Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @zmedico!

Left some minor suggestions to the CHANGELOG. 👍

CHANGELOG.rst Outdated Show resolved Hide resolved
CHANGELOG.rst Outdated Show resolved Hide resolved
CHANGELOG.rst Outdated Show resolved Hide resolved
CHANGELOG.rst Outdated Show resolved Hide resolved
CHANGELOG.rst Show resolved Hide resolved
zmedico added a commit to zmedico/execnet that referenced this pull request Feb 22, 2024
@zmedico zmedico force-pushed the fix_issue_95_WorkerPool_Wait_for_previous_task_in_try_send_to_primary_thread branch from 464a0ed to db8317a Compare February 22, 2024 22:16
zmedico added a commit to zmedico/execnet that referenced this pull request Feb 22, 2024
@zmedico zmedico force-pushed the fix_issue_95_WorkerPool_Wait_for_previous_task_in_try_send_to_primary_thread branch 2 times, most recently from d72144c to db8317a Compare February 22, 2024 22:28
@zmedico zmedico force-pushed the fix_issue_95_WorkerPool_Wait_for_previous_task_in_try_send_to_primary_thread branch from db8317a to c5cef44 Compare February 22, 2024 22:31
@nicoddemus
Copy link
Member

Thanks @zmedico!

@RonnyPfannschmidt would you like to do the honors of merging/releasing this one? 😁

@RonnyPfannschmidt
Copy link
Member

Absolutely, I'll get to it later today

This one is a big plus as it does resolve a issue with xdist paining us ever since exec models where added

@RonnyPfannschmidt RonnyPfannschmidt merged commit 678df09 into pytest-dev:master Feb 24, 2024
12 checks passed
@RonnyPfannschmidt
Copy link
Member

thanks again !

@zmedico zmedico deleted the fix_issue_95_WorkerPool_Wait_for_previous_task_in_try_send_to_primary_thread branch February 24, 2024 20:39
zmedico added a commit to zmedico/pytest-xdist that referenced this pull request Feb 25, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
proposed in pytest-dev/execnet#243, so this
patch should not be merged until there is a release version of execnet
supporting the main_thread_only execmodel.

Closes: pytest-dev#620
zmedico added a commit to zmedico/pytest-xdist that referenced this pull request Feb 25, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
proposed in pytest-dev/execnet#243, so this
patch should not be merged until there is a release version of execnet
supporting the main_thread_only execmodel.

Closes: pytest-dev#620
zmedico added a commit to zmedico/pytest-xdist that referenced this pull request Feb 25, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
proposed in pytest-dev/execnet#243, so this
patch should not be merged until there is a release version of execnet
supporting the main_thread_only execmodel.

Also increase minimum python version to 3.8 since execnet dropped 3.7
support in pytest-dev/execnet#245.
zmedico added a commit to zmedico/pytest-xdist that referenced this pull request Feb 25, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
proposed in pytest-dev/execnet#243, so this
patch should not be merged until there is a release version of execnet
supporting the main_thread_only execmodel.

Also increase minimum python version to 3.8 since execnet dropped 3.7
support in execnet#245.
zmedico added a commit to zmedico/pytest-xdist that referenced this pull request Feb 25, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
merged to the execnet master branch via pytest-dev/execnet#243, so this
patch should not be merged until there is a released version of execnet
supporting the main_thread_only execmodel.

Also increase minimum python version to 3.8 since execnet dropped 3.7
support in pytest-dev/execnet#245.

Closes: pytest-dev#620
zmedico added a commit to zmedico/pytest-xdist that referenced this pull request Feb 25, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
merged to the execnet master branch via pytest-dev/execnet#243, so this
patch should not be merged until there is a released version of execnet
supporting the main_thread_only execmodel.

Also increase minimum python version to 3.8 since execnet dropped 3.7
support in pytest-dev/execnet#245.

Closes: pytest-dev#620
@zmedico
Copy link
Contributor Author

zmedico commented Feb 25, 2024

Corresponding pytest-xdist MR submitted as pytest-dev/pytest-xdist#1027.

zmedico added a commit to zmedico/pytest-xdist that referenced this pull request Apr 8, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
merged to the execnet master branch via pytest-dev/execnet#243, so this
patch should not be merged until there is a released version of execnet
supporting the main_thread_only execmodel.

Closes: pytest-dev#620
zmedico added a commit to zmedico/pytest-xdist that referenced this pull request Apr 17, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
merged to the execnet master branch via pytest-dev/execnet#243, so this
patch should not be merged until there is a released version of execnet
supporting the main_thread_only execmodel.

Closes: pytest-dev#620
zmedico added a commit to zmedico/pytest-xdist that referenced this pull request Apr 17, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
merged to the execnet master branch via pytest-dev/execnet#243, so this
patch should not be merged until there is a released version of execnet
supporting the main_thread_only execmodel.

Closes: pytest-dev#620
nicoddemus pushed a commit to zmedico/pytest-xdist that referenced this pull request Apr 19, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
merged to the execnet master branch via pytest-dev/execnet#243, so this
patch should not be merged until there is a released version of execnet
supporting the main_thread_only execmodel.

Closes: pytest-dev#620
nicoddemus pushed a commit to pytest-dev/pytest-xdist that referenced this pull request Apr 19, 2024
Use the execnet main_thread_only execmodel so that code which expects
to run in the main thread will just work.  This execmodel has been
merged to the execnet master branch via pytest-dev/execnet#243, so this
patch should not be merged until there is a released version of execnet
supporting the main_thread_only execmodel.

Closes #620
@webknjaz
Copy link
Member

This is a possible regression cause: xref pytest-dev/pytest-xdist#1070 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(via xdist) Intermittently ending up on non-main thread
4 participants