Почему моя ошибка подпроцесса Python при управлении супервизором?

Я написал небольшой API для снимков экрана — фляжное приложение, которое передает запросы на захват в CasperJS с помощью subprocess.Popen

В разработке на Mac, и когда я запускаю сервер в оболочке на своем производственном сервере Ubuntu 13.04, все работает отлично.

Однако, когда я управляю сервером с помощью supervisord, вызов подпроцесса возвращает ошибку, что CasperJS не может найти PhantomJS (Casper работает на Phantom).

Выдается ошибка:

Fatal: [Errno 2] Нет такого файла или каталога; вы установили фантомы?

Весь код с открытым исходным кодом.

Вот вызов подпроцесса:

https://github.com/pwalsh/moment/blob/master/moment/models.py#L215

Вот файл конфигурации супервизора для сервера (фактический файл я генерирую с помощью Fabric, но он должен быть четким):

https://github.com/pwalsh/moment/blob/master/fabfile/templates.py#L56

В системе всего два пользователя - root и пользователь моего приложения. Когда я вхожу в систему как любой из этих пользователей, я могу успешно запустить сервер разработки и успешно запустить PhantomJS и CasperJS.

Почему возникает ошибка моего подпроцесса с supervisord?

Изменить: добавление кода + трассировка стека

Конфигурация Supervisord для сервера gunicorn:

; Generated via Fabric on 2013-08-18 23:05:50.928087
; gunicorn configuration for Moment
[program:moment-gunicorn]

command=/srv/environments/moment/bin/gunicorn moment:app --bind 127.0.0.1:9000 --workers 4 --timeout 30 --access-logfile /srv/logs/moment_gunicorn_access.log --error-logfile /srv/logs/moment_gunicorn_error.log

environment=PATH="/srv/environments/moment/bin"
directory=/srv/projects/moment
user=moment
autostart=true
autorestart=true

Код, который отправляет данные в подпроцесс CasperJS/PhantomJS. Это метод класса, полный код находится здесь:

def capture(self):

    filename = '{key}.{format}'.format(key=self.get_key().lstrip(self.prefix),
                                      format=self.arguments['format'])

    image = os.path.join(conf.CAPTURES_ROOT, filename)

    params = [conf.CASPER, conf.CAPTURE_SCRIPT, self.arguments['url'],
              image, self.arguments['viewport'], self.arguments['target']]

    casper = subprocess.Popen(params, stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)

    casper_output, casper_errors = casper.communicate()

    logging.info(casper_output)
    logging.info(casper_errors)
    logging.info(casper.returncode)

    # Here we are relying on convention:
    # If success, subprocess.returncode == 0
    # This could be fragile, need to investigate.
    if casper.returncode:

        raise Exception(casper_errors)

    else:

        return image

Выслеживать:

WARNING:root:Fatal: [Errno 2] No such file or directory; did you install phantomjs?
WARNING:root:
WARNING:root:1
ERROR:moment:Exception on /capture/ [GET]
Traceback (most recent call last):
  File "/srv/environments/moment/local/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/srv/environments/moment/local/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/srv/environments/moment/local/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/srv/environments/moment/local/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/srv/environments/moment/local/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/srv/projects/moment/moment/views.py", line 45, in get_capture
image = capture.capture()
File "/srv/projects/moment/moment/models.py", line 229, in capture
raise Exception(casper_errors)
Exception

Примечание:

  • Я работаю в virtualenv под названием «момент» и под пользователем с именем «момент».
  • Ошибка находится в переменной casper_output - эти первые три предупреждения - это предупреждение, которое я регистрирую при запуске подпроцесса.
  • Я отмечаю, что эти предупреждения выдаются пользователем root - я ожидал, что они будут вызваны «моментом», пользователем, от имени которого должен запускаться процесс supervisord.

person Community    schedule 18.08.2013    source источник
comment
Покажите здесь код и полную трассировку. Проблема почти наверняка в том, что ваш supervisord.conf (или среда, в которой он работает) не настроен так, чтобы PhantomJS был виден.   -  person Marcin    schedule 19.08.2013
comment
Я добавил код + трассировку, спасибо.   -  person    schedule 19.08.2013
comment
Какая информация регистрируется до того, как вы создадите исключение? Похоже, что это, вероятно, будет полезной информации.   -  person Marcin    schedule 19.08.2013
comment
Кроме того, ваш PATH только "/srv/environments/moment/bin". Хранится ли исполняемый файл, который вы ищете, в этом каталоге? Если нет, то в этом проблема.   -  person Marcin    schedule 19.08.2013
comment
Это вся трассировка. Что касается PATH, я понимаю, что конфигурация «среды» супервизора расширяет конфигурацию исполняемого пользователя. Здесь supervisord.org/configuration.html говорится, что подпроцессы наследуют переменные среды оболочки, используемой для запуска. надзиратель. В моем случае это root, а root имеет /usr/bin/ в PATH.   -  person    schedule 19.08.2013
comment
Я бы не был так уверен, что у вас та же среда, что и у root при входе в оболочку. Не существует волшебной базы данных переменных среды. Среды создаются путем явной установки переменной или наследования. Вероятно, вы наследуете среду того, что работает с супервизором. Если это, например. cron, это может быть вообще не среда.   -  person Marcin    schedule 19.08.2013
comment
Marcin, вы абсолютно правы, теперь я явно добавил /usr/bin в PATH и проблема решена. Не могли бы вы добавить это как ответ, чтобы я мог отметить его как правильный ответ?   -  person    schedule 19.08.2013


Ответы (1)


Хотя (по причинам, которые вы должны выяснить) пользователь повысился с исходного пользователя moment до root, это не означает, что процесс имеет среду, присутствующую при входе в оболочку с правами root.

Скорее всего, ваш путь - это только тот, который установлен в вашем supervisord.conf, и поэтому фантомы отсутствуют.

Среды не ищутся в какой-либо базе данных пользователей; вместо этого они создаются путем явной установки значений (например, с помощью сценария) или путем наследования от процесса порождения. В этом случае вы наследуете от супервизора и получите ту среду, которая была у супервизора. Если супервизор управляется чем-то вроде cron, эта среда будет пустой.

Лучшей практикой в ​​отношении супервизора является либо запуск его с использованием скрипта-оболочки, который правильно настраивает среду, либо просто явное задание всего в файле supervisord.conf. Я обычно рекомендую последнее, если только у вас нет общего набора исправлений среды в файле, используемом множеством скриптов (например, потому что вы хотите, чтобы он запускался внутри virtualenv).

person Marcin    schedule 19.08.2013