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

Close old DB connections allow to recover from DB errors on each iteration #147

Closed
wants to merge 1 commit into from

Conversation

bluetech
Copy link
Contributor

This is a proposed fix for #145. Please see the code comment for an explanation.

The added call can cause a connection to close, so it is somewhat assumed that get_due_jobs() is run from the scheduler loop in a context which "owns" a connection (e.g. a management command or dedicated thread) and not a shared/request context.

The close_old_connections API itself is not documented but has existed for a long time and I doubt it will disappear without notice.

The test is a bit hacky but it's what I managed with sqlite.

@codecov
Copy link

codecov bot commented Jun 12, 2021

Codecov Report

Merging #147 (aea86a0) into develop (c3e9d24) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff            @@
##           develop     #147   +/-   ##
========================================
  Coverage    97.85%   97.85%           
========================================
  Files            6        6           
  Lines          326      327    +1     
========================================
+ Hits           319      320    +1     
  Misses           7        7           
Flag Coverage Δ
unittests 97.85% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
django_apscheduler/jobstores.py 98.67% <100.00%> (+<0.01%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c3e9d24...aea86a0. Read the comment docs.

with pytest.raises(db.OperationalError):
with db.connection.cursor() as cursor:
cursor.execute("INVALID SYNTAX ERROR")
assert db.connection.errors_occurred
Copy link
Owner

Choose a reason for hiding this comment

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

It seems like the only purpose of executing a query here that deliberately raises an error, and then checking errors_occurred, is to determine if django.db.backends.base.BaseDatabaseWrapper.close_if_unusable_or_obsolete() was called.

We could probably achieve the same more simply by mocking that method out and checking if it was called.

#
# get_due_jobs() seems like the most appropriate place for this,
# as it's called at the beginning of every scheduler iteration.
db.close_old_connections()
Copy link
Owner

Choose a reason for hiding this comment

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

Pre-emptively closing connections like this is problematic (see #145 (comment)).

The standard Django can get away with it because it does so at the beginning and end of a request-response-cycle, while all other db operations within that cycle still get to re-use the same connection.

#
# get_due_jobs() seems like the most appropriate place for this,
# as it's called at the beginning of every scheduler iteration.
db.close_old_connections()
Copy link
Owner

Choose a reason for hiding this comment

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

Yes, but database connections can be closed by the backend database engine literally anytime and while we are processing code anywhere in the project (see the issue log for examples of where this issue has cropped up elsewhere as well).

We need to find a catch-all solution if possible.

@jcass77
Copy link
Owner

jcass77 commented Jun 13, 2021

Thanks for the PR. I think this is a hard problem to solve and I am not entirely sure how best to go about it.

Please see #148 for an alternative approach that attempts to cover more cases and avoid some of the many pitfalls and side effects. I would be grateful if you could try it out and report your findings there.

@jcass77 jcass77 closed this Jun 13, 2021
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