Skip to content

Commit

Permalink
Allow a custom Executor in App (#453)
Browse files Browse the repository at this point in the history
Co-authored-by: Kazuhiro Sera <seratch@gmail.com>
  • Loading branch information
chrisbouchard and seratch committed Aug 29, 2021
1 parent 1272f89 commit 6684df6
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 6 deletions.
9 changes: 8 additions & 1 deletion slack_bolt/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
import os
import time
from concurrent.futures import Executor
from concurrent.futures.thread import ThreadPoolExecutor
from http.server import SimpleHTTPRequestHandler, HTTPServer
from typing import List, Union, Pattern, Callable, Dict, Optional, Sequence, Any
Expand Down Expand Up @@ -113,6 +114,8 @@ def __init__(
oauth_flow: Optional[OAuthFlow] = None,
# No need to set (the value is used only in response to ssl_check requests)
verification_token: Optional[str] = None,
# Set this one only when you want to customize the executor
listener_executor: Optional[Executor] = None,
):
"""Bolt App that provides functionalities to register middleware/listeners.
Expand Down Expand Up @@ -173,6 +176,8 @@ def message_hello(message, say):
oauth_settings: The settings related to Slack app installation flow (OAuth flow)
oauth_flow: Instantiated `slack_bolt.oauth.OAuthFlow`. This is always prioritized over oauth_settings.
verification_token: Deprecated verification mechanism. This can used only for ssl_check requests.
listener_executor: Custom executor to run background tasks. If absent, the default `ThreadPoolExecutor` will
be used.
"""
signing_secret = signing_secret or os.environ.get("SLACK_SIGNING_SECRET")
token = token or os.environ.get("SLACK_BOT_TOKEN")
Expand Down Expand Up @@ -302,7 +307,9 @@ def message_hello(message, say):
self._middleware_list: List[Union[Callable, Middleware]] = []
self._listeners: List[Listener] = []

listener_executor = ThreadPoolExecutor(max_workers=5)
if listener_executor is None:
listener_executor = ThreadPoolExecutor(max_workers=5)

self._process_before_response = process_before_response
self._listener_runner = ThreadListenerRunner(
logger=self._framework_logger,
Expand Down
4 changes: 2 additions & 2 deletions slack_bolt/lazy_listener/thread_runner.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from concurrent.futures.thread import ThreadPoolExecutor
from concurrent.futures import Executor
from logging import Logger
from typing import Callable

Expand All @@ -13,7 +13,7 @@ class ThreadLazyListenerRunner(LazyListenerRunner):
def __init__(
self,
logger: Logger,
executor: ThreadPoolExecutor,
executor: Executor,
):
self.logger = logger
self.executor = executor
Expand Down
6 changes: 3 additions & 3 deletions slack_bolt/listener/thread_runner.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import time
from concurrent.futures.thread import ThreadPoolExecutor
from concurrent.futures import Executor
from logging import Logger
from typing import Optional, Callable

Expand All @@ -22,7 +22,7 @@ class ThreadListenerRunner:
process_before_response: bool
listener_error_handler: ListenerErrorHandler
listener_completion_handler: ListenerCompletionHandler
listener_executor: ThreadPoolExecutor
listener_executor: Executor
lazy_listener_runner: LazyListenerRunner

def __init__(
Expand All @@ -31,7 +31,7 @@ def __init__(
process_before_response: bool,
listener_error_handler: ListenerErrorHandler,
listener_completion_handler: ListenerCompletionHandler,
listener_executor: ThreadPoolExecutor,
listener_executor: Executor,
lazy_listener_runner: LazyListenerRunner,
):
self.logger = logger
Expand Down
18 changes: 18 additions & 0 deletions tests/scenario_tests/test_app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from concurrent.futures import Executor

import pytest
from slack_sdk import WebClient
from slack_sdk.oauth.installation_store import FileInstallationStore
Expand Down Expand Up @@ -56,6 +58,22 @@ def test_listener_registration_error(self):
with pytest.raises(BoltError):
app.action({"type": "invalid_type", "action_id": "a"})(self.simple_listener)

def test_listener_executor(self):
class TestExecutor(Executor):
"""A executor that does nothing for testing"""

pass

executor = TestExecutor()
app = App(
signing_secret="valid",
client=self.web_client,
listener_executor=executor,
)

assert app.listener_runner.listener_executor == executor
assert app.listener_runner.lazy_listener_runner.executor == executor

# --------------------------
# single team auth
# --------------------------
Expand Down

0 comments on commit 6684df6

Please sign in to comment.