Skip to content

Commit e411385

Browse files
committed
version 1.10.0
1 parent 77db11f commit e411385

12 files changed

+794
-39
lines changed

docs/api-docs/slack_bolt/adapter/django/handler.html

Lines changed: 122 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ <h1 class="title">Module <code>slack_bolt.adapter.django.handler</code></h1>
3737
from slack_bolt.error import BoltError
3838
from slack_bolt.lazy_listener import ThreadLazyListenerRunner
3939
from slack_bolt.lazy_listener.internals import build_runnable_function
40+
from slack_bolt.listener.listener_start_handler import (
41+
ListenerStartHandler,
42+
DefaultListenerStartHandler,
43+
)
4044
from slack_bolt.listener.listener_completion_handler import (
4145
ListenerCompletionHandler,
4246
DefaultListenerCompletionHandler,
@@ -82,26 +86,37 @@ <h1 class="title">Module <code>slack_bolt.adapter.django.handler</code></h1>
8286
return resp
8387

8488

85-
from django.db import connections
89+
from django.db import close_old_connections
8690

8791

88-
def release_thread_local_connections(logger: Logger, execution_type: str):
89-
connections.close_all()
92+
def release_thread_local_connections(logger: Logger, execution_timing: str):
93+
close_old_connections()
9094
if logger.level &lt;= logging.DEBUG:
9195
current: Thread = current_thread()
9296
logger.debug(
93-
f&#34;Released thread-bound DB connections (thread name: {current.name}, execution type: {execution_type})&#34;
97+
&#34;Released thread-bound old DB connections &#34;
98+
f&#34;(thread name: {current.name}, execution timing: {execution_timing})&#34;
9499
)
95100

96101

102+
class DjangoListenerStartHandler(ListenerStartHandler):
103+
&#34;&#34;&#34;Django sets DB connections as a thread-local variable per thread.
104+
If the thread is not managed on the Django app side, the connections won&#39;t be released by Django.
105+
This handler releases the connections every time a ThreadListenerRunner execution completes.
106+
&#34;&#34;&#34;
107+
108+
def handle(self, request: BoltRequest, response: Optional[BoltResponse]) -&gt; None:
109+
release_thread_local_connections(request.context.logger, &#34;listener-start&#34;)
110+
111+
97112
class DjangoListenerCompletionHandler(ListenerCompletionHandler):
98113
&#34;&#34;&#34;Django sets DB connections as a thread-local variable per thread.
99114
If the thread is not managed on the Django app side, the connections won&#39;t be released by Django.
100115
This handler releases the connections every time a ThreadListenerRunner execution completes.
101116
&#34;&#34;&#34;
102117

103118
def handle(self, request: BoltRequest, response: Optional[BoltResponse]) -&gt; None:
104-
release_thread_local_connections(request.context.logger, &#34;listener&#34;)
119+
release_thread_local_connections(request.context.logger, &#34;listener-completion&#34;)
105120

106121

107122
class DjangoThreadLazyListenerRunner(ThreadLazyListenerRunner):
@@ -113,11 +128,14 @@ <h1 class="title">Module <code>slack_bolt.adapter.django.handler</code></h1>
113128
)
114129

115130
def wrapped_func():
131+
release_thread_local_connections(
132+
request.context.logger, &#34;before-lazy-listener&#34;
133+
)
116134
try:
117135
func()
118136
finally:
119137
release_thread_local_connections(
120-
request.context.logger, &#34;lazy-listener&#34;
138+
request.context.logger, &#34;lazy-listener-completion&#34;
121139
)
122140

123141
self.executor.submit(wrapped_func)
@@ -144,18 +162,39 @@ <h1 class="title">Module <code>slack_bolt.adapter.django.handler</code></h1>
144162
self.app.logger.debug(&#34;App.process_before_response is set to True&#34;)
145163
return
146164

165+
current_start_handler = listener_runner.listener_start_handler
166+
if current_start_handler is not None and not isinstance(
167+
current_start_handler, DefaultListenerStartHandler
168+
):
169+
# As we run release_thread_local_connections() before listener executions,
170+
# it&#39;s okay to skip calling the same connection clean-up method at the listener completion.
171+
message = &#34;&#34;&#34;As you&#39;ve already set app.listener_runner.listener_start_handler to your own one,
172+
Bolt skipped to set it to slack_sdk.adapter.django.DjangoListenerStartHandler.
173+
174+
If you go with your own handler here, we highly recommend having the following lines of code
175+
in your handle() method to clean up unmanaged stale/old database connections:
176+
177+
from django.db import close_old_connections
178+
close_old_connections()
179+
&#34;&#34;&#34;
180+
self.app.logger.info(message)
181+
else:
182+
# for proper management of thread-local Django DB connections
183+
self.app.listener_runner.listener_start_handler = (
184+
DjangoListenerStartHandler()
185+
)
186+
self.app.logger.debug(&#34;DjangoListenerStartHandler has been enabled&#34;)
187+
147188
current_completion_handler = listener_runner.listener_completion_handler
148189
if current_completion_handler is not None and not isinstance(
149190
current_completion_handler, DefaultListenerCompletionHandler
150191
):
192+
# As we run release_thread_local_connections() before listener executions,
193+
# it&#39;s okay to skip calling the same connection clean-up method at the listener completion.
151194
message = &#34;&#34;&#34;As you&#39;ve already set app.listener_runner.listener_completion_handler to your own one,
152195
Bolt skipped to set it to slack_sdk.adapter.django.DjangoListenerCompletionHandler.
153-
We strongly recommend having the following lines of code in your listener_completion_handler:
154-
155-
from django.db import connections
156-
connections.close_all()
157196
&#34;&#34;&#34;
158-
self.app.logger.warning(message)
197+
self.app.logger.info(message)
159198
return
160199
# for proper management of thread-local Django DB connections
161200
self.app.listener_runner.listener_completion_handler = (
@@ -188,20 +227,21 @@ <h1 class="title">Module <code>slack_bolt.adapter.django.handler</code></h1>
188227
<h2 class="section-title" id="header-functions">Functions</h2>
189228
<dl>
190229
<dt id="slack_bolt.adapter.django.handler.release_thread_local_connections"><code class="name flex">
191-
<span>def <span class="ident">release_thread_local_connections</span></span>(<span>logger: logging.Logger, execution_type: str)</span>
230+
<span>def <span class="ident">release_thread_local_connections</span></span>(<span>logger: logging.Logger, execution_timing: str)</span>
192231
</code></dt>
193232
<dd>
194233
<div class="desc"></div>
195234
<details class="source">
196235
<summary>
197236
<span>Expand source code</span>
198237
</summary>
199-
<pre><code class="python">def release_thread_local_connections(logger: Logger, execution_type: str):
200-
connections.close_all()
238+
<pre><code class="python">def release_thread_local_connections(logger: Logger, execution_timing: str):
239+
close_old_connections()
201240
if logger.level &lt;= logging.DEBUG:
202241
current: Thread = current_thread()
203242
logger.debug(
204-
f&#34;Released thread-bound DB connections (thread name: {current.name}, execution type: {execution_type})&#34;
243+
&#34;Released thread-bound old DB connections &#34;
244+
f&#34;(thread name: {current.name}, execution timing: {execution_timing})&#34;
205245
)</code></pre>
206246
</details>
207247
</dd>
@@ -281,7 +321,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
281321
&#34;&#34;&#34;
282322

283323
def handle(self, request: BoltRequest, response: Optional[BoltResponse]) -&gt; None:
284-
release_thread_local_connections(request.context.logger, &#34;listener&#34;)</code></pre>
324+
release_thread_local_connections(request.context.logger, &#34;listener-completion&#34;)</code></pre>
285325
</details>
286326
<h3>Ancestors</h3>
287327
<ul class="hlist">
@@ -296,6 +336,39 @@ <h3>Inherited members</h3>
296336
</li>
297337
</ul>
298338
</dd>
339+
<dt id="slack_bolt.adapter.django.handler.DjangoListenerStartHandler"><code class="flex name class">
340+
<span>class <span class="ident">DjangoListenerStartHandler</span></span>
341+
</code></dt>
342+
<dd>
343+
<div class="desc"><p>Django sets DB connections as a thread-local variable per thread.
344+
If the thread is not managed on the Django app side, the connections won't be released by Django.
345+
This handler releases the connections every time a ThreadListenerRunner execution completes.</p></div>
346+
<details class="source">
347+
<summary>
348+
<span>Expand source code</span>
349+
</summary>
350+
<pre><code class="python">class DjangoListenerStartHandler(ListenerStartHandler):
351+
&#34;&#34;&#34;Django sets DB connections as a thread-local variable per thread.
352+
If the thread is not managed on the Django app side, the connections won&#39;t be released by Django.
353+
This handler releases the connections every time a ThreadListenerRunner execution completes.
354+
&#34;&#34;&#34;
355+
356+
def handle(self, request: BoltRequest, response: Optional[BoltResponse]) -&gt; None:
357+
release_thread_local_connections(request.context.logger, &#34;listener-start&#34;)</code></pre>
358+
</details>
359+
<h3>Ancestors</h3>
360+
<ul class="hlist">
361+
<li><a title="slack_bolt.listener.listener_start_handler.ListenerStartHandler" href="../../listener/listener_start_handler.html#slack_bolt.listener.listener_start_handler.ListenerStartHandler">ListenerStartHandler</a></li>
362+
</ul>
363+
<h3>Inherited members</h3>
364+
<ul class="hlist">
365+
<li><code><b><a title="slack_bolt.listener.listener_start_handler.ListenerStartHandler" href="../../listener/listener_start_handler.html#slack_bolt.listener.listener_start_handler.ListenerStartHandler">ListenerStartHandler</a></b></code>:
366+
<ul class="hlist">
367+
<li><code><a title="slack_bolt.listener.listener_start_handler.ListenerStartHandler.handle" href="../../listener/listener_start_handler.html#slack_bolt.listener.listener_start_handler.ListenerStartHandler.handle">handle</a></code></li>
368+
</ul>
369+
</li>
370+
</ul>
371+
</dd>
299372
<dt id="slack_bolt.adapter.django.handler.DjangoThreadLazyListenerRunner"><code class="flex name class">
300373
<span>class <span class="ident">DjangoThreadLazyListenerRunner</span></span>
301374
<span>(</span><span>logger: logging.Logger, executor: concurrent.futures._base.Executor)</span>
@@ -315,11 +388,14 @@ <h3>Inherited members</h3>
315388
)
316389

317390
def wrapped_func():
391+
release_thread_local_connections(
392+
request.context.logger, &#34;before-lazy-listener&#34;
393+
)
318394
try:
319395
func()
320396
finally:
321397
release_thread_local_connections(
322-
request.context.logger, &#34;lazy-listener&#34;
398+
request.context.logger, &#34;lazy-listener-completion&#34;
323399
)
324400

325401
self.executor.submit(wrapped_func)</code></pre>
@@ -377,18 +453,39 @@ <h3>Inherited members</h3>
377453
self.app.logger.debug(&#34;App.process_before_response is set to True&#34;)
378454
return
379455

456+
current_start_handler = listener_runner.listener_start_handler
457+
if current_start_handler is not None and not isinstance(
458+
current_start_handler, DefaultListenerStartHandler
459+
):
460+
# As we run release_thread_local_connections() before listener executions,
461+
# it&#39;s okay to skip calling the same connection clean-up method at the listener completion.
462+
message = &#34;&#34;&#34;As you&#39;ve already set app.listener_runner.listener_start_handler to your own one,
463+
Bolt skipped to set it to slack_sdk.adapter.django.DjangoListenerStartHandler.
464+
465+
If you go with your own handler here, we highly recommend having the following lines of code
466+
in your handle() method to clean up unmanaged stale/old database connections:
467+
468+
from django.db import close_old_connections
469+
close_old_connections()
470+
&#34;&#34;&#34;
471+
self.app.logger.info(message)
472+
else:
473+
# for proper management of thread-local Django DB connections
474+
self.app.listener_runner.listener_start_handler = (
475+
DjangoListenerStartHandler()
476+
)
477+
self.app.logger.debug(&#34;DjangoListenerStartHandler has been enabled&#34;)
478+
380479
current_completion_handler = listener_runner.listener_completion_handler
381480
if current_completion_handler is not None and not isinstance(
382481
current_completion_handler, DefaultListenerCompletionHandler
383482
):
483+
# As we run release_thread_local_connections() before listener executions,
484+
# it&#39;s okay to skip calling the same connection clean-up method at the listener completion.
384485
message = &#34;&#34;&#34;As you&#39;ve already set app.listener_runner.listener_completion_handler to your own one,
385486
Bolt skipped to set it to slack_sdk.adapter.django.DjangoListenerCompletionHandler.
386-
We strongly recommend having the following lines of code in your listener_completion_handler:
387-
388-
from django.db import connections
389-
connections.close_all()
390487
&#34;&#34;&#34;
391-
self.app.logger.warning(message)
488+
self.app.logger.info(message)
392489
return
393490
# for proper management of thread-local Django DB connections
394491
self.app.listener_runner.listener_completion_handler = (
@@ -469,6 +566,9 @@ <h1>Index</h1>
469566
<h4><code><a title="slack_bolt.adapter.django.handler.DjangoListenerCompletionHandler" href="#slack_bolt.adapter.django.handler.DjangoListenerCompletionHandler">DjangoListenerCompletionHandler</a></code></h4>
470567
</li>
471568
<li>
569+
<h4><code><a title="slack_bolt.adapter.django.handler.DjangoListenerStartHandler" href="#slack_bolt.adapter.django.handler.DjangoListenerStartHandler">DjangoListenerStartHandler</a></code></h4>
570+
</li>
571+
<li>
472572
<h4><code><a title="slack_bolt.adapter.django.handler.DjangoThreadLazyListenerRunner" href="#slack_bolt.adapter.django.handler.DjangoThreadLazyListenerRunner">DjangoThreadLazyListenerRunner</a></code></h4>
473573
<ul class="">
474574
<li><code><a title="slack_bolt.adapter.django.handler.DjangoThreadLazyListenerRunner.logger" href="#slack_bolt.adapter.django.handler.DjangoThreadLazyListenerRunner.logger">logger</a></code></li>

docs/api-docs/slack_bolt/app/app.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ <h1 class="title">Module <code>slack_bolt.app.app</code></h1>
5151
from slack_bolt.listener.builtins import TokenRevocationListeners
5252
from slack_bolt.listener.custom_listener import CustomListener
5353
from slack_bolt.listener.listener import Listener
54+
from slack_bolt.listener.listener_start_handler import DefaultListenerStartHandler
5455
from slack_bolt.listener.listener_completion_handler import (
5556
DefaultListenerCompletionHandler,
5657
)
@@ -345,6 +346,9 @@ <h1 class="title">Module <code>slack_bolt.app.app</code></h1>
345346
listener_error_handler=DefaultListenerErrorHandler(
346347
logger=self._framework_logger
347348
),
349+
listener_start_handler=DefaultListenerStartHandler(
350+
logger=self._framework_logger
351+
),
348352
listener_completion_handler=DefaultListenerCompletionHandler(
349353
logger=self._framework_logger
350354
),
@@ -1807,6 +1811,9 @@ <h2 id="args">Args</h2>
18071811
listener_error_handler=DefaultListenerErrorHandler(
18081812
logger=self._framework_logger
18091813
),
1814+
listener_start_handler=DefaultListenerStartHandler(
1815+
logger=self._framework_logger
1816+
),
18101817
listener_completion_handler=DefaultListenerCompletionHandler(
18111818
logger=self._framework_logger
18121819
),

docs/api-docs/slack_bolt/app/async_app.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ <h1 class="title">Module <code>slack_bolt.app.async_app</code></h1>
3636

3737
from slack_bolt.app.async_server import AsyncSlackAppServer
3838
from slack_bolt.listener.async_builtins import AsyncTokenRevocationListeners
39+
from slack_bolt.listener.async_listener_start_handler import (
40+
AsyncDefaultListenerStartHandler,
41+
)
3942
from slack_bolt.listener.async_listener_completion_handler import (
4043
AsyncDefaultListenerCompletionHandler,
4144
)
@@ -365,6 +368,9 @@ <h1 class="title">Module <code>slack_bolt.app.async_app</code></h1>
365368
listener_error_handler=AsyncDefaultListenerErrorHandler(
366369
logger=self._framework_logger
367370
),
371+
listener_start_handler=AsyncDefaultListenerStartHandler(
372+
logger=self._framework_logger
373+
),
368374
listener_completion_handler=AsyncDefaultListenerCompletionHandler(
369375
logger=self._framework_logger
370376
),
@@ -1753,6 +1759,9 @@ <h2 id="args">Args</h2>
17531759
listener_error_handler=AsyncDefaultListenerErrorHandler(
17541760
logger=self._framework_logger
17551761
),
1762+
listener_start_handler=AsyncDefaultListenerStartHandler(
1763+
logger=self._framework_logger
1764+
),
17561765
listener_completion_handler=AsyncDefaultListenerCompletionHandler(
17571766
logger=self._framework_logger
17581767
),

docs/api-docs/slack_bolt/listener/async_listener_completion_handler.html

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@ <h1 class="title">Module <code>slack_bolt.listener.async_listener_completion_han
4343
request: AsyncBoltRequest,
4444
response: Optional[BoltResponse],
4545
) -&gt; None:
46-
&#34;&#34;&#34;Handles an unhandled exception.
46+
&#34;&#34;&#34;Do something extra after the listener execution
4747

4848
Args:
49-
error: The raised exception.
5049
request: The request.
5150
response: The response.
5251
&#34;&#34;&#34;
@@ -188,10 +187,9 @@ <h3>Inherited members</h3>
188187
request: AsyncBoltRequest,
189188
response: Optional[BoltResponse],
190189
) -&gt; None:
191-
&#34;&#34;&#34;Handles an unhandled exception.
190+
&#34;&#34;&#34;Do something extra after the listener execution
192191

193192
Args:
194-
error: The raised exception.
195193
request: The request.
196194
response: The response.
197195
&#34;&#34;&#34;
@@ -208,11 +206,9 @@ <h3>Methods</h3>
208206
<span>async def <span class="ident">handle</span></span>(<span>self, request: <a title="slack_bolt.request.async_request.AsyncBoltRequest" href="../request/async_request.html#slack_bolt.request.async_request.AsyncBoltRequest">AsyncBoltRequest</a>, response: Optional[<a title="slack_bolt.response.response.BoltResponse" href="../response/response.html#slack_bolt.response.response.BoltResponse">BoltResponse</a>]) ‑> None</span>
209207
</code></dt>
210208
<dd>
211-
<div class="desc"><p>Handles an unhandled exception.</p>
209+
<div class="desc"><p>Do something extra after the listener execution</p>
212210
<h2 id="args">Args</h2>
213211
<dl>
214-
<dt><strong><code>error</code></strong></dt>
215-
<dd>The raised exception.</dd>
216212
<dt><strong><code>request</code></strong></dt>
217213
<dd>The request.</dd>
218214
<dt><strong><code>response</code></strong></dt>
@@ -228,10 +224,9 @@ <h2 id="args">Args</h2>
228224
request: AsyncBoltRequest,
229225
response: Optional[BoltResponse],
230226
) -&gt; None:
231-
&#34;&#34;&#34;Handles an unhandled exception.
227+
&#34;&#34;&#34;Do something extra after the listener execution
232228

233229
Args:
234-
error: The raised exception.
235230
request: The request.
236231
response: The response.
237232
&#34;&#34;&#34;

0 commit comments

Comments
 (0)