Как запустить Python-скрипт аналогично pm2 для Node.js
Проблема с перезапуском скрипта Python на EC2
Я использую pm2
для управления своим скриптом на Node.js и мне это очень нравится. Теперь у меня есть скрипт на Python, который собирает потоковые данные на EC2. Иногда скрипт аварийно завершает работу, и мне нужен менеджер процессов, который бы перезапускал его автоматически, как делает pm2
.
Существует ли что-то подобное pm2
для Python? Я искал, но не нашёл ничего подходящего.
Вот ошибка, с которой я столкнулся:
File "/usr/local/lib/python2.7/dist-packages/tweepy/streaming.py", line 430, in filter
self._start(async)
File "/usr/local/lib/python2.7/dist-packages/tweepy/streaming.py", line 346, in _start
self._run()
File "/usr/local/lib/python2.7/dist-packages/tweepy/streaming.py", line 286, in _run
raise exception
AttributeError: 'NoneType' object has no attribute 'strip'
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:90:
Это простой скрипт для сбора данных:
class StdOutListener(StreamListener):
def on_data(self, data):
mydata = json.loads(data)
db.raw_tweets.insert_one(mydata)
return True
def on_error(self, status):
mydata = json.loads(status)
db.error_tweets.insert_one(mydata)
if __name__ == '__main__':
# Это обрабатывает аутентификацию Twitter и подключение к Twitter Streaming API
l = StdOutListener()
auth = OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
stream = Stream(auth, l)
# Эта строка фильтрует потоки Twitter, чтобы захватить данные по ключевым словам: 'python', 'javascript', 'ruby'
stream.filter(follow=[''])
Я хотел бы, чтобы скрипт сам перезапускался, если что-то пойдёт не так.
5 ответ(ов)
Вы действительно можете запускать скрипты на Python из pm2 следующим образом:
pm2 start echo.py
Если ваш скрипт имеет суффикс .py, pm2 будет использовать интерпретатор Python по умолчанию. Если же имя вашего файла не заканчивается на .py, вы можете сделать так:
pm2 start echo --interpreter=python
Я заметил, что нужно быть осторожным с тем, какой именно Python вы используете, особенно если вы работаете в виртуальной среде (virtualenv) с версией Python, отличной от 'умолчательной' версии на вашем компьютере.
Ваш вопрос вполне понятен. Вы создали файл конфигурации ecosystem.config.json
, в котором описаны ваши приложения, и хотите запустить его с помощью PM2.
Вот пример вашего файла конфигурации:
{
"apps": [{
"name": "app_name",
"script": "/the/app/path/my_app.py",
"args": ["-c", "my_config.prod.json"],
"instances": "1",
"wait_ready": true,
"autorestart": false,
"max_restarts": 5,
"interpreter": "/path/to/venv/bin/python"
}]
}
Согласно вашему примеру, вы запускаете PM2 с помощью команды:
$ pm2 start ecosystem.config.json
$ pm2 -v
3.2.8
Если у вас возникли проблемы при запуске, вот несколько рекомендаций:
Проверка пути до интерпретатора: Убедитесь, что указанный путь
/path/to/venv/bin/python
действительно существует и что это правильный интерпретатор Python, используемый для вашего приложения.Права доступа: Убедитесь, что у вас есть необходимые права доступа к файлу
my_app.py
и к конфигурационному файлуmy_config.prod.json
.Логи ошибок: Проверьте логи ошибок PM2 с помощью команды
pm2 logs
. Это может дать подсказки о том, почему приложение не запускается.Версия PM2: У вас установлена версия PM2 3.2.8, которая может быть устаревшей. Возможно, имеет смысл обновить PM2 до последней версии. Это можно сделать с помощью команды:
npm install pm2@latest -g
Попробуйте эти шаги, если столкнетесь с проблемами, и дайте знать, если потребуется помощь с конкретной ошибкой!
PM2 вполне достаточно, он будет запускать интерпретатор по суффиксу файла. Вот пример конфигурации:
{
".sh": "bash",
".py": "python",
".rb": "ruby",
".coffee": "coffee",
".php": "php",
".pl": "perl",
".js": "node"
}
Таким образом, PM2 автоматически определит, какой интерпретатор использовать в зависимости от расширения файла вашего скрипта. Это значительно упрощает процесс настройки и управления процессами.
Если вы пытаетесь запустить программу на Python с использованием pipenv, попробуйте настроить pm2.config.json (или ecosystem.json.config, как указано в официальной документации PM2) следующим образом:
Обратите внимание на важные части: "interpreter" : "pipenv"
и "interpreter_args": "run python3"
.
pm2.config.json:
{
"apps": [{
"name": "BackupService",
"script": "/home/service-backup/service/server.py",
"args": [""],
"wait_ready": true,
"autorestart": false,
"max_restarts": 5,
"interpreter" : "pipenv",
"interpreter_args": "run python3"
}]
}
После этого выполните команду pm2 start pm2.config.json
. Я всегда выполняю pm2 delete BackupService
(или то, как вы его назвали в поле "name"
), перед повторным запуском, так как даже с флагом --update-env
он не использует обновленную pm2.config.json
. Почему именно так - не знаю.
Также обратите внимание, что, согласно последней документации PM2, "interpreter_args"
могло поменяться на "node_args"
. Я использую версию pm2 --version
3.0.0, и старый способ всё еще работает.
Если вы хотите запустить программу на Python, использующую библиотеку multiprocessing, решение заключается в том, чтобы принудительно запустить её в fork режиме. PM2, если ему не указать иное, автоматически пытается запустить программу в cluster
режиме.
Однако, я подозреваю, что необходимо полностью оставить управление multiprocessing на Python. Мне трудно представить, что PM2 сможет управлять множеством процессов, порождаемых Python, когда работает в cluster
режиме. Кроме того, если вы используете опцию "interpreter"
(например, для pipenv), только fork_mode
будет работать, согласно документации PM2.
Таким образом, добавьте "exec_mode": "fork"
в ваш pm2.config.json
, чтобы запустить его в нужном режиме.
Если вы не используете файл pm2.config.json
, передача -i 0
в команду pm2 start
также должна принудить запуск в fork режиме. (-i обозначает количество экземпляров).
UPD: Смотрите ответы ниже для более оптимальных решений.
Существует несколько решений для данной задачи. Во-первых, вы можете воспользоваться supervisord, который является достойной универсальной системой контроля процессов и предлагает множество функций "из коробки", таких как автоматический перезапуск, счетчик перезапусков, логирование, гибкая конфигурация и многое другое.
Кроме того, вы можете просто обернуть вашу реализацию в функцию, запустить её в блоке try except
, перехватить все исключения и, когда произойдет исключение, вызвать функцию снова вместо выхода из скрипта. В вашем случае такая функция могла бы включать в себя создание слушателя, аутентификацию и работу с потоками.
TensorFlow Python: Доступ к отдельным элементам в тензоре
"Попытка установить pymssql на Ubuntu 12.04 с помощью pip"
Скачать видео с YouTube с помощью Python в определённую директорию
Доступ к атрибутам на литералах работает для всех типов, кроме `int`; почему?
Генерация / синтез звука на Python?