如何修复“ OperationalError:(psycopg2.OperationalError)服务器意外关闭了连接”

时间:2019-04-01 14:04:34

标签: postgresql macos docker flask

服务

我基于烧瓶+ PostgreSQL + Gunicorn +主管+ Nginx的服务

在通过docker进行部署时,运行服务后再访问api,有时会提示错误消息,有时效果很好。

然后sqlachemy connect数据库添加参数'sslmode:disable'

File "/usr/local/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 287, in _execute_on_connection
    Return connection._execute_clauseelement(self, multiparams, params)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1107, in _execute_clauseelement
    Distilled_params,
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1248, in _execute_context
    e, statement, parameters, cursor, context
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1466, in _handle_dbapi_exception
    Util.raise_from_cause(sqlalchemy_exception, exc_info)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 383, in raise_from_cause
    Reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1244, in _execute_context
    Cursor, statement, parameters, context
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 552, in do_execute
    Cursor.execute(statement, parameters)
OperationalError: (psycopg2.OperationalError) server closed the connection unexpectedly
    This probably means the server terminated abnormally
    before or while processing the request.

信息

适用于Mac的Docker:版本:2.0.0.3(31259)

macOS:版本10.14.2

Python:版本2.7.15

重复方法

通过命令查看端口信息时

lsof -i:5432

端口5432是PostgreSQL数据库的默认端口,如果输出控制台是

COMMAND    PID        USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
postgres 86469 user    4u  IPv6 0xxddd      0t0  TCP *:postgresql (LISTEN)
postgres 86469 user    5u  IPv4 0xxddr      0t0  TCP *:postgresql (LISTEN)

它将显示错误消息:

OperationalError: (psycopg2.OperationalError) server closed the connection unexpectedly

但是如果outputconsolelog显示以下内容:

COMMAND     PID        USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
com.docke 62421 user   26u  IPv4 0xe93      0t0  TCP 192.168.2.7:6435->192.168.2.7:postgresql (ESTABLISHED)
postgres  86460 user    4u  IPv6 0xed3      0t0  TCP *:postgresql (LISTEN)
postgres  86460 user    5u  IPv4 0xe513      0t0  TCP *:postgresql (LISTEN)
postgres  86856 user   11u  IPv4 0xfe93      0t0  TCP 192.168.2.7:postgresql->192.168.2.7:6435 (ESTABLISHED)

在这种情况下,api会很好地工作。

因为Docker for mac?

引用链接https://github.com/docker/for-mac/issues/2442,该问题无法解决我的问题。

是否注意到类似的问题?

引用链接Python & Sqlalchemy - Connection pattern -> Disconnected from the remote server randomly

这个问题也解决不了我的问题。

解决方案

flask_sqlachemy need the parameter pool_pre_ping

from flask_sqlalchemy import SQLAlchemy as _BaseSQLAlchemy

class SQLAlchemy(_BaseSQLAlchemy):
    def apply_pool_defaults(self, app, options):
        super(SQLAlchemy, self).apply_pool_defaults(self, app, options)
        options["pool_pre_ping"] = True

db = SQLAlchemy()

4 个答案:

答案 0 :(得分:2)

sqlalchemy.orm具有相同的逻辑(flask_sqlalchemy基于btw)

engine = sqlalchemy.create_engine(connection_string, pool_pre_ping=True)

可以设置更多保护策略,例如文档https://docs.sqlalchemy.org/en/13/core/pooling.html#disconnect-handling-pessimistic

中所述。

例如,这是我的引擎实例:

engine = sqlalchemy.create_engine(connection_string,
                                      pool_size=10,
                                      max_overflow=2,
                                      pool_recycle=300,
                                      pool_pre_ping=True,
                                      pool_use_lifo=True)

sqlalchemy.orm.sessionmaker(bind=engine, query_cls=RetryingQuery)

对于RetryingQuery代码,请参见:Retry failed sqlalchemy queries

答案 1 :(得分:1)

我正在发布我自己的答案,因为以上都没有解决我的特定设置(Postgres 12.2、SQLAlchemy 1.3)。

要停止 id med_name_one med_name_two mg_one mg_two administration_datetime <dbl> <chr> <chr> <chr> <chr> <chr> 1 1 Co-amoxiclav NA 411 mg NA 2020-01-03 10:08 2 1 doxycycline Gentamicin 120 mg 11280 mg 2020-01-01 11:08 3 2 Gentamicin Co-trimoxazole 11280 mg 8 mg 2020-01-02 19:08 4 2 Co-trimoxazole NA 8 mg NA 2020-01-08 20:08 5 3 Gentamicin NA 11280 mg NA 2020-01-02 19:08 6 4 Co-trimoxazole NA 8 mg NA 2020-01-08 20:08 7 5 Sodium Chloride NA 411 mg NA 2019-01-30 08:08 8 6 Piperacillin NA 120 mg NA 2020-01-03 09:08 9 7 Piperacillin-tazobactam NA NA NA 2020-01-03 09:08 ,我必须将一些额外的 OperationalError 传递给 connect_args

create_engine

答案 2 :(得分:0)

以答案中的解决方案和@ MaxBlax360答案中的信息为基础。我认为在Flask-SQLAlchemy中设置这些配置值的正确方法是设置app.config['SQLALCHEMY_ENGINE_OPTIONS']

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
# pool_pre_ping should help handle DB connection drops
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {"pool_pre_ping": True}  
app.config['SQLALCHEMY_DATABASE_URI'] = \
    f'postgresql+psycopg2://{POSTGRES_USER}:{dbpass}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DBNAME}'
db = SQLAlchemy(app)

See also Flask-SQLAlchemy docs on Configuration Keys

答案 3 :(得分:0)

我的数据库配置:

app = Flask(__name__)
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {"pool_pre_ping": True}
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Play with following options:
app.config['SQLALCHEMY_POOL_SIZE'] = 10
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 20
app.config['SQLALCHEMY_POOL_RECYCLE'] = 1800

db = SQLAlchemy(app)