Skip to content

Commit

Permalink
version 1.10.0
Browse files Browse the repository at this point in the history
  • Loading branch information
seratch committed Nov 4, 2021
1 parent 77db11f commit e411385
Show file tree
Hide file tree
Showing 12 changed files with 794 additions and 39 deletions.
144 changes: 122 additions & 22 deletions docs/api-docs/slack_bolt/adapter/django/handler.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ <h1 class="title">Module <code>slack_bolt.adapter.django.handler</code></h1>
from slack_bolt.error import BoltError
from slack_bolt.lazy_listener import ThreadLazyListenerRunner
from slack_bolt.lazy_listener.internals import build_runnable_function
from slack_bolt.listener.listener_start_handler import (
ListenerStartHandler,
DefaultListenerStartHandler,
)
from slack_bolt.listener.listener_completion_handler import (
ListenerCompletionHandler,
DefaultListenerCompletionHandler,
Expand Down Expand Up @@ -82,26 +86,37 @@ <h1 class="title">Module <code>slack_bolt.adapter.django.handler</code></h1>
return resp


from django.db import connections
from django.db import close_old_connections


def release_thread_local_connections(logger: Logger, execution_type: str):
connections.close_all()
def release_thread_local_connections(logger: Logger, execution_timing: str):
close_old_connections()
if logger.level &lt;= logging.DEBUG:
current: Thread = current_thread()
logger.debug(
f&#34;Released thread-bound DB connections (thread name: {current.name}, execution type: {execution_type})&#34;
&#34;Released thread-bound old DB connections &#34;
f&#34;(thread name: {current.name}, execution timing: {execution_timing})&#34;
)


class DjangoListenerStartHandler(ListenerStartHandler):
&#34;&#34;&#34;Django sets DB connections as a thread-local variable per thread.
If the thread is not managed on the Django app side, the connections won&#39;t be released by Django.
This handler releases the connections every time a ThreadListenerRunner execution completes.
&#34;&#34;&#34;

def handle(self, request: BoltRequest, response: Optional[BoltResponse]) -&gt; None:
release_thread_local_connections(request.context.logger, &#34;listener-start&#34;)


class DjangoListenerCompletionHandler(ListenerCompletionHandler):
&#34;&#34;&#34;Django sets DB connections as a thread-local variable per thread.
If the thread is not managed on the Django app side, the connections won&#39;t be released by Django.
This handler releases the connections every time a ThreadListenerRunner execution completes.
&#34;&#34;&#34;

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


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

def wrapped_func():
release_thread_local_connections(
request.context.logger, &#34;before-lazy-listener&#34;
)
try:
func()
finally:
release_thread_local_connections(
request.context.logger, &#34;lazy-listener&#34;
request.context.logger, &#34;lazy-listener-completion&#34;
)

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

current_start_handler = listener_runner.listener_start_handler
if current_start_handler is not None and not isinstance(
current_start_handler, DefaultListenerStartHandler
):
# As we run release_thread_local_connections() before listener executions,
# it&#39;s okay to skip calling the same connection clean-up method at the listener completion.
message = &#34;&#34;&#34;As you&#39;ve already set app.listener_runner.listener_start_handler to your own one,
Bolt skipped to set it to slack_sdk.adapter.django.DjangoListenerStartHandler.

If you go with your own handler here, we highly recommend having the following lines of code
in your handle() method to clean up unmanaged stale/old database connections:

from django.db import close_old_connections
close_old_connections()
&#34;&#34;&#34;
self.app.logger.info(message)
else:
# for proper management of thread-local Django DB connections
self.app.listener_runner.listener_start_handler = (
DjangoListenerStartHandler()
)
self.app.logger.debug(&#34;DjangoListenerStartHandler has been enabled&#34;)

current_completion_handler = listener_runner.listener_completion_handler
if current_completion_handler is not None and not isinstance(
current_completion_handler, DefaultListenerCompletionHandler
):
# As we run release_thread_local_connections() before listener executions,
# it&#39;s okay to skip calling the same connection clean-up method at the listener completion.
message = &#34;&#34;&#34;As you&#39;ve already set app.listener_runner.listener_completion_handler to your own one,
Bolt skipped to set it to slack_sdk.adapter.django.DjangoListenerCompletionHandler.
We strongly recommend having the following lines of code in your listener_completion_handler:

from django.db import connections
connections.close_all()
&#34;&#34;&#34;
self.app.logger.warning(message)
self.app.logger.info(message)
return
# for proper management of thread-local Django DB connections
self.app.listener_runner.listener_completion_handler = (
Expand Down Expand Up @@ -188,20 +227,21 @@ <h1 class="title">Module <code>slack_bolt.adapter.django.handler</code></h1>
<h2 class="section-title" id="header-functions">Functions</h2>
<dl>
<dt id="slack_bolt.adapter.django.handler.release_thread_local_connections"><code class="name flex">
<span>def <span class="ident">release_thread_local_connections</span></span>(<span>logger: logging.Logger, execution_type: str)</span>
<span>def <span class="ident">release_thread_local_connections</span></span>(<span>logger: logging.Logger, execution_timing: str)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def release_thread_local_connections(logger: Logger, execution_type: str):
connections.close_all()
<pre><code class="python">def release_thread_local_connections(logger: Logger, execution_timing: str):
close_old_connections()
if logger.level &lt;= logging.DEBUG:
current: Thread = current_thread()
logger.debug(
f&#34;Released thread-bound DB connections (thread name: {current.name}, execution type: {execution_type})&#34;
&#34;Released thread-bound old DB connections &#34;
f&#34;(thread name: {current.name}, execution timing: {execution_timing})&#34;
)</code></pre>
</details>
</dd>
Expand Down Expand Up @@ -281,7 +321,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
&#34;&#34;&#34;

def handle(self, request: BoltRequest, response: Optional[BoltResponse]) -&gt; None:
release_thread_local_connections(request.context.logger, &#34;listener&#34;)</code></pre>
release_thread_local_connections(request.context.logger, &#34;listener-completion&#34;)</code></pre>
</details>
<h3>Ancestors</h3>
<ul class="hlist">
Expand All @@ -296,6 +336,39 @@ <h3>Inherited members</h3>
</li>
</ul>
</dd>
<dt id="slack_bolt.adapter.django.handler.DjangoListenerStartHandler"><code class="flex name class">
<span>class <span class="ident">DjangoListenerStartHandler</span></span>
</code></dt>
<dd>
<div class="desc"><p>Django sets DB connections as a thread-local variable per thread.
If the thread is not managed on the Django app side, the connections won't be released by Django.
This handler releases the connections every time a ThreadListenerRunner execution completes.</p></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">class DjangoListenerStartHandler(ListenerStartHandler):
&#34;&#34;&#34;Django sets DB connections as a thread-local variable per thread.
If the thread is not managed on the Django app side, the connections won&#39;t be released by Django.
This handler releases the connections every time a ThreadListenerRunner execution completes.
&#34;&#34;&#34;

def handle(self, request: BoltRequest, response: Optional[BoltResponse]) -&gt; None:
release_thread_local_connections(request.context.logger, &#34;listener-start&#34;)</code></pre>
</details>
<h3>Ancestors</h3>
<ul class="hlist">
<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>
</ul>
<h3>Inherited members</h3>
<ul class="hlist">
<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>:
<ul class="hlist">
<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>
</ul>
</li>
</ul>
</dd>
<dt id="slack_bolt.adapter.django.handler.DjangoThreadLazyListenerRunner"><code class="flex name class">
<span>class <span class="ident">DjangoThreadLazyListenerRunner</span></span>
<span>(</span><span>logger: logging.Logger, executor: concurrent.futures._base.Executor)</span>
Expand All @@ -315,11 +388,14 @@ <h3>Inherited members</h3>
)

def wrapped_func():
release_thread_local_connections(
request.context.logger, &#34;before-lazy-listener&#34;
)
try:
func()
finally:
release_thread_local_connections(
request.context.logger, &#34;lazy-listener&#34;
request.context.logger, &#34;lazy-listener-completion&#34;
)

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

current_start_handler = listener_runner.listener_start_handler
if current_start_handler is not None and not isinstance(
current_start_handler, DefaultListenerStartHandler
):
# As we run release_thread_local_connections() before listener executions,
# it&#39;s okay to skip calling the same connection clean-up method at the listener completion.
message = &#34;&#34;&#34;As you&#39;ve already set app.listener_runner.listener_start_handler to your own one,
Bolt skipped to set it to slack_sdk.adapter.django.DjangoListenerStartHandler.

If you go with your own handler here, we highly recommend having the following lines of code
in your handle() method to clean up unmanaged stale/old database connections:

from django.db import close_old_connections
close_old_connections()
&#34;&#34;&#34;
self.app.logger.info(message)
else:
# for proper management of thread-local Django DB connections
self.app.listener_runner.listener_start_handler = (
DjangoListenerStartHandler()
)
self.app.logger.debug(&#34;DjangoListenerStartHandler has been enabled&#34;)

current_completion_handler = listener_runner.listener_completion_handler
if current_completion_handler is not None and not isinstance(
current_completion_handler, DefaultListenerCompletionHandler
):
# As we run release_thread_local_connections() before listener executions,
# it&#39;s okay to skip calling the same connection clean-up method at the listener completion.
message = &#34;&#34;&#34;As you&#39;ve already set app.listener_runner.listener_completion_handler to your own one,
Bolt skipped to set it to slack_sdk.adapter.django.DjangoListenerCompletionHandler.
We strongly recommend having the following lines of code in your listener_completion_handler:

from django.db import connections
connections.close_all()
&#34;&#34;&#34;
self.app.logger.warning(message)
self.app.logger.info(message)
return
# for proper management of thread-local Django DB connections
self.app.listener_runner.listener_completion_handler = (
Expand Down Expand Up @@ -469,6 +566,9 @@ <h1>Index</h1>
<h4><code><a title="slack_bolt.adapter.django.handler.DjangoListenerCompletionHandler" href="#slack_bolt.adapter.django.handler.DjangoListenerCompletionHandler">DjangoListenerCompletionHandler</a></code></h4>
</li>
<li>
<h4><code><a title="slack_bolt.adapter.django.handler.DjangoListenerStartHandler" href="#slack_bolt.adapter.django.handler.DjangoListenerStartHandler">DjangoListenerStartHandler</a></code></h4>
</li>
<li>
<h4><code><a title="slack_bolt.adapter.django.handler.DjangoThreadLazyListenerRunner" href="#slack_bolt.adapter.django.handler.DjangoThreadLazyListenerRunner">DjangoThreadLazyListenerRunner</a></code></h4>
<ul class="">
<li><code><a title="slack_bolt.adapter.django.handler.DjangoThreadLazyListenerRunner.logger" href="#slack_bolt.adapter.django.handler.DjangoThreadLazyListenerRunner.logger">logger</a></code></li>
Expand Down
7 changes: 7 additions & 0 deletions docs/api-docs/slack_bolt/app/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ <h1 class="title">Module <code>slack_bolt.app.app</code></h1>
from slack_bolt.listener.builtins import TokenRevocationListeners
from slack_bolt.listener.custom_listener import CustomListener
from slack_bolt.listener.listener import Listener
from slack_bolt.listener.listener_start_handler import DefaultListenerStartHandler
from slack_bolt.listener.listener_completion_handler import (
DefaultListenerCompletionHandler,
)
Expand Down Expand Up @@ -345,6 +346,9 @@ <h1 class="title">Module <code>slack_bolt.app.app</code></h1>
listener_error_handler=DefaultListenerErrorHandler(
logger=self._framework_logger
),
listener_start_handler=DefaultListenerStartHandler(
logger=self._framework_logger
),
listener_completion_handler=DefaultListenerCompletionHandler(
logger=self._framework_logger
),
Expand Down Expand Up @@ -1807,6 +1811,9 @@ <h2 id="args">Args</h2>
listener_error_handler=DefaultListenerErrorHandler(
logger=self._framework_logger
),
listener_start_handler=DefaultListenerStartHandler(
logger=self._framework_logger
),
listener_completion_handler=DefaultListenerCompletionHandler(
logger=self._framework_logger
),
Expand Down
9 changes: 9 additions & 0 deletions docs/api-docs/slack_bolt/app/async_app.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ <h1 class="title">Module <code>slack_bolt.app.async_app</code></h1>

from slack_bolt.app.async_server import AsyncSlackAppServer
from slack_bolt.listener.async_builtins import AsyncTokenRevocationListeners
from slack_bolt.listener.async_listener_start_handler import (
AsyncDefaultListenerStartHandler,
)
from slack_bolt.listener.async_listener_completion_handler import (
AsyncDefaultListenerCompletionHandler,
)
Expand Down Expand Up @@ -365,6 +368,9 @@ <h1 class="title">Module <code>slack_bolt.app.async_app</code></h1>
listener_error_handler=AsyncDefaultListenerErrorHandler(
logger=self._framework_logger
),
listener_start_handler=AsyncDefaultListenerStartHandler(
logger=self._framework_logger
),
listener_completion_handler=AsyncDefaultListenerCompletionHandler(
logger=self._framework_logger
),
Expand Down Expand Up @@ -1753,6 +1759,9 @@ <h2 id="args">Args</h2>
listener_error_handler=AsyncDefaultListenerErrorHandler(
logger=self._framework_logger
),
listener_start_handler=AsyncDefaultListenerStartHandler(
logger=self._framework_logger
),
listener_completion_handler=AsyncDefaultListenerCompletionHandler(
logger=self._framework_logger
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,9 @@ <h1 class="title">Module <code>slack_bolt.listener.async_listener_completion_han
request: AsyncBoltRequest,
response: Optional[BoltResponse],
) -&gt; None:
&#34;&#34;&#34;Handles an unhandled exception.
&#34;&#34;&#34;Do something extra after the listener execution

Args:
error: The raised exception.
request: The request.
response: The response.
&#34;&#34;&#34;
Expand Down Expand Up @@ -188,10 +187,9 @@ <h3>Inherited members</h3>
request: AsyncBoltRequest,
response: Optional[BoltResponse],
) -&gt; None:
&#34;&#34;&#34;Handles an unhandled exception.
&#34;&#34;&#34;Do something extra after the listener execution

Args:
error: The raised exception.
request: The request.
response: The response.
&#34;&#34;&#34;
Expand All @@ -208,11 +206,9 @@ <h3>Methods</h3>
<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>
</code></dt>
<dd>
<div class="desc"><p>Handles an unhandled exception.</p>
<div class="desc"><p>Do something extra after the listener execution</p>
<h2 id="args">Args</h2>
<dl>
<dt><strong><code>error</code></strong></dt>
<dd>The raised exception.</dd>
<dt><strong><code>request</code></strong></dt>
<dd>The request.</dd>
<dt><strong><code>response</code></strong></dt>
Expand All @@ -228,10 +224,9 @@ <h2 id="args">Args</h2>
request: AsyncBoltRequest,
response: Optional[BoltResponse],
) -&gt; None:
&#34;&#34;&#34;Handles an unhandled exception.
&#34;&#34;&#34;Do something extra after the listener execution

Args:
error: The raised exception.
request: The request.
response: The response.
&#34;&#34;&#34;
Expand Down
Loading

0 comments on commit e411385

Please sign in to comment.