当我使用HerokuRedis进行多线程处理时,为什么会达到连接限制并超时查询?

2024-05-23 17:47:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我在Heroku上托管了一个DjangoWeb应用程序,它使用Redis在后台运行一个任务(当用户提交表单时,这会被启动)。任务通常必须依次使用pexpect对API进行多个查询。当我在本地设置它时,我没有超时的问题,但是现在我经常遇到两个问题:pexpect函数中的超时和“达到的最大客户端连接数”。你知道吗

我使用的是Heroku Redis的免费层,所以我的连接限制是20。这对于我所做的应该已经足够了,但是我在Redis仪表板上注意到,当我运行程序时,连接会保持打开状态一段时间(我怀疑这就是导致“max connections”错误的原因——旧的连接没有关闭)。我在命令行上使用了heroku redis来设置它,这样空闲连接应该在15秒后关闭,但看起来不是这样。我还应该同时只有4个并发连接(在Django中设置)设置.py),但我经常有15个左右的产卵为一次运行。你知道吗

我该如何限制为我的程序生成的redis连接的数量,并确保它们在完成任务时真正关闭?如何防止超时(我怀疑是因为没有连接可以完成查询而发生的)?我不明白为什么一个后台任务需要这么多Redis连接。你知道吗

这是我的Django中的相关内容设置.py文件。我使用芹菜来运行我的后台任务,所以我不直接与Redis接口。你知道吗

CACHES = {
    "default": {
         "BACKEND": "redis_cache.RedisCache",
         "LOCATION": "redis:// censored",
         "OPTIONS": {
            'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool',
            'CONNECTION_POOL_CLASS_KWARGS': {
                'max_connections': 4, 
                'timeout': 15,
                'retry_on_timeout': True
            },
        },
    }
}

# the line below lets it run locally
# BROKER_URL and CELERY_RESULT_BACKEND = 'amqp://guest:guest@rabbit:5672/%2F'

# I'm not sure what the difference between BROKER_* and REDIS_* are,
# so I've included them both for good measure 
BROKER_BACKEND = "redis"
BROKER_HOST = "amazonaws.com censored"  
BROKER_PORT = 20789
BROKER_PASSWORD = "censored"
BROKER_VHOST = "0"
BROKER_POOL_LIMIT = 4 # limit # of celery workers

REDIS_URL = "redis://censored
REDIS_HOST = "amazonaws.com censored" 
REDIS_PORT = 20789
REDIS_PASSWORD = "censored"
REDIS_DB = 0
REDIS_CONNECT_RETRY = True

CELERY_RESULT_BACKEND = REDIS_URL
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_REDIS_MAX_CONNECTIONS = 4
CELERYD_TASK_SOFT_TIME_LIMIT = 30

DATABASE_URL = "postgres:// censored"
# I added this for Heroku
django_heroku.settings(locals())

这是我做芹菜的地方。我使用@shared\u task(bind=True)装饰器作为后台任务函数。你知道吗

app = Celery('aircraftToAirQuality', backend=settings.CELERY_RESULT_BACKEND, broker=settings.REDIS_URL)
app.conf.broker_pool_limit = 0
app.conf.broker_transport_options = {"visibility_timeout": 60}

我的UI定期检查任务的进度,以更新进度栏。这只是一个简单的httppost调用。你知道吗

如果相关的话,这就是预期代码。因为我发送的是敏感内容(密码之类的),所以我删除了大部分的文本。你知道吗

def use_pexpect(self, query):
    cmd = 'censored'
    pex = pexpect.spawn(cmd)
    pex.timeout = 30
    index = pex.expect(censored)
    time.sleep(0.1)
    pex.sendline(censored)
    pex.sendline(query)
    pex.expect(censored)
    result = pex.before
    pex.sendline('quit;')
    pex.close()
    return result

现在,我很少能成功地运行我的任务。任务应该运行的时间越长(进行10次查询,而不是仅仅3次),程序在完成运行之前失败的可能性就越大。我的后台任务应该能够按顺序进行查询,我的UI线程应该能够检查其进度,而不存在任何连接限制或超时问题。你知道吗


Tags: 程序redisbackendurlherokutimeoutbrokerresult