Я размещаю веб-приложение Django на Heroku, и оно использует Redis для запуска задачи в фоновом режиме (оно запускается пользователем при отправке формы).Задача часто должна делать несколько запросов к API, используя pexpect, последовательно.Когда все было настроено локально, у меня не было проблем с таймаутами, но теперь я регулярно сталкиваюсь с двумя проблемами: TIMEOUT в функции pexpect и «достигнуто максимальное количество клиентских подключений».
Я использую бесплатный уровень Heroku-Redis, поэтому мой лимит подключения составляет 20. Этого должно быть более чем достаточно для того, что я делаю, но на панели инструментов Redis я замечаю, что при запускеВ программе после этого соединения остаются открытыми некоторое время (что, как я подозреваю, вызывает ошибку «max connections» - старые соединения не закрывались).Я использовал heroku-redis в командной строке, чтобы установить так, чтобы бездействующие соединения закрывались через 15 секунд, но не похоже, что они есть.У меня также должно быть только 4 одновременных соединения (настройка в Django settings.py), но я регулярно получаю 15 или около того порожденных для одного запуска.
Как на самом деле ограничить количество подключений redis, сгенерированных для моей программы, и убедиться, что они действительно закрываются после завершения работы?И как мне предотвратить тайм-ауты (что, как я подозреваю, происходит из-за отсутствия доступного соединения для завершения запроса)?Я не понимаю, почему так много подключений Redis необходимо для одной фоновой задачи.
Это релевантный контент в моем файле Django settings.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())
Здесь я инициализирую Celery.Я использую декоратор @shared_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}
Мой пользовательский интерфейс регулярно проверяет ход выполнения задачи по обновлению индикатора выполнения.Это всего лишь простой вызов HTTP Post.
И это код pexpect, в случае необходимости.Поскольку я отправляю конфиденциальный контент (пароли и прочее), я удалил большую часть текста.
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), тем больше вероятность того, что программа завершится неудачно, прежде чем завершит работу.Моя фоновая задача должна быть в состоянии выполнять запросы последовательно, а мой поток пользовательского интерфейса должен иметь возможность проверять ход выполнения без каких-либо ограничений соединения или проблем с TIMEOUT.