Cailean Parker
Cailean Parker

Reputation: 143

Gunicorn fails with "Application object must be callable" in server hook for Flask app, but only if run as service

I've written a Flask app that's being served with Gunicorn and running on Raspberry Pi OS (Buster). The app is supposed to run automatically as a service on system boot. The issue is, the app fails when run as a service... but only when run as a service...

It used to work until I introduced server hooks into my Gunicorn configuration file. There's a few of them, but the first to be called, and thus fail is:

gunicorn.conf.py:

def on_starting(server):
    import wsgi
    wsgi.on_starting(server)

wsgi.py:

def on_starting(server):
    api_instance = server.app.wsgi()
    shared_memory_manager = Manager()
    api_instance.requestless_variables = shared_memory_manager.dict()
    api_instance.log = server.log
    server.log.info("Loading API...")

With the following traceback:

Traceback (most recent call last):
  File "/home/pi/.local/bin/gunicorn", line 8, in <module>
    sys.exit(run())
  File "/home/pi/.local/lib/python3.8/site-packages/gunicorn/app/wsgiapp.py", line 67, in run
    WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
  File "/home/pi/.local/lib/python3.8/site-packages/gunicorn/app/base.py", line 231, in run
    super().run()
  File "/home/pi/.local/lib/python3.8/site-packages/gunicorn/app/base.py", line 72, in run
    Arbiter(self).run()
  File "/home/pi/.local/lib/python3.8/site-packages/gunicorn/arbiter.py", line 198, in run
    self.start()
  File "/home/pi/.local/lib/python3.8/site-packages/gunicorn/arbiter.py", line 138, in start
    self.cfg.on_starting(self)
  File "/home/pi/nano/manager/src/api/gunicorn.conf.py", line 56, in on_starting
    api_instance = server.app.wsgi()
  File "/home/pi/.local/lib/python3.8/site-packages/gunicorn/app/base.py", line 67, in wsgi
    self.callable = self.load()
  File "/home/pi/.local/lib/python3.8/site-packages/gunicorn/app/wsgiapp.py", line 58, in load
    return self.load_wsgiapp()
  File "/home/pi/.local/lib/python3.8/site-packages/gunicorn/app/wsgiapp.py", line 48, in load_wsgiapp
    return util.import_app(self.app_uri)
  File "/home/pi/.local/lib/python3.8/site-packages/gunicorn/util.py", line 430, in import_app
    raise AppImportError("Application object must be callable.")
gunicorn.errors.AppImportError: Application object must be callable.

As you can see, the error seems to be with api_instance = server.app.wsgi(), which appears in each of my server hooks and is likewise my point of failure in each.

The absolute weirdest thing about this is that the app/Gunicorn works perfectly if instantiated directly from the terminal: /home/pi/.local/bin/gunicorn -c /home/pi/nano/manager/src/api/gunicorn.conf.py --bind unix:nano_api.sock --umask 007 But produces the above error if instantiated from the following service:

[Unit]
Description=Gunicorn instance serving the Nano API
After=network.target

[Service]
User=pi
Group=www-data
WorkingDirectory=/home/pi/nano/manager/src/api
ExecStart=/home/pi/.local/bin/gunicorn -c /home/pi/nano/manager/src/api/gunicorn.conf.py --bind unix:nano_api.sock --umask 007
[Install]
WantedBy=multi-user.target

Anyone have any ideas as to what might be causing this issue and how to fix it? Many thanks!

Upvotes: 1

Views: 2865

Answers (1)

Cailean Parker
Cailean Parker

Reputation: 143

Well, after a solid 10 hours of debugging, I finally figured out the problem...

I'm ashamed to say it was just a naming conflict. I had a package named "api" containing a module named "api.py" that housed a Flask instance named, you guessed it, "api."

Since I've given these three items distinct names and fixed my references, everything's ran smoothly.

Upvotes: 7

Related Questions