如何在Amazon Elastic Beanstalk上部署Rails项目时自动重启delayed_job?

15
我在Amazon Elastic Beanstalk上托管了一个Rails项目,并尝试配置一个容器命令,在每次部署后自动重启服务器上的delayed_job工作进程。我试过这个命令:
container_commands:
  restartdelayedjob:
    command: "RAILS_ENV=production script/delayed_job --pid-dir=/home/ec2-user/pids start"
    cwd: /var/app/current

但是,似乎推送的版本在worker重新启动后才被部署,因此任务无法被worker处理。

当我通过ssh连接到我的实例时,杀掉worker进程并从部署版本文件夹中重新启动一个新进程,一切都正常工作。

你有任何想法如何处理这个问题吗?

谢谢。

4个回答

22
根据Amazon关于container_commands的文档,如下所示:

它们在应用程序和Web服务器设置完成且已提取应用程序版本文件之后运行,但在应用程序版本部署之前运行。

(我强调的)

这意味着此时您为命令设置的cwd/var/app/current仍指向先前的版本。 但是从文档中默认情况下,cwd如下:

是未解压缩应用程序的目录。

这意味着如果您想从刚提取但尚未部署的应用程序目录中运行delayed_job,请勿覆盖cwd,则应该启动即将部署的应用程序的延迟作业。

参考:http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html#customize-containers-format-container_commands

更新:

我现在已经自己设置好了,发现通过标准的container_commands进行设置存在限制——基本上,当它仍在/var/app/ondeck目录中时,将启动延迟作业。通常这是可以的,但由于应用程序现在位于/var/app/current,路径仍然存在,因此可能会导致错误。

我发现了一种未记录(因此请注意!)的方法,可以添加要在应用服务器重新启动后运行的脚本(并且您的新部署在/var/app/current中)。

基本上,Elastic Beanstalk将执行/opt/elasticbeanstalk/hooks/appdeploy/post目录中的任何脚本,以便在Web服务器重启之后运行这些脚本。这意味着如果您将shell脚本放在此目录中,则它们将被运行。

我创建了一个像这样的shell脚本:

#!/usr/bin/env bash
. /opt/elasticbeanstalk/support/envvars
cd $EB_CONFIG_APP_CURRENT
su -c "RAILS_ENV=production script/delayed_job --pid-dir=$EB_CONFIG_APP_SUPPORT/pids restart" $EB_CONFIG_APP_USER

我将这个脚本上传到S3存储桶,并确保其为“公共”状态。然后,您可以在.ebextensions目录下使用一个选项脚本(例如99delayed_job.config),将此脚本作为应用程序部署的一部分进行部署,注意post目录可能不存在:

commands:
  create_post_dir:
    command: "mkdir /opt/elasticbeanstalk/hooks/appdeploy/post"
    ignoreErrors: true
files:
  "/opt/elasticbeanstalk/hooks/appdeploy/post/99_restart_delayed_job.sh":
    mode: "000755"
    owner: root
    group: root
    source: http://YOUR_BUCKET.s3.amazonaws.com/99_restart_delayed_job.sh
当您部署时,您应该在您的/var/log/eb-tools.log中看到类似这样的内容:
2013-05-16 01:20:53,759 [INFO] (6467 MainThread) [directoryHooksExecutor.py-29] [root directoryHooksExecutor info] Executing directory: /opt/elasticbeanstalk/hooks/appdeploy/post/
2013-05-16 01:20:53,760 [INFO] (6467 MainThread) [directoryHooksExecutor.py-29] [root directoryHooksExecutor info] Executing script: /opt/elasticbeanstalk/hooks/appdeploy/post/99_restart_delayed_job.sh
2013-05-16 01:21:02,619 [INFO] (6467 MainThread) [directoryHooksExecutor.py-29] [root directoryHooksExecutor info] Output from script: delayed_job: trying to stop process with pid 6139...
delayed_job: process with pid 6139 successfully stopped.

2013-05-16 01:21:02,620 [INFO] (6467 MainThread) [directoryHooksExecutor.py-29] [root directoryHooksExecutor info] Script succeeded.

就像我说的一样,把东西放到“post”目录下是没有记录的 - 但希望在某些时候Amazon会在.options脚本中添加实际支持以运行部署后的命令,在那种情况下,您可以将其移动到官方支持的方法。


2
谢谢!对我也有用。只需注意以下几点:
  • 如果您正在使用Rails 4,请修改shell脚本以执行bin/delayed_job而不是script/delayed_job;
  • 我必须在脚本的cd $EB_CONFIG_APP_CURRENT行后添加此命令(chmod +x bin/delayed_job)。否则会出现权限错误;
  • 如果在执行脚本时出现“没有这样的文件或目录”错误,则可能需要在您的.ebextensions .config文件中添加一些行。添加dos2unix软件包安装和命令dos2unix /opt/elasticbeanstalk/hooks/appdeploy/post/99_restart_delayed_job.sh。
- William Weckl
@Marcin 如果您在负载均衡器后面有多个实例,那么这是否会在每个实例中启动后台作业?有没有办法只在一个实例中运行后台作业?或者您打算在哪里运行此代码。后台工作者? - King'ori Maina
1
@King'oriMaina - 是的,它会在每个实例上启动作业,但是delayed_job(我假设大多数队列系统也是如此)将锁定它们正在处理的作业,以避免重复,并且工作是分布式的。使用EB,您可以仅在“leader”上运行命令,因此如果您只想在一个实例上运行,请查看该选项。 - Marcin
@Marcin 确认过了,谢谢。我知道可以在 leader 上运行,但这个选项只存在于 EB 的 container_commands 中,而不是 files 配置选项中。 - King'ori Maina
最新的EB Ruby容器似乎存在问题,请参见此处的错误... '如何在Elastic Beanstalk上设置delayed_job时解决'require'错误' - King'ori Maina
2
魔法数字99是什么意思,为什么不是1或79,我们能不能用109?我在几个地方看到了九十多,但没有人解释它! - Dan

6
运行Ruby 2.1(Passenger Standalone)的64位Amazon Linux 2014.09 v1.1.0中,我参考了这篇文章成功地实现了它。
请注意,这个脚本是以root用户身份运行的,但你的工作进程应该以webapp用户身份运行。
# Adds a post-deploy hook such that after a new version is deployed
# successfully, restarts the delayed_job workers.
#
# https://dev59.com/ZmYq5IYBdhLWcg3wixJr
# http://www.dannemanne.com/posts/post-deployment_script_on_elastic_beanstalk_restart_delayed_job
files:
  "/opt/elasticbeanstalk/hooks/appdeploy/post/50_restart_delayed_job.sh":
    mode: "000755"
    owner: root
    group: root
    encoding: plain
    content: |
      #!/usr/bin/env bash

      EB_SCRIPT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k script_dir)
      EB_APP_CURRENT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_deploy_dir)
      EB_APP_USER=$(/opt/elasticbeanstalk/bin/get-config container -k app_user)
      EB_SUPPORT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k support_dir)
      EB_APP_PIDS_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_pid_dir)

      . $EB_SUPPORT_DIR/envvars
      . $EB_SCRIPT_DIR/use-app-ruby.sh

      cd $EB_APP_CURRENT_DIR

      # Switch to the webapp user.  Worker shouldn't be run as root.
      su -s /bin/bash -c "bundle exec bin/delayed_job --pid-dir=$EB_APP_PIDS_DIR restart" $EB_APP_USER

4

如果有人想在最新的ElasticBeanstalk(64位Amazon Linux 2014.09 v1.0.9运行Ruby 2.1(Puma))中使用delayed_job,我已经使用以下代码使其正常工作(感谢damontorgerson)。该文件放置在.ebextensions文件夹中的ruby.config中。

# Install git in order to be able to bundle gems from git
packages:
yum:
  git: []

files: 
  "/opt/elasticbeanstalk/hooks/appdeploy/post/50_restart_delayed_job":
    mode: "000777"
    owner: root
    group: root
    content: |
      EB_SCRIPT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k script_dir)
      EB_APP_STAGING_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_staging_dir)
      EB_CONFIG_APP_CURRENT=$(/opt/elasticbeanstalk/bin/get-config container -k app_deploy_dir)
      EB_CONFIG_APP_LOGS=$(/opt/elasticbeanstalk/bin/get-config container -k app_log_dir)
      EB_APP_USER=$(/opt/elasticbeanstalk/bin/get-config container -k app_user)
      EB_SUPPORT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k support_dir)
      EB_CONFIG_APP_PIDS=$(/opt/elasticbeanstalk/bin/get-config container -k app_pid_dir)

      . $EB_SUPPORT_DIR/envvars
      . $EB_SCRIPT_DIR/use-app-ruby.sh

      cd $EB_CONFIG_APP_CURRENT

      . $EB_SUPPORT_DIR/envvars.d/sysenv

      bin/delayed_job --pid-dir=/var/tmp restart

1
我用"daemons" gem 这样让我的工作正常运行:
commands:
  create_post_dir:
    command: "mkdir /opt/elasticbeanstalk/hooks/appdeploy/post"
    ignoreErrors: true
  webapp_pids:
    command: "mkdir /home/webapp/pids"
    ignoreErrors: true
files:
  "/opt/elasticbeanstalk/hooks/appdeploy/post/99_restart_delayed_job.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/usr/bin/env bash
      . /opt/elasticbeanstalk/support/envvars
      chown webapp:webapp /home/webapp/pids
      su -l -c "$EB_CONFIG_APP_CURRENT/bin/delayed_job --pid-dir=/home/webapp/pids restart" $EB_CONFIG_APP_USER
      echo "worker starting" >> /var/log/directory-hooks-executor.log

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接