本文介绍了当我通过Gunicorn和Flask连接到Cassandra的时候为什么会挂起Cassandra?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个连接到Cassandra的Flask应用程序。当我在Gunicorn下运行这个应用程序并且将Gunicorn作为一个flask-script命令 python manage.py gunicorn 时,它会挂起。但是当我在 gunicorn manage:app 命令行上运行这个相同的应用程序时,它会成功。为什么?

解决方案

解释



要求。
如果Cassandra会话(连接池)是在 fork之前(例如,在使用应用程序工厂模式创建应用程序的时候)在之前创建的,则工作人员在使用Cassandra时会遇到问题。 DataStax建议每个工作人员都有自己的会话,因此您需要推迟会话创建,直到之后的分支。
当你将Gunicorn和Flask捆绑在一起作为一个自定义应用程序时,这是一个问题,但是大概在命令行上,Gunicorn显然可以在创建Flask应用程序之前进行初始化和分叉。



示例



要查看这两个行为,请手动将bad = False更改为bad = True。从cassandra.cluster导入群集
从flask中导入群集
从flask_script中导入
import gunicorn.app.base中的命令,管理器
import BaseApplication
from gunicorn.six import iteritems


class CassandraClient:
def __init __(self,bad = False):
self.session = None
self。 cluster = None
if bad:
self.connect()

def connect(self):
self.cluster = Cluster(['127.0.0.1'] )
self.session = self.cluster.connect('keyspace')

def execute(self):
如果不是self.session:
self.connect ()
query ='''
从system.local选择now()

'''
返回self.session.execute(query)[0]


class GunicornApp(BaseApplication):
'''
将Gunicorn和Flask捆绑在一起,这样我们可以把它叫做
flask-script命令。

http://docs.gunicorn.org/en/stable/custom.html
'''

def __init __(self,app,options = None ):
self.options = options或{}
self.application = app $ b $ super(GunicornApp,self).__ init __()
$ b $ def load_config(self) :
config = dict(
[key,value)for iteritems(self.options)
如果key为self.cfg.settings且值不是None])
为键值,iteritems(config):
self.cfg.set(key.lower(),value)

def load(self):
return self.application


class GunicornCommand(命令):
'''
模拟关于flask_script.Server
'''
def __init __(self,app,options):
self.app = app
self.options = options
$ b def __call __(self,* args,** kwargs):
GunicornApp(self.app,self.options).run()


app = Flask(__ name__)
app.cassandra = CassandraClient()
@ app.route('/')
def hello():
return str(app.cassandra。执行())


if __name__ =='__main__':
manager = Manager(app)
gunicorn_options = {
'bind':'
port:8000,
'workers':4
}
manager.add_command(gunicorn,GunicornCommand(app,gunicorn_options))
manager.run()



版本



  Flask == 0.12.1 
Flask-Script == 2.0.5
gunicorn == 19.7.1
cassandra-driver == 3.8。 1



参考文献









I have a Flask app that connects to Cassandra. When I run this app under Gunicorn and invoke Gunicorn as a flask-script command python manage.py gunicorn, it hangs. But when I run this same app on the command line as gunicorn manage:app, it succeeds. Why?

解决方案

Explanation

Gunicorn forks off workers to handle incoming requests. If the Cassandra session (connection pool) is created before the worker fork (e.g., during app creation using an application factory pattern), the workers will have problems using Cassandra. DataStax recommends that each worker get its own session, and so you need to defer session creation until after the fork. This is a problem when you bundle Gunicorn and Flask together as a custom application, but presumably on the command line Gunicorn can obviously initialize and fork fully before creating the Flask app.

Example

To see the two behaviors, manually change bad=False to bad=True.

from cassandra.cluster import Cluster
from flask import Flask
from flask_script import Command, Manager
from gunicorn.app.base import BaseApplication
from gunicorn.six import iteritems


class CassandraClient:
    def __init__(self, bad=False):
        self.session = None
        self.cluster = None
        if bad:
            self.connect()

    def connect(self):
        self.cluster = Cluster(['127.0.0.1'])
        self.session = self.cluster.connect('keyspace')

    def execute(self):
        if not self.session:
            self.connect()
        query = '''
            select now()
            from system.local
        '''
        return self.session.execute(query)[0]


class GunicornApp(BaseApplication):
    '''
    Bundle Gunicorn and Flask together, so that we can call it as a
    flask-script command.

    http://docs.gunicorn.org/en/stable/custom.html
    '''

    def __init__(self, app, options=None):
        self.options = options or {}
        self.application = app
        super(GunicornApp, self).__init__()

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

    def load(self):
        return self.application


class GunicornCommand(Command):
    '''
    Modeled off of flask_script.Server
    '''
    def __init__(self, app, options):
        self.app = app
        self.options = options

    def __call__(self, *args, **kwargs):
        GunicornApp(self.app, self.options).run()


app = Flask(__name__)
app.cassandra = CassandraClient()
@app.route('/')
def hello():
    return str(app.cassandra.execute())


if __name__ == '__main__':
    manager = Manager(app)
    gunicorn_options = {
        'bind': '127.0.0.1',
        'port': 8000,
        'workers': 4
    }
    manager.add_command("gunicorn", GunicornCommand(app, gunicorn_options))
    manager.run()

Versions

Flask==0.12.1  
Flask-Script==2.0.5  
gunicorn==19.7.1  
cassandra-driver==3.8.1 

References

这篇关于当我通过Gunicorn和Flask连接到Cassandra的时候为什么会挂起Cassandra?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-11 03:55