The bot functions as expected while the Cloud Function is warm, but from a cold start more often that not Slack will show a timeout message as the bot does not respond within the expected 3 seconds.
The user experience is:
- ✅ a request to the bot
- ❌ a timeout message from Slack
- ✅ the response from the bot
Result: Confused user 😕
While this does not end in a failed result, it does not do any favours for user confidence in the bot and will generate a lot of noise from users checking if the bot is working, or worst case, avoidance as it appears to be unreliable.
First investigations into the Python code resulted in deferred loading of the
random module, moving it inside of the thread that is created so it is loaded on demand. This did not improve the cold start time enough to provide the required response time. Logically this makes sense — by the time code execution has reached the point of handling the request, a cold start would have already have been invoked.
It would be possible to set up a Cloud Scheduler job to periodically query the bot to ensure it’s always in a warm state but that effectively defeats the purpose of a serverless function and results in a general sense of annoyance akin to a dripping tap.
Onward to version 2 of the bot, which is split into two major components:
goCloud Function — receives the request from Slack and responds quickly then forwards request to the slash command handler
pythonCloud Function — handles and responds to the slash command
The first half of the bot is based on the information from this Google tutorial which implements a Slack slash handler in Go. The second half is a slightly less complicated version of the original python bot as some of the handling and verification is implemented in the
The important first step in this
go code section is to send a
200 response back to Slack. This section also implements the preferred Slack Request verification via signed secrets. The request is repackaged into another
POST request with an OAuth token attached to be sent to the
python code section to handle.
python function is no longer available to unauthenticated users which necessitates the presence of an OAuth token. Additionally no configuration information has been packaged with the function. The required configuration information is now expected to be passed in via the
POST request, being the URLs for the
- Follow the steps above to create the Slack app and enable incoming webhooks. From the Slack App Basic Information copy the Signing Secret to update the
gobotween. Additionally use the webhook url to populate the
2. Initialise gcloud as required for the target project and then deploy both of the Cloud Functions.
Python Cloud Function:
gcloud functions deploy hello_bot --runtime python37 —-trigger-http
Go Cloud Function:
- Use the url created for the
pythonfunction just deployed to update the
gcloud functions deploy Gobotween --runtime go111 —-trigger-http
3. Update the
Gobotween function permissions to grant
allUsers the Cloud Functions Invoker role. This makes the function publicly available to be invoked from Slack:
4. Update the
hello_bot function permissions to grant
<project_id>@appspot.gserviceaccount.com the Cloud Functions Invoker role. This makes the function available to be invoked from another Cloud function:
5. Follow the steps above to create the Slash command using the url endpoint for the
gotbotween Cloud Function.
Now we have a serverless slack bot hosted on GCP which is more consistent in providing a response to Slack within the required time frame for both warm and cold starts. On occasion the cold start for the
go function will be larger than 3 seconds and the timeout message may appear, however as Google Cloud continues to improve cold start times, this issue should disappear.
It may be possible to get a slightly better result by rewriting the
go component into
go implementation is sufficient for the current need.
Experimentation with a minimalistic
go handler with an aim to remove dependencies could assist with decreasing cold start times.
go handler could be used to route commands for multiple bots based on information passed into the function by Slack. This would further decrease the probability that the function would need a cold start as it will be invoked more often.
In conclusion, with a little bit of additional infrastructure, Google Cloud can be used to host a mostly well behaved serverless Slack bot implemented in a language of choice.