eycloud-recipe-delayed_job 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg
2
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ eycloud-recipe-delayed_job (1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (0.9.2.2)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ eycloud-recipe-delayed_job!
16
+ rake
data/README.markdown ADDED
@@ -0,0 +1,100 @@
1
+ # Delayed Job recipe for EY Cloud
2
+
3
+ This cookbook can serve as a good starting point for setting up Delayed Job support in your application.
4
+ In this recipe your Delayed Job workers will be set up to run under monit. The number of workers will
5
+ vary based on the size of the instance running Delayed Job.
6
+
7
+ This recipe will setup `delayed_job` on a Solo instance environment or on named Utility instances in a cluster environment.
8
+
9
+ Name your Utility instances with prefixes: `dj`, `delayed_job`, `delayedjob`. For example, `dj1`, `delayedjob4`.
10
+
11
+ If you want `delayed_job` to run on App instances instead of Utility, you will need to modify the recipe.
12
+
13
+ TODO: if no corresponding dj|delayed_job|delayedjob named Utility instances, then install DJ on the app instances.
14
+
15
+ ## How many workers do I get?
16
+
17
+ The number of parallel workers is based on the instance type.
18
+
19
+ Solo instances allocate a single Delayed Job worker because the instance is primarily for running the Application and its database.
20
+
21
+ For each `dj` utility instance the number of workers is determined by the `delayed_job_worker_count` library helper:
22
+
23
+ ``` ruby
24
+ def delayed_job_worker_count(instance_type)
25
+ case instance_type
26
+ when "m1.small"
27
+ 3
28
+ when "m1.medium"
29
+ 4
30
+ when "m1.large"
31
+ 8
32
+ when "m1.xlarge"
33
+ 12
34
+ when "m2.xlarge"
35
+ 10
36
+ when "m2.2xlarge"
37
+ 10
38
+ when "m2.4xlarge"
39
+ 24
40
+ when "c1.medium"
41
+ 4
42
+ when "c1.xlarge"
43
+ 24
44
+ else
45
+ 2
46
+ end
47
+ end
48
+ ```
49
+
50
+ To learn more about each instance type, see the [AWS EC2 Instance Type](http://aws.amazon.com/ec2/instance-types/ "Amazon EC2 Instance Types") page.
51
+
52
+ ## Installation
53
+
54
+ This recipe must be installed as `delayed_job` and not `eycloud-recipe-delayed_job`.
55
+
56
+ ## Simple Installation
57
+
58
+ To add this recipe to your collection of recipes, or as your first recipe, you can use the helpful `ey-recipes` command line tool:
59
+
60
+ cd myapp
61
+ gem install engineyard engineyard-recipes
62
+ ey-recipes init
63
+ ey-recipes clone git://github.com/engineyard/eycloud-recipe-delayed_job.git -n delayed_job
64
+ ey recipes upload --apply
65
+
66
+ If you want to have your recipes run during deploy (rather than the separate `ey recipes upload --apply` step):
67
+
68
+ ey-recipes init -d
69
+ ey-recipes clone git://github.com/engineyard/eycloud-recipe-delayed_job.git -n delayed_job
70
+ git add .; git commit -m "added delayed job recipe"; git push origin master
71
+ ey deploy
72
+
73
+ ## Manual Installation
74
+
75
+ Clone/copy this repository into a `cookbooks/delayed_job` folder (such that you have a `cookbooks/delayed_job/recipes/default.rb` file).
76
+
77
+ Then add the following to `cookbooks/main/recipes/default.rb`:
78
+
79
+ require_recipe "delayed_job"
80
+
81
+ Make sure this and any customizations to the recipe are committed to your own fork of this
82
+ repository.
83
+
84
+ Then to upload and apply to EY Cloud for a given environment:
85
+
86
+ ey recipes upload --apply -e target-environment
87
+
88
+ ## Restarting your workers
89
+
90
+ This recipe does NOT restart your workers. The reason for this is that shipping your application and
91
+ rebuilding your instances (i.e. running chef) are not always done at the same time. It is best to
92
+ restart your Delayed Job workers when you ship (deploy) your application code. To do this, add a
93
+ deploy hook to perform the following:
94
+
95
+ sudo "monit -g dj_<app_name> restart all"
96
+
97
+ Make sure to replace <app_name> with the name of your application. You likely want to use the
98
+ after_restart hook for this. See our [Deploy Hook](http://docs.engineyard.com/appcloud/howtos/deployment/use-deploy-hooks-with-engine-yard-appcloud) documentation
99
+ for more information on using deploy hooks.
100
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ version = "1.0" # get from metadata.json or .rb
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "eycloud-recipe-delayed_job"
8
+ s.version = version
9
+ s.authors = ["Dr Nic Williams"]
10
+ s.email = ["drnicwilliams@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Delayed Job for EY Cloud} # from metadata
13
+ s.description = %q{Delayed Job for EY Cloud} # from metadata long_description
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_development_dependency("rake")
21
+ end
@@ -0,0 +1,8 @@
1
+ class Chef
2
+ class Recipe
3
+ # Only Rails applications (containing script/runner) are valid
4
+ def delayed_job_applications
5
+ node[:applications]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,29 @@
1
+ class Chef
2
+ class Recipe
3
+ # If you change this, please copy it back into the README as documentation
4
+ def delayed_job_worker_count(instance_type)
5
+ case instance_type
6
+ when "m1.small"
7
+ 3
8
+ when "m1.medium"
9
+ 4
10
+ when "m1.large"
11
+ 8
12
+ when "m1.xlarge"
13
+ 12
14
+ when "m2.xlarge"
15
+ 10
16
+ when "m2.2xlarge"
17
+ 10
18
+ when "m2.4xlarge"
19
+ 24
20
+ when "c1.medium"
21
+ 4
22
+ when "c1.xlarge"
23
+ 24
24
+ else
25
+ 2
26
+ end
27
+ end
28
+ end
29
+ end
data/metadata.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "license": "MIT",
3
+ "maintainer": "Engine Yard LLC",
4
+ "maintainer_email": "drnic@engineyard.com",
5
+ "version": "1.0",
6
+ "description": "Delayed Job for EY Cloud",
7
+ "name": "delayed_job",
8
+ "attributes": {
9
+
10
+ },
11
+ "long_description": ""
12
+ }
data/metadata.rb ADDED
@@ -0,0 +1,6 @@
1
+ name "delayed_job"
2
+ description "Delayed Job for EY Cloud"
3
+ long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
4
+ maintainer "Engine Yard LLC"
5
+ maintainer_email "drnic@engineyard.com"
6
+ version "1.0"
@@ -0,0 +1,35 @@
1
+ #
2
+ # Cookbook Name:: delayed_job
3
+ # Recipe:: configure
4
+ #
5
+
6
+ # This recipe will setup `delayed_job` on a Solo instance environment or on named Utility instances in a cluster environment.
7
+ # Name your Utility instances with prefixes: `dj`, `delayed_job`, `delayedjob`. For example, `dj1`, `delayedjob4`.
8
+ if node[:instance_role] == "solo" || node[:instance_role] == "eylocal" ||
9
+ (node[:instance_role] == "util" && node[:name] =~ /^(dj|delayed_job|delayedjob)/)
10
+ delayed_job_applications().each do |app_name,data|
11
+
12
+ # determine the number of workers to run based on instance size
13
+ if node[:instance_role] == 'solo' || node[:instance_role] == 'eylocal'
14
+ worker_count = 1
15
+ else
16
+ worker_count = delayed_job_worker_count(node[:ec2][:instance_type])
17
+ end
18
+
19
+ worker_count.times do |count|
20
+ template "/etc/monit.d/delayed_job#{count+1}.#{app_name}.monitrc" do
21
+ source "dj.monitrc.erb"
22
+ owner "root"
23
+ group "root"
24
+ mode 0644
25
+ variables({
26
+ :app_name => app_name,
27
+ :user => node[:owner_name],
28
+ :worker_name => "delayed_job#{count+1}",
29
+ :framework_env => node[:environment][:framework_env]
30
+ })
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ #
2
+ # Cookbook Name:: delayed_job
3
+ # Recipe:: default
4
+ #
5
+
6
+ require_recipe "delayed_job::install"
7
+ require_recipe "delayed_job::configure"
8
+ require_recipe "delayed_job::restart"
9
+
@@ -0,0 +1,26 @@
1
+ #
2
+ # Cookbook Name:: delayed_job
3
+ # Recipe:: install
4
+ #
5
+
6
+ # This recipe will setup `delayed_job` on a Solo instance environment or on named Utility instances in a cluster environment.
7
+ # Name your Utility instances with prefixes: `dj`, `delayed_job`, `delayedjob`. For example, `dj1`, `delayedjob4`.
8
+ if node[:instance_role] == "solo" || node[:instance_role] == "eylocal" ||
9
+ (node[:instance_role] == "util" && node[:name] =~ /^(dj|delayed_job|delayedjob)/)
10
+ delayed_job_applications().each do |app_name,data|
11
+
12
+ directory "/engineyard/bin" do
13
+ owner "root"
14
+ group "root"
15
+ mode 0755
16
+ end
17
+
18
+ template "/engineyard/bin/dj" do
19
+ source "dj.erb"
20
+ owner "root"
21
+ group "root"
22
+ mode 0755
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ #
2
+ # Cookbook Name:: delayed_job
3
+ # Recipe:: restart
4
+ #
5
+
6
+ # This recipe will setup `delayed_job` on a Solo instance environment or on named Utility instances in a cluster environment.
7
+ # Name your Utility instances with prefixes: `dj`, `delayed_job`, `delayedjob`. For example, `dj1`, `delayedjob4`.
8
+ if node[:instance_role] == "solo" || node[:instance_role] == "eylocal" ||
9
+ (node[:instance_role] == "util" && node[:name] =~ /^(dj|delayed_job|delayedjob)/)
10
+ delayed_job_applications().each do |app_name,data|
11
+
12
+ execute "monit-reload-restart" do
13
+ command "sleep 30 && monit reload && monit restart all -g dj_#{app_name}"
14
+ action :run
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,182 @@
1
+ #!/bin/sh
2
+ #
3
+ # This script starts and stops the Dj daemon
4
+ # This script belongs in /engineyard/bin/dj
5
+ #
6
+ PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
7
+ CURDIR=`pwd`
8
+
9
+ usage() {
10
+ echo "Usage: $0 <appname> {start|stop} enviroment [name maximum_priority minimum_priority]"
11
+ exit 1
12
+ }
13
+
14
+ if [ $# -lt 3 ]; then usage; fi
15
+
16
+ if [ $4 ]; then
17
+ NAME="_$4"
18
+
19
+ if [ $5 ]; then
20
+ OPTIONS=":max_priority=>$5"
21
+ if [ $6 ]; then
22
+ OPTIONS="$OPTIONS,:min_priority=>$6"
23
+ fi
24
+ OPTIONS="{$OPTIONS}"
25
+ fi
26
+ fi
27
+
28
+ if [ "`whoami`" != "root" ]; then
29
+ logger -t `basename $0` -s "Must be run as root"
30
+ exit 1
31
+ fi
32
+ ## Function definitions - casual readers encouraged to skip this ##
33
+ rm_lockfile(){
34
+ if [ -e $LOCK_FILE ]; then
35
+ logger -t "monit_dj:$WORKER[$$]" "removing $LOCK_FILE for `cat $LOCK_FILE`"
36
+ rm $LOCK_FILE
37
+ fi
38
+ }
39
+
40
+ lock(){
41
+ RESULT=0
42
+ if [ -e $LOCK_FILE ]; then
43
+ LAST_LOCK_PID=`cat $LOCK_FILE`
44
+ if [ -n $LAST_LOCK_PID -a -z "`ps axo pid|grep $LAST_LOCK_PID`" -a -f $LOCK_FILE ];then
45
+ sleep 1
46
+ logger -t "monit-dj:$WORKER[$$]" "Removing stale lock file for $WORKER ($LAST_LOCK_PID)"
47
+ rm $LOCK_FILE 2>&1
48
+ else
49
+ logger -t "monit-dj:$WORKER[$$]" "Monit already messing with $WORKER ($LAST_LOCK_PID)"
50
+ RESULT=1
51
+ exit_cleanly
52
+ fi
53
+ fi
54
+ echo $$ > $LOCK_FILE
55
+ }
56
+
57
+ exit_cleanly() {
58
+ cd $CURDIR
59
+ logger -t "mont-dj:$WORKER[$$]" "exiting wrapper cleanly with $RESULT"
60
+ exit $RESULT
61
+ }
62
+
63
+ unlock_and_exit_cleanly(){
64
+ rm_lockfile
65
+ exit_cleanly
66
+ }
67
+
68
+ ## End function definitions ##
69
+ #set -x
70
+ WORKER=$1$NAME
71
+ LOCK_FILE="/tmp/$WORKER.monit-lock"
72
+ BUNDLER_COMMAND="ruby"
73
+ RAILS_ROOT=/data/$1/current
74
+ if [ -d $RAILS_ROOT ]; then
75
+ if [ -f $RAILS_ROOT/Gemfile ]; then
76
+ if [ -d $RAILS_ROOT/ey_bundler_binstubs ]; then
77
+ PATH=$RAILS_ROOT/ey_bundler_binstubs:$PATH
78
+ else
79
+ BUNDLER_COMMAND="bundle exec ruby"
80
+ fi
81
+ fi
82
+
83
+ RAILS_ENV=$3
84
+ export $RAILS_ENV
85
+ RUNNER='runner'
86
+ #RAILS_SCRIPTS="$RAILS_ROOT/script"
87
+ RAILS_SCRIPTS="$RAILS_ROOT/script"
88
+ [ -f $RAILS_SCRIPTS/rails ] && chmod a+x $RAILS_SCRIPTS/rails && RUNNER="rails runner"
89
+ cd $RAILS_ROOT
90
+ PID_FILE=/var/run/engineyard/dj/$1/dj$NAME.pid
91
+ USER=`stat -c"%U" /data/$1/current/`
92
+ HOME="/home/$USER" ; export HOME
93
+ RESULT=0
94
+ GRACE_TIME=${GRACE_TIME:-60}
95
+ let "GRACE_TIME=$GRACE_TIME*4"
96
+
97
+ mkdir -p /var/run/engineyard/dj/$1
98
+
99
+ case "$2" in
100
+ start)
101
+ lock
102
+ cd $RAILS_ROOT
103
+ HAS_DJ_COMMAND="RAILS_ENV=$RAILS_ENV $BUNDLER_COMMAND $RAILS_SCRIPTS/$RUNNER -e $RAILS_ENV \"require 'delayed/command';puts defined?(Delayed::Command)\" 2>/dev/null"
104
+ has_dj_command=$(sudo -u $USER -H /bin/bash -c "$HAS_DJ_COMMAND")
105
+ if [[ $has_dj_command == "constant" ]];then
106
+ OPTIONS=${OPTIONS:-[]}
107
+ HAS_BEFORE_FORK="RAILS_ENV=$RAILS_ENV $BUNDLER_COMMAND $RAILS_SCRIPTS/$RUNNER -e $RAILS_ENV \"require 'delayed/worker';puts Delayed::Worker.respond_to?(:before_fork)\" 2>/dev/null"
108
+ has_before_fork=$(sudo -u $USER -H /bin/bash -c "$HAS_BEFORE_FORK")
109
+ if [[ $has_before_fork == "true" ]];then
110
+ RUNNER_COMMAND="require 'delayed/command';Delayed::Worker.before_fork;Delayed::Command.new($OPTIONS).run"
111
+ else
112
+ RUNNER_COMMAND="require 'delayed/command';Delayed::Command.new($OPTIONS).run"
113
+ fi
114
+ else
115
+ RUNNER_COMMAND="Delayed::Worker.new($OPTIONS).start"
116
+ fi
117
+
118
+ COMMAND="$BUNDLER_COMMAND $RAILS_SCRIPTS/$RUNNER -e $RAILS_ENV \"$RUNNER_COMMAND\""
119
+ logger -t "monit-dj:$WORKER[$$]" "DJ Worker starting from $PPID"
120
+ if [ -f $PID_FILE ]; then
121
+ PID=`cat $PID_FILE`
122
+ if [ -n "$PID" ];then
123
+ logger -t "monit-dj:$WORKER[$$]" "There is already a PID file for delayed Job [$PID]"
124
+ if [ -d /proc/$PID ]; then
125
+ logger -t "monit-dj:$WORKER[$$]" "Dj worker is already running with PID of $PID"
126
+ RESULT=1
127
+ else
128
+ logger -t "monit-dj:$WORKER[$$]" "Removing stale pid file for $WORKER"
129
+ rm -f $PID_FILE
130
+ fi
131
+ fi
132
+ fi
133
+
134
+ if [ $RESULT -eq 0 ]; then
135
+ logger -t "monit-dj:$WORKER[$$]" "issuing command $COMMAND in $PWD for $USER"
136
+ sudo -u $USER -H /bin/bash -c "$COMMAND" &
137
+ NEW_PID=$!
138
+ RESULT=$?
139
+ logger -t "monit-dj:$WORKER[$$]" "$WORKER started as $NEW_PID : $RESULT"
140
+ echo $NEW_PID > $PID_FILE
141
+ fi
142
+ unlock_and_exit_cleanly
143
+ ;;
144
+ stop)
145
+ lock
146
+ logger -t "monit_dj:$WORKER[$$]" "Stopping DJ worker:"
147
+ if [ -f $PID_FILE ]; then
148
+ PID=$(cat $PID_FILE)
149
+
150
+ # Find children
151
+ WORKER_PID=$(ps axo pid,ppid,command|awk '$2=='$PID' {print $1}')
152
+
153
+ kill -15 $PID $PPID; # kill worker and any child that it may have at this very moment
154
+ logger -t "monit-dj:$WORKER[$$]" "Stopping DJ Worker Process $PID $PPID"
155
+
156
+ SLEEP_COUNT=0
157
+ while [ -e /proc/$PID ]; do
158
+ sleep .25
159
+ let "SLEEP_COUNT+=1"
160
+ let "REPORT_TIME = $SLEEP_COUNT%4"
161
+ if(( "$SLEEP_COUNT" > $GRACE_TIME )); then
162
+ logger -t "monit-dj:$WORKER[$$]" "Stopping DJ Worker Child Process $PID wait exceeded, killing it"
163
+ kill -9 $PID 2>/dev/null; true
164
+ break
165
+ elif(( $REPORT_TIME == 0 ));then
166
+ let "RUNTIME = $SLEEP_COUNT/4"
167
+ logger -t "monit-dj:$WORKER[$$]" "Waiting for $PID to die ( for $RUNTIME seconds now)"
168
+ fi
169
+ done
170
+ fi
171
+
172
+ [ -e "$PID_FILE" ] && rm -f $PID_FILE
173
+ unlock_and_exit_cleanly
174
+ ;;
175
+ *)
176
+ usage
177
+ ;;
178
+ esac
179
+ else
180
+ echo "/data/$1/current doesn't exist."
181
+ usage
182
+ fi
@@ -0,0 +1,6 @@
1
+ check process <%= @worker_name %>
2
+ with pidfile /var/run/engineyard/dj/<%= @app_name %>/dj_<%= @worker_name %>.pid
3
+ start program = "/engineyard/bin/dj <%= @app_name %> start <%= @framework_env %> <%= @worker_name %>" with timeout 60 seconds
4
+ stop program = "/engineyard/bin/dj <%= @app_name %> stop <%= @framework_env %> <%= @worker_name %>" with timeout 60 seconds
5
+ if totalmem is greater than 300 MB then restart # eating up memory?
6
+ group dj_<%= @app_name %>
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eycloud-recipe-delayed_job
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dr Nic Williams
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70271935729380 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70271935729380
25
+ description: Delayed Job for EY Cloud
26
+ email:
27
+ - drnicwilliams@gmail.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - Gemfile.lock
35
+ - README.markdown
36
+ - Rakefile
37
+ - eycloud-recipe-delayed_job.gemspec
38
+ - libraries/delayed_job_applications.rb
39
+ - libraries/delayed_job_worker_count.rb
40
+ - metadata.json
41
+ - metadata.rb
42
+ - recipes/configure.rb
43
+ - recipes/default.rb
44
+ - recipes/install.rb
45
+ - recipes/restart.rb
46
+ - templates/default/dj.erb
47
+ - templates/default/dj.monitrc.erb
48
+ homepage: ''
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ segments:
61
+ - 0
62
+ hash: -3120554601435364730
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ segments:
70
+ - 0
71
+ hash: -3120554601435364730
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 1.8.17
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Delayed Job for EY Cloud
78
+ test_files: []