Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Socket Mode and Flask/Gunicorn simultaneous run #255

Closed
rdbreak opened this issue Mar 7, 2021 · 3 comments
Closed

Socket Mode and Flask/Gunicorn simultaneous run #255

rdbreak opened this issue Mar 7, 2021 · 3 comments
Labels
area:adapter area:sync question Further information is requested

Comments

@rdbreak
Copy link

rdbreak commented Mar 7, 2021

I recently switched my bot running in Heroku to the bolt framework but I'm only able to get it working in Socket Mode.

Reproducible in:

--> slack-bolt==1.1.1

--> Python 3.9.0

ProductName:	macOS
ProductVersion:	11.2.2
BuildVersion:	20D80
Darwin Kernel Version 20.3.0

Steps to reproduce:

1.) Searched issues for existing issues.
2.) Tried various code changes. One example below:

app = App(
    token=SLACK_BOT_TOKEN,
    signing_secret=SLACK_SIGNING_SECRET,
    verification_token=VERIFICATION_TOKEN
    )

flask_app = Flask(__name__)

@flask_app.route("/slack/events", methods=["POST"])
def flask_handler(event):
    _handler = SlackRequestHandler(app=app)
    return _handler.handle(event)

...

if __name__ == "__main__":
    # Only for local debug
    SocketModeHandler(app, SLACK_APP_TOKEN).start()
    flask_app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 3000))). # or flask_app.run(port=os.environ.get('PORT'))

3.) Disabled Socket Mode, reenabled.
4.) Tried different code snippets from Docker/Flask/flask-gunicorn examples directory

Expected result:

The bot to run and accept event requests server-side (via Heroku) and able to run Socket Mode for ongoing local development simultaneously.

Actual result:

Getting 404 and 503 errors (with Socket Mode disabled)

heroku[router]: at=info method=POST path="/" host=bot.herokuapp.com request_id=b2fe742e-412e-419b-a828 fwd="35.170.200.13" dyno=web.1 connect=0ms service=3ms status=404 bytes=400 protocol=https

heroku[router]: at=error code=H12 desc="Request timeout" method=POST path="/slack/events" host=rhc-bot.herokuapp.com request_id=a68ec33d-500f-40f7-a750-f44de4327de4 fwd="3.80.210.39" dyno=web.1 connect=1ms service=30000ms status=503 bytes=0 protocol=https
@rdbreak rdbreak changed the title Socket Mode and Flask/Gunicorn simultaneously run Socket Mode and Flask/Gunicorn simultaneous run Mar 7, 2021
@seratch seratch added area:adapter area:sync question Further information is requested labels Mar 7, 2021
@seratch
Copy link
Member

seratch commented Mar 7, 2021

Hey @rdbreak, thanks for asking the question!

For an app that run with a Socket Mode connection, the app no longer needs to serve /slack/events endpoint. The app receives payloads from the Slack server-side only through a WebSocket connection.

That being said, you may want to run web app too for Slack OAuth flow or some other purpose. For this, your app can use SocketModeAdapter's connect() method to establish a WS connection without blocking the current thread and use Flask along with it:

#
# Bolt App
#
import os
import logging
from slack_bolt import App

logging.basicConfig(level=logging.DEBUG)

app = App(token=os.environ["SLACK_BOT_TOKEN"])

# Add middleware / listeners here

@app.command("/hi")
def hello(body, ack):
    user_id = body["user_id"]
    ack(f"Hi <@{user_id}>!")


#
# Socket Mode
#
from slack_bolt.adapter.socket_mode import SocketModeHandler
handler = SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"])
# Use connect() method as start() blocks the current thread
handler.connect()


#
# Web App
#
from flask import Flask, request
flask_app = Flask(__name__)

# You won't use the Flask adapter as all the event requests are handled by the above Socket Mode connection
# from slack_bolt.adapter.flask import SlackRequestHandler
# handler = SlackRequestHandler(app)

@flask_app.route("/", methods=["GET"])
def index():
    return "Hello World"

# You can run this app by the following command:
# gunicorn --bind :3000 --workers 1 --threads 2 --timeout 0 app:flask_app

@rdbreak
Copy link
Author

rdbreak commented Mar 7, 2021

Thanks for you reply!

I'll make the necessary changes. Thanks again!

@YAMLcase
Copy link

This sounds like a roundabout way to create a liveness endpoint for local user health checks. Is there some more built-in way to have a local user interact with SocketModeHandler().start()? This is for kubernetes to check periodically if the app is health.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:adapter area:sync question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants