@@ -1240,23 +1240,27 @@ def enable_token_revocation_listeners(self) -> None:
12401240 def _init_context (self , req : AsyncBoltRequest ):
12411241 req .context ["logger" ] = get_bolt_app_logger (app_name = self .name , base_logger = self ._base_logger )
12421242 req .context ["token" ] = self ._token
1243- if self ._token is not None :
1244- # This AsyncWebClient instance can be safely singleton
1245- req .context ["client" ] = self ._async_client
1246- else :
1247- # Set a new dedicated instance for this request
1248- client_per_request : AsyncWebClient = AsyncWebClient (
1249- token = None , # the token will be set later
1250- base_url = self ._async_client .base_url ,
1251- timeout = self ._async_client .timeout ,
1252- ssl = self ._async_client .ssl ,
1253- proxy = self ._async_client .proxy ,
1254- session = self ._async_client .session ,
1255- trust_env_in_session = self ._async_client .trust_env_in_session ,
1256- headers = self ._async_client .headers ,
1257- team_id = req .context .team_id ,
1258- )
1259- req .context ["client" ] = client_per_request
1243+ # Prior to version 1.15, when the token is static, self._client was passed to `req.context`.
1244+ # The intention was to avoid creating a new instance per request
1245+ # in the interest of runtime performance/memory footprint optimization.
1246+ # However, developers may want to replace the token held by req.context.client in some situations.
1247+ # In this case, this behavior can result in thread-unsafe data modification on `self._client`.
1248+ # (`self._client` a.k.a. `app.client` is a singleton object per an App instance)
1249+ # Thus, we've changed the behavior to create a new instance per request regardless of token argument
1250+ # in the App initialization starting v1.15.
1251+ # The overhead brought by this change is slight so that we believe that it is ignorable in any cases.
1252+ client_per_request : AsyncWebClient = AsyncWebClient (
1253+ token = self ._token , # this can be None, and it can be set later on
1254+ base_url = self ._async_client .base_url ,
1255+ timeout = self ._async_client .timeout ,
1256+ ssl = self ._async_client .ssl ,
1257+ proxy = self ._async_client .proxy ,
1258+ session = self ._async_client .session ,
1259+ trust_env_in_session = self ._async_client .trust_env_in_session ,
1260+ headers = self ._async_client .headers ,
1261+ team_id = req .context .team_id ,
1262+ )
1263+ req .context ["client" ] = client_per_request
12601264
12611265 @staticmethod
12621266 def _to_listener_functions (
0 commit comments