【问题标题】:Celery + Flask + Docker, consumer: Cannot connect to amqp://admin:**@rabbit:5672/myhost: failed to resolve broker hostnameCelery + Flask + Docker,消费者:无法连接到 amqp://admin:**@rabbit:5672/myhost:无法解析代理主机名
【发布时间】:2020-07-21 06:01:49
【问题描述】:

背景

我正在构建一个使用 Flask 作为后端框架的 Web 应用程序。该应用程序使用 Celery 将所有耗时的任务作为后台任务处理,以免阻塞后端线程。我使用 RabbitMQ 作为 Celery 工作人员的消息代理。我使用 docker-compose 捆绑了每个服务。

问题

该应用程序在过去几天一直运行良好,突然之间,Celery 工作人员一直无法连接到消息代理并显示错误消息 [ERROR/MainProcess] consumer: Cannot connect to amqp://admin:**@rabbit:5672/myhost: failed to resolve broker hostname.

目录结构和代码

我将文件和目录放在一起以作为可重复性最低的示例。

debug/
├── code
│   ├── dev.Dockerfile
│   ├── my_app
│   │   ├── celery_app.py
│   │   ├── config.py
│   │   ├── extensions.py
│   │   ├── __init__.py
│   │   ├── my_tasks.py
│   │   └── test_app.py
│   └── requirements.txt
└── docker-compose_dev.yml

docker-compose_dev.yml

version: "3.7"
services:
  rabbit:
    image: rabbitmq:3.8.5-management
    ports:
      - '15673:15672' # in case user has rabbitMQ installed on host
    expose:
      - "5672"
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=mypass
      - RABBITMQ_DEFAULT_VHOST=myhost

  non_working_worker:
    build:
      context: ./code
      dockerfile: dev.Dockerfile
    command: "celery worker -A my_app.celery_app:app -l info"
    volumes:
      - ./code:/code
    links:
      - rabbit

  working_worker:
    build:
      context: ./code
      dockerfile: dev.Dockerfile
    command: "celery worker -A my_app.my_tasks:app -l info"
    volumes:
      - ./code:/code
    links:
      - rabbit

dev.Dockerfile

FROM continuumio/miniconda3

# Make /backend working directory; flask code lives here
WORKDIR /code

# Install from requirements.txt using pip
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
RUN rm requirements.txt

requirements.txt

luigi==2.8.11
plotnine==0.7.0
celery==4.4.6
flask==1.1.2
flask-cors
flask-socketio
Flask-Mail
eventlet

test_app.py

import eventlet
eventlet.monkey_patch()

from flask import Flask
from my_app.extensions import celery

def create_app():
    """
    Application factory. Create application here.
    """
    app = Flask(__name__)
    app.config.from_object("my_app.config")

    return app

def init_celery(app=None):
    """
    Initialize Celery App
    """
    app = app or create_app()
    app.config.from_object("my_app.config")

    # Set celery worker configuration
    # Use this to load config information from flask config file
    celery.conf.broker_url = app.config["CELERY_BROKER_URL"]
    celery.conf.result_backend = app.config["CELERY_RESULT_BACKEND"]

    class ContextTask(celery.Task):
        """Make celery tasks work with Flask app context"""

        def __call__(self, *args, **kwargs):
            with app.app_context():
                return self.run(*args, **kwargs)

    celery.Task = ContextTask

    return celery

config.py

# RabbitMQ
CELERY_BROKER_URL='pyamqp://admin:mypass@rabbit/myhost'
CELERY_RESULT_BACKEND='rpc://'

extensions.py

from celery import Celery

celery = Celery()

celery_app.py

from my_app.test_app import init_celery

app = init_celery()

my_tasks.py

from celery import Celery


app = Celery()

app.conf.broker_url = 'pyamqp://admin:mypass@rabbit/myhost'
app.conf.result_backend = 'rpc://'

我的尝试

以下是我尝试过但没有奏效的方法。

  1. RabbitMQ 没有正常启动?
    • 一个。它使用给定的用户名、密码和虚拟主机正确启动。 (可以使用管理插件@localhost:15673查看)
  2. Celery worker 启动后 RabbitMQ 启动,worker 找不到代理?
    • 一个。 Celery 具有retry 功能,因此它将继续重试,直到消息代理启动。
  3. 网络问题?
    • 一个。我尝试使用/不使用links 来指定服务名称别名,但仍然没有成功。
    • 乙。注意我已经将代理名称指定为rabbit,正如config.py 文件中指定的那样,而不是localhost
    • c。我尝试使用默认网络 docker-compose 创建和自定义网络,但都失败了。
  4. 有趣的是,my_tasks.py 中的 Celery 应用程序实例有效(在 docker-compose 文件中命名为 working_worker),但 Flask 工厂模式中的 Celery 应用程序实例不起作用(在撰写文件)
    • 一个。同样,它表明 RabbitMQ 工作正常,但 Flask 工厂模式风格的 Celery 应用实例化出现了一些奇怪的问题。

我花了几天时间试图解决这个问题并在互联网上搜索类似的问题,但没有运气。

我知道这是一个相当长的帖子,但任何帮助/建议将不胜感激。

docker-compose 版本

docker-compose version 1.25.3, build d4d1b42b
docker-py version: 4.1.0
CPython version: 3.7.5
OpenSSL version: OpenSSL 1.1.0l  10 Sep 2019

码头工人版本

Client: Docker Engine - Community
 Version:           19.03.12
 API version:       1.40
 Go version:        go1.13.10
 Git commit:        48a66213fe
 Built:             Mon Jun 22 15:45:36 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:44:07 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

【问题讨论】:

  • 首先:对帖子的赞美。结构良好,你非常清楚你遇到了什么。我没有时间完全重建您的环境,但我发现 docker 容器通常很难调试。您可以通过 ssh 进入烧瓶容器并检查是否可以在命令行上使用 python 建立连接?只是为了检查您是否可以真正到达实例并缩小问题范围。如果您不使用 docker-compose 而是手动运行容器,代码是否有效?也许您可以在执行对 rmq 的调用之前运行调试器或打印出语句?

标签: python python-3.x flask rabbitmq celery


【解决方案1】:

我有一个类似的问题,我可以通过在 eventlet 上方的 requirements.txt 中将 dnspython 的版本(eventlets 依赖项之一)指定为 1.16.0 来解决。看起来 eventlet 与最新版本的 dnspython 不兼容,更多信息在这里https://github.com/eventlet/eventlet/issues/619

【讨论】:

  • 哇,,,不敢相信这是问题所在。我真的花了 5 天时间试图调试这个问题。非常感谢。 dnspython 版本更新日志与我的应用程序开始无法运行的那一天匹配。你是救世主
猜你喜欢
  • 2019-01-10
  • 2013-08-10
  • 2017-11-26
  • 2020-03-12
  • 2020-12-30
  • 1970-01-01
  • 2019-11-09
  • 2020-01-29
相关资源
最近更新 更多