slackapi/python-slack-sdk

thread safety of WebClient

baryluk opened this issue · 6 comments

It could not find any documentation about thread safety of sdk components.

Can I safely use a single slack_sdk.web.WebClient instance (initialized in main thread for example) from multiple threads (i.e. each calling sc.chat_postMessage concurrently)? Or do I need to protect it with a lock, or alternatively use separate instance for each thread?

Also, if the answer to the first question is yes, it is thread-safe and internally synchronized, are messages serialized, and possibly lead to queuing, should I use maybe pool of WebClients to hide some network and RPC latency?

I did find this discussion #508 , but no details or real resolution there either.

Hi @baryluk, thanks for asking the question. Since WebClient is a simple Web API caller, it does not have any internal state and cached data such as channel messages. Thus, it is completely thread-safe. As for #508, it is a past issue that existed in v2 series (the implementation of the class at that time was not optimal). No need to worry about it. Is everything clear now?

So like Tcp/Ssl sockets to Slack servers are not even stored in WebClient and recreated on each API call? Or it relies on some other library (like requests / urrlib3 to at least do some connection pooling)?

It's just a stateless HTTP client. As you can see here, the WebClient simply relies on urllib, a built-in HTTP module within Python runtime. It's quite simple. No connection polling.

@seratch Thanks. Looking into the code, it has same threading guarantees as urllib.urlopen (and SSLContext if ssl custom context is used, but these are thread safe anyway). The only other requirement is that the logger used is thread safe, but the default one is thread safe.

Also default retry handlers (which is just connection error retry?) looks to be thread safe.

But RateLimitErrorRetryHandler appears to me to not be thread safe.

The retry handler performs retries only when an HTTP response includes a retry-after response header, which indicates the number of seconds to wait before a retry. The number of concurrent API calls is indeed shared among WebClient instances in your app. I wouldn't call it thread-unsafe (in terms of Python coding), but it's indeed shared among API clients.

If you're considering executing a large number of similar API calls in a short timeframe, I recommend managing the frequency in some way. Our Java SDK offers a sophisticated rate limiter (https://slack.dev/java-slack-sdk/guides/web-api-basics#rate-limits), however, this feature is not available in our Python SDK. Therefore, you'll need to implement something similar on your own, if necessary.

Since I am in a different timezone (+09:00), I will be offline for a while. If everything is clear now, please close this issue now. I hope this was helpful to you!

@seratch Thanks a lot for the help.

I do not plan to send large number of API calls, but in my app there might be periods of very little traffic for hours, but maybe once a day there might be some spike of messages. This is used for some automated alerting, and was wondering about reliability of various components.

I think you answered all my questions adequately.

Might be worth adding a note to web client class doc string about thread safety.