Skip to content

Commit cf3951e

Browse files
authored
Improve the Django DB connection management #509 (#512)
1 parent 4d64484 commit cf3951e

File tree

1 file changed

+17
-11
lines changed

1 file changed

+17
-11
lines changed

slack_bolt/adapter/django/handler.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,16 @@ def to_django_response(bolt_resp: BoltResponse) -> HttpResponse:
5454
return resp
5555

5656

57-
from django.db import connections
57+
from django.db import close_old_connections
5858

5959

60-
def release_thread_local_connections(logger: Logger, execution_type: str):
61-
connections.close_all()
60+
def release_thread_local_connections(logger: Logger, execution_timing: str):
61+
close_old_connections()
6262
if logger.level <= logging.DEBUG:
6363
current: Thread = current_thread()
6464
logger.debug(
65-
f"Released thread-bound DB connections (thread name: {current.name}, execution type: {execution_type})"
65+
"Released thread-bound old DB connections "
66+
f"(thread name: {current.name}, execution timing: {execution_timing})"
6667
)
6768

6869

@@ -73,7 +74,7 @@ class DjangoListenerCompletionHandler(ListenerCompletionHandler):
7374
"""
7475

7576
def handle(self, request: BoltRequest, response: Optional[BoltResponse]) -> None:
76-
release_thread_local_connections(request.context.logger, "listener")
77+
release_thread_local_connections(request.context.logger, "listener-completion")
7778

7879

7980
class DjangoThreadLazyListenerRunner(ThreadLazyListenerRunner):
@@ -89,7 +90,7 @@ def wrapped_func():
8990
func()
9091
finally:
9192
release_thread_local_connections(
92-
request.context.logger, "lazy-listener"
93+
request.context.logger, "lazy-listener-completion"
9394
)
9495

9596
self.executor.submit(wrapped_func)
@@ -120,14 +121,12 @@ def __init__(self, app: App): # type: ignore
120121
if current_completion_handler is not None and not isinstance(
121122
current_completion_handler, DefaultListenerCompletionHandler
122123
):
124+
# As we run release_thread_local_connections() before listener executions,
125+
# it's okay to skip calling the same connection clean-up method at the listener completion.
123126
message = """As you've already set app.listener_runner.listener_completion_handler to your own one,
124127
Bolt skipped to set it to slack_sdk.adapter.django.DjangoListenerCompletionHandler.
125-
We strongly recommend having the following lines of code in your listener_completion_handler:
126-
127-
from django.db import connections
128-
connections.close_all()
129128
"""
130-
self.app.logger.warning(message)
129+
self.app.logger.info(message)
131130
return
132131
# for proper management of thread-local Django DB connections
133132
self.app.listener_runner.listener_completion_handler = (
@@ -146,6 +145,13 @@ def handle(self, req: HttpRequest) -> HttpResponse:
146145
bolt_resp = oauth_flow.handle_callback(to_bolt_request(req))
147146
return to_django_response(bolt_resp)
148147
elif req.method == "POST":
148+
# As bolt-python utilizes threads for async `ack()` method execution,
149+
# we have to manually clean old/stale Django ORM connections bound to the "unmanaged" threads
150+
# Refer to https://github.com/slackapi/bolt-python/issues/280 for more details.
151+
release_thread_local_connections(
152+
self.app.logger, "before-listener-invocation"
153+
)
154+
# And then, run the App listener/lazy listener here
149155
bolt_resp: BoltResponse = self.app.dispatch(to_bolt_request(req))
150156
return to_django_response(bolt_resp)
151157

0 commit comments

Comments
 (0)