Serving Discord bot and web requests simultaneously - python

I am currently building a Flask application where I use the python discord API to listen to commands and return simple messages.
bot = commands.Bot(command_prefix="!", description="Bot")
#bot.command()
async def ping(ctx):
await ctx.send('%s PONG' % ctx.message.author.mention)
bot.run(BOT_TOKEN)
At the same time, I am serving a webpage at '/' but when I try to go onto the webpage, the page just hangs. I launch my flask application using gunicorn with the command "gunicorn -b 0.0.0.0:8080 --chdir application/site/ main:app --reload --log-level=DEBUG" and in the output, I get
[2019-08-26 23:17:04 -0400] [50370] [INFO] Starting gunicorn 19.9.0
[2019-08-26 23:17:05 -0400] [50370] [DEBUG] Arbiter booted
[2019-08-26 23:17:05 -0400] [50370] [INFO] Listening at: http://0.0.0.0:8080 (50370)
[2019-08-26 23:17:05 -0400] [50370] [INFO] Using worker: sync
[2019-08-26 23:17:05 -0400] [50373] [INFO] Booting worker with pid: 50373
[2019-08-26 23:17:05 -0400] [50370] [DEBUG] 1 workers
[2019-08-26 23:17:08 -0400] [50373] [INFO] Logged in as Discord Bot 603846646383509504
[2019-08-26 23:17:35 -0400] [50370] [CRITICAL] WORKER TIMEOUT (pid:50373)
[2019-08-26 23:17:35 -0400] [50373] [INFO] Worker exiting (pid: 50373)
[2019-08-26 23:17:35 -0400] [50374] [INFO] Booting worker with pid: 50374
[2019-08-26 23:17:37 -0400] [50374] [INFO] Logged in as Discord Bot 603846646383509504
The discord bot works fine but loading the webpage does not. Am I missing something for my flask application to serve both requests at the same time or is this expected behavior?

Yes, the issue you are having is because both the Flask app and the Discord bot are both synchronous and Python by default can handle only one synchronous process at a time.
Fortunately, you can use the threading library in Python to put the Flask app into a thread and leave the Discord bot function running to handle events.
See this Github gist for an example of how to do this: https://gist.github.com/crrapi/c8465f9ce8b579a8ca3e78845309b832

Related

Gunicorn with django giving 500 with no extra information

I am trying to run django 3.2.16 with gunicorn, I get this output in console:
[2023-01-15 23:45:39 +0100] [210935] [INFO] Starting gunicorn 20.1.0
[2023-01-15 23:45:39 +0100] [210935] [DEBUG] Arbiter booted
[2023-01-15 23:45:39 +0100] [210935] [INFO] Listening at: http://0.0.0.0:8000 (210935)
[2023-01-15 23:45:39 +0100] [210935] [INFO] Using worker: sync
[2023-01-15 23:45:39 +0100] [210936] [INFO] Booting worker with pid: 210936
[2023-01-15 23:45:39 +0100] [210935] [DEBUG] 1 workers
Everything looks like working, but when I go to localhost, I get Internal Server Error.
It kinda behaves like if I had DEBUG = False, but I have DEBUG = True and there is also nothing in console. Django setup finishes and I also verify, that settings.DEBUG is indded true:
My wsgi.py file:
application = get_wsgi_application()
print(settings.DEBUG)
And of course runserver works fine.
What else could that be? How to get some kind of error output? I tried capture-out and all the log files and levels that gunicorn provides but got nothing useful from the console.
The reason was this line in my django log settings:
"disable_existing_loggers": True,
Setting this to False fixed my problem.

Python + FastAPI + OracleCloud: How to expose my python fastapi endpoint on Oracle Cloud to Internet

I have a Python + FastAPI restful API project running the free tier of Oracle Cloud VM instance.
I use Gunicorn to serve the api and also installed Nginx just in case it's needed.
I have tested my running project with
curl http://localhost:8000
and I can see my API response.
Now my question is : how can I expose this api endpoint outside on the Internet?
Update 1
I started my Python API project with this command:
gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app --timeout 1200 -b 0.0.0.0
I saw the messages below:
[2021-05-23 00:40:28 +0000] [3850] [INFO] Starting gunicorn 20.0.2
[2021-05-23 00:40:28 +0000] [3850] [INFO] Listening at: http://0.0.0.0:8000 (3850)
[2021-05-23 00:40:28 +0000] [3850] [INFO] Using worker: uvicorn.workers.UvicornWorker
[2021-05-23 00:40:28 +0000] [3853] [INFO] Booting worker with pid: 3853
[2021-05-23 00:40:28 +0000] [3854] [INFO] Booting worker with pid: 3854
[2021-05-23 00:40:28 +0000] [3857] [INFO] Booting worker with pid: 3857
[2021-05-23 00:40:28 +0000] [3858] [INFO] Booting worker with pid: 3858
[2021-05-23 00:42:04 +0000] [3853] [INFO] Started server process [3853]
[2021-05-23 00:42:04 +0000] [3857] [INFO] Started server process [3857]
[2021-05-23 00:42:04 +0000] [3857] [INFO] Waiting for application startup.
[2021-05-23 00:42:04 +0000] [3858] [INFO] Started server process [3858]
[2021-05-23 00:42:04 +0000] [3858] [INFO] Waiting for application startup.
[2021-05-23 00:42:04 +0000] [3858] [INFO] Application startup complete.
[2021-05-23 00:42:04 +0000] [3853] [INFO] Waiting for application startup.
[2021-05-23 00:42:04 +0000] [3853] [INFO] Application startup complete.
[2021-05-23 00:42:04 +0000] [3857] [INFO] Application startup complete.
[2021-05-23 00:42:04 +0000] [3854] [INFO] Started server process [3854]
[2021-05-23 00:42:04 +0000] [3854] [INFO] Waiting for application startup.
[2021-05-23 00:42:04 +0000] [3854] [INFO] Application startup complete.
Then I copied the IP address from the Compute >> Instances >> Instance Details panel and accessed it from my Chrome. Straightaway, it shows me
Unable to connect
Also read through several articles about using Nginx and tried without any luck.
Update 2
Using curl to access the website from my local machine
$ curl http://168.138.12.192:8000/
curl: (7) Failed to connect to 168.138.12.192 port 8000: No route to host
However, when access the IP directly using curl, I was able to get the default Nginx website.
$ curl http://168.138.12.192
Finally, I found out what I missed:
sudo iptables -I INPUT -p tcp -s 0.0.0.0/0 --dport 8000 -j ACCEPT
I have to run this command to open the port 8000(yes, my website is using port 8000).
I thought I have added Ingress Rule to accept tcp 8000, but it turns out that I still need to run the aforementioned command.
I do not quite understand why I need to do it, but it solves the problem.
Did you changed the default html page under /var/www/html directory? If not try customize the html page as per your requirement and see if it works for you or else it would just show the default nginx page when accessed from browser using public IP.
Adding to this, Also check if the port 8000 is allowed in the security list and OS firewall. The default port for http request is 80, you need to change the default port from 80 to 8000 in the config file to make this work. refer this page this might be useful How to Change Apache HTTP Port in Linux.

Which logger is outputting this in gunicorn?

When I start gunicorn it prints this:
[2018-11-09 16:30:20 +0000] [16] [INFO] Starting gunicorn 19.9.0
[2018-11-09 16:30:20 +0000] [16] [INFO] Listening at: http://0.0.0.0:8000 (16)
[2018-11-09 16:30:20 +0000] [16] [INFO] Using worker: sync
[2018-11-09 16:30:20 +0000] [19] [INFO] Booting worker with pid: 19
Setting up a logger for the gunicorn package (propagating) doesn't seem to affect it. What module is the one I should configure to modify these messages?
Those messages are output by the Arbiter class in gunicorn/arbiter.py, but it may be that any configuring you try and do is overridden by gunicorn's machinery, or not applicable - for example, trying to set up logging in a worker won't affect what the arbiter does, as they are separate processes. So you may need to invoke the arbiter in a special way (i.e. not just through running a canned gunicorn script) if you want to affect its logging, or amend the gunicorn configuration used for the arbiter.

Running a Simple Falcon App

I've a simple falcon app straight from the getting started example
import falcon
import json
class QuoteResource:
def on_get(self, req, resp):
"""Handles GET requests"""
quote = {
'quote': 'I\'ve always been more interested in the future than in the past.',
'author': 'Grace Hopper'
}
resp.body = json.dumps(quote)
api = falcon.API()
api.add_route('/quote', QuoteResource())
The code is in a file called manage.py
When I try to run gunicorn manage:app
This is what I get
2017-06-04 20:47:18 -0700] [2370] [INFO] Starting gunicorn 19.7.1
[2017-06-04 20:47:18 -0700] [2370] [INFO] Listening at: http://127.0.0.1:8000 (2370)
[2017-06-04 20:47:18 -0700] [2370] [INFO] Using worker: sync
[2017-06-04 20:47:18 -0700] [2373] [INFO] Booting worker with pid: 2373
Failed to find application: 'manage'
[2017-06-04 20:47:18 -0700] [2373] [INFO] Worker exiting (pid: 2373)
[2017-06-04 20:47:18 -0700] [2370] [INFO] Shutting down: Master
[2017-06-04 20:47:18 -0700] [2370] [INFO] Reason: App failed to load.
What am I doing wrong here?
Not sure whether it is a typo or because of misunderstanding but you should start the application this way:
gunicorn manage:api
But not gunicorn manage:app
The manage:api option tells to invoke the api object defined in your manage.py module. Otherwise you need to rename api variable to app in your code.
Then you can check that application is running by accessing the following url:
http://localhost:8000/quote
By default the port should 8000 but you need to check it when gunicorn starts. It should be something like this:
[INFO] Listening at: http://127.0.0.1:8000

Gunicorn workers timeout no matter what

I'm trying to run a simple flask app through gunicorn, but having my workers timeout no matter what I do. Whether there's activity against the app or not, workers will always timeout after whatever I set the timeout value to. What's causing them to timeout? Requests go through successfully when I make them, but workers still timeout. Here's what I'm running:
gunicorn test_app.py -b 127.0.0.1:8000 --log-level=debug --log-file /tmp/log
* Running on http://127.0.0.1:5000/
127.0.0.1 - - [28/Aug/2014 11:23:50] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [28/Aug/2014 11:23:53] "GET / HTTP/1.1" 200 -
* Running on http://127.0.0.1:5000/
* Running on http://127.0.0.1:5000/
And here's what I'm seeing in /tmp/log:
[2014-08-28 11:23:32 -0700] [36868] [INFO] Listening at: http://127.0.0.1:8000 (36868)
[2014-08-28 11:23:32 -0700] [36868] [INFO] Using worker: sync
[2014-08-28 11:23:32 -0700] [36871] [INFO] Booting worker with pid: 36871
[2014-08-28 11:23:32 -0700] [36868] [DEBUG] 1 workers
[2014-08-28 11:24:02 -0700] [36868] [CRITICAL] WORKER TIMEOUT (pid:36871)
[2014-08-28 11:24:02 -0700] [36868] [DEBUG] 1 workers
[2014-08-28 11:24:03 -0700] [36868] [DEBUG] 1 workers
[2014-08-28 11:24:03 -0700] [36872] [INFO] Booting worker with pid: 36872
[2014-08-28 11:24:03 -0700] [36868] [DEBUG] 1 workers
[2014-08-28 11:24:03 -0700] [36868] [DEBUG] 1 workers
[2014-08-28 11:24:33 -0700] [36868] [CRITICAL] WORKER TIMEOUT (pid:36872)
[2014-08-28 11:24:33 -0700] [36868] [DEBUG] 1 workers
[2014-08-28 11:24:33 -0700] [36872] [INFO] Worker exiting (pid: 36872)
[2014-08-28 11:24:33 -0700] [36873] [INFO] Booting worker with pid: 36873
[2014-08-28 11:24:33 -0700] [36868] [DEBUG] 1 workers
[2014-08-28 11:24:33 -0700] [36868] [DEBUG] 1 workers
[2014-08-28 11:25:03 -0700] [36868] [CRITICAL] WORKER TIMEOUT (pid:36873)
As you can see, my worker times out every 30 seconds, even though there's nothing wrong with it. What gives?
For anyone having this issue in the future, the main problem was me doing:
app.run()
and not
if __name__ == '__main__':
app.run()
with the former, the workers would wind up being run through flask instead of gunicorn, and the whole thing would become confused. Just switching to the latter fixed my issue.
Usually worker timeout will happen if the request take more time. Try add new parameter called --timeout <some value> it should work.
ex: gunicorn test_app.py -b 127.0.0.1:8000 --log-level=debug --log-file /tmp/log -t 900

Categories

Resources