我为屏幕截图编写了一个小API - 一个使用subprocess.Popen
将捕获请求传递给CasperJS的烧录应用程序在Mac上进行开发,当我在生产服务器(即Ubuntu 13.04)的shell中运行服务器时 - 一切都运行良好。
然而,当我使用supervisord管理服务器时,子进程调用返回CasperJS找不到PhantomJS的错误(Casper在Phantom上运行)。
抛出的错误是:
致命:[Errno 2]没有这样的文件或目录;你安装了phantomjs吗?
代码全是开源的。
这是子进程调用:
https://github.com/pwalsh/moment/blob/master/moment/models.py#L215
这是服务器的主管conf文件(我使用Fabric生成实际文件,但应该很清楚):
https://github.com/pwalsh/moment/blob/master/fabfile/templates.py#L56
系统上只有两个用户 - root用户和我的应用用户。当我以这些用户中的任何一个登录计算机时,我可以成功运行开发服务器,并且我可以成功运行PhantomJS和CasperJS。
为什么我的子流程错误与supervisord有关?
编辑:添加代码+ stacktrace
gunicord conf为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子进程的代码。它是一个类的方法,即完整的code is here:
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
注意:
答案 0 :(得分:0)
虽然(出于您应该调查的原因)用户已从原始moment
用户升级到root
,但这并不意味着当您以root用户身份登录shell时,该进程存在环境
您的路径可能只是supervisord.conf
中设置的路径,这就是为什么phantomjs似乎不存在的原因。
在某些用户数据库中没有查找环境;相反,它们是通过显式设置值(例如使用脚本)或通过产生过程的继承来构造的。在这种情况下,您将从主管继承,并将获得任何环境主管。如果主管是由像cron这样的东西运行的,那么该环境将是空的。
与supervisor相关的最佳实践是使用包装器脚本运行它,该脚本正确设置环境,或者仅显式设置supervisord.conf
中的所有内容。我通常推荐使用后者,除非你在很多脚本使用的文件中有一套通用的环境修正(例如因为你希望它在virtualenv中运行)。