How to create a Gunicorn custom application with Click commands?

Question:

I am trying to build a custom application using gunicorn server with flask framework utilizing click commands.
I used the class App to create an application that has the command say_hello which outputs Hello to the terminal:

import click
from flask import Flask
from gunicorn.app.base import BaseApplication

class App(BaseApplication):
    def __init__(self, options=None):
        self.options = options or {}
        self.application = Flask(__name__)
        super(App, self).__init__()

    def load_config(self):
        config = dict([(key, value) for key, value in self.options.items()
                       if key in self.cfg.settings and value is not None])
        for key, value in config.items():
            self.cfg.set(key.lower(), value)

    def load(self):
        return self.application

    @click.command()
    def say_hello(self):
        print('Hello')

options = {
    'bind': '%s:%s' % ('127.0.0.1', '5000'),
    'workers': 2
}

app = App(options)

When I try to run this app using the command gunicorn test:app, I get this error:

[2022-12-30 14:39:20 -0500] [302113] [INFO] Starting gunicorn 20.1.0
[2022-12-30 14:39:20 -0500] [302113] [INFO] Listening at: http://127.0.0.1:8000 (302113)
[2022-12-30 14:39:20 -0500] [302113] [INFO] Using worker: sync
[2022-12-30 14:39:20 -0500] [302114] [INFO] Booting worker with pid: 302114
Application object must be callable.
[2022-12-30 14:39:20 -0500] [302114] [INFO] Worker exiting (pid: 302114)
[2022-12-30 14:39:20 -0500] [302113] [INFO] Shutting down: Master
[2022-12-30 14:39:20 -0500] [302113] [INFO] Reason: App failed to load.

If I change app = App(options) to app = App(options).application, the application starts with one worker but the workers are set to 2 in the source code.

How to create a custom application that has Click commands?

Asked By: loaded_dypper

||

Answers:

You need to call app.run() to run the Gunicorn custom application.

Make running the Gunicorn server another Click (group) command, instead of making the Click command an instance method of the Gunicorn custom application:

@click.group()
def cli():
    pass


@cli.command()
def runserver():
    app.run()


@cli.command()
def say_hello():
    print('Hello')


cli()

Run command for Gunicorn custom application:

python test.py runserver

Run command for CLI program:

python test.py say-hello

References:

Answered By: aaron
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.