Skip to content

Commit 6684df6

Browse files
Allow a custom Executor in App (#453)
Co-authored-by: Kazuhiro Sera <[email protected]>
1 parent 1272f89 commit 6684df6

File tree

4 files changed

+31
-6
lines changed

4 files changed

+31
-6
lines changed

slack_bolt/app/app.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44
import os
55
import time
6+
from concurrent.futures import Executor
67
from concurrent.futures.thread import ThreadPoolExecutor
78
from http.server import SimpleHTTPRequestHandler, HTTPServer
89
from typing import List, Union, Pattern, Callable, Dict, Optional, Sequence, Any
@@ -113,6 +114,8 @@ def __init__(
113114
oauth_flow: Optional[OAuthFlow] = None,
114115
# No need to set (the value is used only in response to ssl_check requests)
115116
verification_token: Optional[str] = None,
117+
# Set this one only when you want to customize the executor
118+
listener_executor: Optional[Executor] = None,
116119
):
117120
"""Bolt App that provides functionalities to register middleware/listeners.
118121
@@ -173,6 +176,8 @@ def message_hello(message, say):
173176
oauth_settings: The settings related to Slack app installation flow (OAuth flow)
174177
oauth_flow: Instantiated `slack_bolt.oauth.OAuthFlow`. This is always prioritized over oauth_settings.
175178
verification_token: Deprecated verification mechanism. This can used only for ssl_check requests.
179+
listener_executor: Custom executor to run background tasks. If absent, the default `ThreadPoolExecutor` will
180+
be used.
176181
"""
177182
signing_secret = signing_secret or os.environ.get("SLACK_SIGNING_SECRET")
178183
token = token or os.environ.get("SLACK_BOT_TOKEN")
@@ -302,7 +307,9 @@ def message_hello(message, say):
302307
self._middleware_list: List[Union[Callable, Middleware]] = []
303308
self._listeners: List[Listener] = []
304309

305-
listener_executor = ThreadPoolExecutor(max_workers=5)
310+
if listener_executor is None:
311+
listener_executor = ThreadPoolExecutor(max_workers=5)
312+
306313
self._process_before_response = process_before_response
307314
self._listener_runner = ThreadListenerRunner(
308315
logger=self._framework_logger,

slack_bolt/lazy_listener/thread_runner.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from concurrent.futures.thread import ThreadPoolExecutor
1+
from concurrent.futures import Executor
22
from logging import Logger
33
from typing import Callable
44

@@ -13,7 +13,7 @@ class ThreadLazyListenerRunner(LazyListenerRunner):
1313
def __init__(
1414
self,
1515
logger: Logger,
16-
executor: ThreadPoolExecutor,
16+
executor: Executor,
1717
):
1818
self.logger = logger
1919
self.executor = executor

slack_bolt/listener/thread_runner.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import time
2-
from concurrent.futures.thread import ThreadPoolExecutor
2+
from concurrent.futures import Executor
33
from logging import Logger
44
from typing import Optional, Callable
55

@@ -22,7 +22,7 @@ class ThreadListenerRunner:
2222
process_before_response: bool
2323
listener_error_handler: ListenerErrorHandler
2424
listener_completion_handler: ListenerCompletionHandler
25-
listener_executor: ThreadPoolExecutor
25+
listener_executor: Executor
2626
lazy_listener_runner: LazyListenerRunner
2727

2828
def __init__(
@@ -31,7 +31,7 @@ def __init__(
3131
process_before_response: bool,
3232
listener_error_handler: ListenerErrorHandler,
3333
listener_completion_handler: ListenerCompletionHandler,
34-
listener_executor: ThreadPoolExecutor,
34+
listener_executor: Executor,
3535
lazy_listener_runner: LazyListenerRunner,
3636
):
3737
self.logger = logger

tests/scenario_tests/test_app.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from concurrent.futures import Executor
2+
13
import pytest
24
from slack_sdk import WebClient
35
from slack_sdk.oauth.installation_store import FileInstallationStore
@@ -56,6 +58,22 @@ def test_listener_registration_error(self):
5658
with pytest.raises(BoltError):
5759
app.action({"type": "invalid_type", "action_id": "a"})(self.simple_listener)
5860

61+
def test_listener_executor(self):
62+
class TestExecutor(Executor):
63+
"""A executor that does nothing for testing"""
64+
65+
pass
66+
67+
executor = TestExecutor()
68+
app = App(
69+
signing_secret="valid",
70+
client=self.web_client,
71+
listener_executor=executor,
72+
)
73+
74+
assert app.listener_runner.listener_executor == executor
75+
assert app.listener_runner.lazy_listener_runner.executor == executor
76+
5977
# --------------------------
6078
# single team auth
6179
# --------------------------

0 commit comments

Comments
 (0)