8000 Fix thread shutdown on PY39+ (fix #1121) by haakonvt · Pull Request #1122 · cognitedata/cognite-sdk-python · GitHub
[go: up one dir, main page]

Skip to content

Fix thread shutdown on PY39+ (fix #1121) #1122

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

Merged
merged 7 commits into from
Jan 27, 2023
Merged

Conversation

haakonvt
Copy link
Contributor
@haakonvt haakonvt commented Jan 25, 2023

Description

Starting in 3.9, ThreadPoolExecutor no longer uses daemon threads, but instead, an internal function hook very similar to atexit.register(), which gets called at 'threading' shutdown instead of interpreter shutdown. Check out python/cpython#83993

Some links:

This sounds like an argument for testing multiple Python versions (with tox perhaps)? 🤔

Checklist:

  • Tests added/updated.
  • Documentation updated. Documentation is generated from docstrings - these must be updated according to your change.
    If a new method has been added it should be referenced in cognite.rst in order to generate docs based on its docstring.
  • Changelog updated in CHANGELOG.md.
  • Version bumped. If triggering a new release is desired, bump the version number in _version.py and pyproject.toml per semantic versioning.

@haakonvt haakonvt requested review from a team as code owners January 25, 2023 15:30
@haakonvt haakonvt requested a review from a team January 25, 2023 15:30
@haakonvt haakonvt requested a review from a team as a code owner January 25, 2023 15:30
@codecov
Copy link
codecov bot commented Jan 25, 2023

Codecov Report

Merging #1122 (24b9b42) into master (06893a8) will decrease coverage by 0.05%.
The diff coverage is 79.41%.

@@            Coverage Diff             @@
##           master    #1122      +/-   ##
==========================================
- Coverage   91.35%   91.30%   -0.05%     
==========================================
  Files          80       80              
  Lines        9159     9166       +7     
==========================================
+ Hits         8367     8369       +2     
- Misses        792      797       +5     
Impacted Files Coverage Δ
cognite/client/utils/_priority_tpe.py 79.01% <78.12%> (-6.33%) ⬇️
cognite/client/_api/datapoints.py 95.92% <100.00%> (+<0.01%) ⬆️
cognite/client/_version.py 100.00% <100.00%> (ø)
cognite/client/_api/datapoint_tasks.py 95.33% <0.00%> (+0.12%) ⬆️

Copy link
Collaborator
@erlendvollset erlendvollset left a comment

Choose a reason for hiding this comment

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

I don't have enough context here to give a proper review, but LGTM. Maybe @doctrino wants to have a look - I believe he added this module initially?

@haakonvt
Copy link
Contributor Author
haakonvt commented Jan 26, 2023

This PR is probably a good change either way, but I found what seems to be the root cause of all this; Futures with an exception (e.g. ts not found) causes it to not be cleaned up and thus after the change from atexit to threading.... the ref count is keeping it from being garbage collected. I added a super simple future._exception = None and 🪄 problem gone.

I'll investigate some more tomorrow @erlendvollset

for thread, queue in items:
queue.put(NULL_ENTRY)
for thread, queue in items:
thread.join()


atexit.unregister(_python_exit)
atexit.register(python_exit)
# We should register an at-exit-handler to clean up our threads gracefully at interpreter shutdown.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't really think there is a need for "cleaning up the threads gracefully". Essentially you're just waiting for work to finish, and then tossing the results out, so the only thing you achieve is slower shutdown of the interpreter. Unless I'm missing something here, I think we can remove the atexit hook altogether.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With current tasks, yes, however, that gives us a "dependency" on the future use of the PTPE to never have tasks with side effects; not something I would want to perpetually make sure is the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've gone down the deep rabbit hole here and I really think this implementation is the way way to do it. Separate thread pools, separate thread-safe queues, and separate cleanup functions registered that take the python version into account! 🍀

Copy link
Collaborator
@erlendvollset erlendvollset Jan 27, 2023

Choose a reason for hiding this comment

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

Fair point (although YAGNI 😄) - let's go for this approach then! 🤝

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Lol YAGNI, learned something new today 😂 Btw, if you really want it removed why don’t we also remove from the standard library by monkeypatching? 😜 I feel good knowing we mimic the exact same approach as some code written by people way smarter than myself 😂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also; the code do crash without it 😉

@haakonvt haakonvt merged commit 2cdd57e into master Jan 27, 2023
@haakonvt haakonvt deleted the fix-dps-atexit-bug-39plus branch January 27, 2023 10:34
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.

2 participants
0