When does Djangos CONN_MAX_AGE get checked/used?
I recently had a "Too many connections" issues of my Django+Celery application with a Postgres DB on Heroku.
Could dyno restarts be the issue? The idea is that the dyno restart drops the connection, but Postgres keeps them.
Setting CONN_MAX_AGE
seems to have solved the issue, but I'm uncertain.
The question now is: How does CONN_MAX_AGE
work?
(1) Does Django actively check the age of the connection and close + restart it when it's too old
or
(2) Is CONN_MAX_AGE
a parameter of the connection itself, so that postgres automatically closes the connection after that time?
Does Django actively check the age of the connection and close + restart it when it's too old.
Django will, each time it opens a connection, set the time when it has to close the connection [GitHub]:
class BaseDatabaseWrapper: # … @async_unsafe def connect(self): # … max_age = self.settings_dict["CONN_MAX_AGE"] self.close_at = None if max_age is None else time.monotonic() + max_age
Django will then, when a method named .close_if_unusable_or_obsolete()
is called, close the connection [GitHub]:
class BaseDatabaseWrapper: # … def close_if_unusable_or_obsolete(self): # … if self.connection is not None: # … if self.close_at is not None and time.monotonic() >= self.close_at: self.close() return
You can call that method yourself to "recycle" connections. But it is by default done when a request starts and when a request ends, indeed Django registers this on two signals [GitHub]:
def close_old_connections(**kwargs): for conn in connections.all(initialized_only=True): conn.close_if_unusable_or_obsolete() signals.request_started.connect(close_old_connections) signals.request_finished.connect(close_old_connections)
It will thus, before a request fires, recycle the connections, and also after a request has fired, recycle the connections with unrecoverable errors, or outdated ones. Recycling these in the middle of a request might not be a good idea, since the connection might be stateful.