rails_daemons 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 341d44fec654ca5a7bd975916ab575d877103b1c
4
+ data.tar.gz: 171b1b87e26e5468321c4683e82e93bf598fb643
5
+ SHA512:
6
+ metadata.gz: 1623e1db2fea6fc3f69f4b2ca4680453c4ab59a8eda59dfd117394b62ba5aeac725f2dcef972122bebe397622a829790f01a42007318343f601076c404261a90
7
+ data.tar.gz: 3cdabbaeb5782b96c560296afb3b2e488fda08d62fb2d6cf4f090bf0d6b3509328b289ad3970a29de81928fb378f2e755604775d22e4f841e54eb142f9fb9432
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ rails_daemons
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.5
data/Capfile ADDED
@@ -0,0 +1,25 @@
1
+ # Load DSL and Setup Up Stages
2
+ require 'capistrano/setup'
3
+
4
+ # Includes default deployment tasks
5
+ require 'capistrano/deploy'
6
+
7
+ # Includes tasks from other gems included in your Gemfile
8
+ #
9
+ # For documentation on these, see for example:
10
+ #
11
+ # https://github.com/capistrano/rvm
12
+ # https://github.com/capistrano/rbenv
13
+ # https://github.com/capistrano/chruby
14
+ # https://github.com/capistrano/bundler
15
+ # https://github.com/capistrano/rails/tree/master/assets
16
+ # https://github.com/capistrano/rails/tree/master/migrations
17
+ #
18
+ # require 'capistrano/rvm'
19
+ # require 'capistrano/rbenv'
20
+ # require 'capistrano/chruby'
21
+ # require 'capistrano/bundler'
22
+ # require 'capistrano/rails/assets'
23
+ # require 'capistrano/rails/migrations'
24
+
25
+ require 'rails_daemons/capistrano'
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rails_daemons.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Sergey Malykh
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,218 @@
1
+ # RailsDaemons
2
+
3
+ Background workers for Rails. The gem is designed to safely handling exceptions occured in workers. Daemons restarts gracefully to achieve zerro downtime. RailsDaemons includes [Capistrano](https://github.com/capistrano/capistrano) and [Monit](https://mmonit.com/monit/) support. The gem also supports logrotate by safely handling signal USR1.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rails_daemons'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rails_daemons
18
+
19
+ ## Capistrano integration
20
+
21
+ Add ```require 'rails_daemons/capistrano'``` to Capfile
22
+
23
+ This will get available commands:
24
+
25
+ ```
26
+ cap production daemon:start[<worker_name>]
27
+ cap production daemon:restart[<worker_name>]
28
+ cap production daemon:stop[<worker_name>]
29
+ ```
30
+
31
+ ## Background worker controls
32
+
33
+ ```
34
+ bundle exec daemon start <worker_name>
35
+ bundle exec daemon restart <worker_name>
36
+ bundle exec daemon stop <worker_name>
37
+ ```
38
+
39
+ ## Worker construction
40
+
41
+ Create background worker.
42
+
43
+ ```ruby
44
+ class ParserWorker
45
+ include RailsDaemons::Worker
46
+
47
+ def work
48
+ # your work here
49
+ end
50
+ end
51
+ ```
52
+
53
+ Also you can specify:
54
+
55
+ * ```tick``` - delay between daemon cycles (in seconds, default 1.0)
56
+ * ```start``` - work that should be done once on the daemon`s start (and restart)
57
+ * ```shutdown``` - work that should be done before the daemon`s stop (either on exception or regular stop)
58
+
59
+ Example usage (with Mongoid):
60
+
61
+ ```ruby
62
+ # app/models/parsing.rb
63
+ class Parsing
64
+ include Mongoid::Document
65
+
66
+ field :url
67
+ field :state, default: 'pending'
68
+
69
+ scope :pending, ->() { where( state: 'pending' ) }
70
+ scope :running, ->() { where( state: 'running' ) }
71
+
72
+ class << self
73
+ def start
74
+ [ 'http://www.example.com' ].each do |url|
75
+ create!( url: url )
76
+ end
77
+ end
78
+ end
79
+
80
+ def process( logger )
81
+ set( state: 'running' )
82
+
83
+ # do the job
84
+
85
+ rescue => e
86
+ logger.info e.inspect
87
+
88
+ set( state: 'halted' )
89
+ end
90
+ end
91
+
92
+ # app/daemons/parser_worker.rb
93
+ class ParserWorker
94
+ include RailsDaemons::Worker
95
+
96
+ def tick
97
+ 3 # in seconds
98
+ end
99
+
100
+ # daemon start
101
+ def start
102
+ require 'mechanize'
103
+ require 'rufus-scheduler'
104
+
105
+ scheduler = Rufus::Scheduler.new
106
+
107
+ scheduler.every '12h' do
108
+ Parsing.start # create parsing jobs every 12 hours
109
+ end
110
+ end
111
+
112
+ # main work
113
+ def work
114
+ Parsing.pending.each do |parsing|
115
+ t = Thread.new do
116
+ parsing.process( $logger )
117
+ end
118
+
119
+ # exceptions handled in method ```process``` (just for an example)
120
+ t.abort_on_exception = false
121
+ end
122
+ end
123
+
124
+ # stop the daemon
125
+ def shutdown
126
+ Parsing.running.each do |parsing|
127
+ parsing.set( state: 'stopped' )
128
+ end
129
+ end
130
+ end
131
+
132
+ ```
133
+
134
+ ## Monit integration:
135
+
136
+ Put the following code to /etc/init.d/<worker_name>, replace <worker_name> with you name.
137
+
138
+ ```
139
+ #!/bin/bash
140
+ ### BEGIN INIT INFO
141
+ # Provides: <worker_name>
142
+ # Required-Start: $all
143
+ # Required-Stop: $network $local_fs $syslog
144
+ # Default-Start: 2 3 4 5
145
+ # Default-Stop: 0 1 6
146
+ # Short-Description: Start daemon at boot
147
+ # Description: Enable daemon at boot time.
148
+ ### END INIT INFO
149
+
150
+ set -u
151
+ set -e
152
+
153
+ # Change these to match your app:
154
+ APP_NAME=app
155
+ ENV=production
156
+ USER=user
157
+ APP_ROOT="/home/$USER/$APP_NAME/current"
158
+
159
+ SET_PATH="cd $APP_ROOT; rvm use `cat $APP_ROOT/.ruby-version`@`cat $APP_ROOT/.ruby-gemset`"
160
+ OUT=">> $APP_ROOT/log/worker_name.$ENV.monit.log 2>&1"
161
+
162
+ cd $APP_ROOT || exit 1
163
+
164
+ case ${1-help} in
165
+ start)
166
+ su - $USER -c "$SET_PATH; RAILS_ENV=$ENV bundle exec daemon start <worker_name> $OUT"
167
+ ;;
168
+ stop)
169
+ su - $USER -c "$SET_PATH; RAILS_ENV=$ENV bundle exec daemon stop <worker_name> $OUT"
170
+ ;;
171
+ restart|reload)
172
+ su - $USER -c "$SET_PATH; RAILS_ENV=$ENV bundle exec daemon restart <worker_name> $OUT"
173
+ ;;
174
+ *)
175
+ echo >&2 "Usage: $0 <start|stop|restart>"
176
+ exit 1
177
+ ;;
178
+ esac
179
+ ```
180
+
181
+ Monit task:
182
+
183
+ ```
184
+ check process <worker_name> with pidfile /<path_to_project>/current/tmp/pids/<worker_name>.production.pid
185
+ start program = "/etc/init.d/<worker_name> start"
186
+ stop program = "/etc/init.d/<worker_name> stop"
187
+ if changed pid for 3 times within 5 cycles then restart
188
+ if 5 restarts within 5 cycles then timeout
189
+ ```
190
+
191
+ ## Logrotate integration
192
+
193
+ ```
194
+ /<path_to_project>/shared/log/*.log
195
+ {
196
+ su <user> <group>
197
+ daily
198
+ missingok
199
+ rotate 360
200
+ compress
201
+ delaycompress
202
+ notifempty
203
+ dateext
204
+ create 0660 <user> <group>
205
+ postrotate
206
+ [ ! -f /<path_to_project>/shared/tmp/pids/unicorn.pid ] || kill -USR1 `cat /<path_to_project>/shared/tmp/pids/unicorn.pid`
207
+ [ ! -f /<path_to_project>/shared/tmp/pids/<worker_name>.production.pid ] || kill -USR1 `cat /<path_to_project>/shared/tmp/pids/<worker_name>.production.pid`
208
+ endscript
209
+ }
210
+ ```
211
+
212
+ ## Contributing
213
+
214
+ 1. Fork it
215
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
216
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
217
+ 4. Push to the branch (`git push origin my-new-feature`)
218
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/Thorfile ADDED
@@ -0,0 +1,14 @@
1
+ # https://shvets.github.io/blog/2013/12/14/using_thor_as_rake_replacement.html
2
+ unless defined? Thor::Runner
3
+ require 'bundler'
4
+
5
+ gems = Bundler::Definition.build(Bundler.default_gemfile, Bundler.default_lockfile, nil).requested_specs
6
+
7
+ gem = gems.find { |gem| gem.name == 'thor' }
8
+
9
+ load "#{ENV['GEM_HOME']}/gems/#{gem.name}-#{gem.version}/bin/thor"
10
+ end
11
+
12
+ Dir.glob("lib/rails_daemons/tasks/*.thor") do |name|
13
+ Thor::Util.load_thorfile(name)
14
+ end
data/bin/daemon ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
3
+ require 'rails_daemons/thor'
4
+ RailsDaemons::Daemon.start
@@ -0,0 +1,6 @@
1
+ require "rails_daemons/version"
2
+ require "rails_daemons/railtie" if defined?(Rails)
3
+ require "rails_daemons/worker"
4
+
5
+ module RailsDaemons
6
+ end
@@ -0,0 +1,7 @@
1
+ require 'capistrano/version'
2
+
3
+ if defined?(Capistrano::Version) && Gem::Version.new(Capistrano::Version).release < Gem::Version.new("3.0")
4
+ raise "RailsDaemons requires Capistrano 3.x"
5
+ end
6
+
7
+ load File.expand_path("../tasks/rails_daemons.cap", __FILE__)
@@ -0,0 +1,4 @@
1
+ module RailsDaemons
2
+ class Railtie < Rails::Railtie
3
+ end
4
+ end
@@ -0,0 +1,40 @@
1
+ namespace :daemon do
2
+ desc 'Start background worker'
3
+ task :start, :worker_name do |task, args|
4
+ raise 'Worked is not specified' if args[:worker_name].nil?
5
+
6
+ on roles(:app) do
7
+ within release_path do
8
+ with rails_env: fetch(:rails_env) do
9
+ execute :bundle, :exec, :daemon, "start #{args[:worker_name]}"
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ desc 'Restart background worker'
16
+ task :restart, :worker_name do |task, args|
17
+ raise 'Worked is not specified' if args[:worker_name].nil?
18
+
19
+ on roles(:app) do
20
+ within release_path do
21
+ with rails_env: fetch(:rails_env) do
22
+ execute :bundle, :exec, :daemon, "restart #{args[:worker_name]}"
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ desc 'Stop background worker'
29
+ task :stop, :worker_name do |task, args|
30
+ raise 'Worked is not specified' if args[:worker_name].nil?
31
+
32
+ on roles(:app) do
33
+ within release_path do
34
+ with rails_env: fetch(:rails_env) do
35
+ execute :bundle, :exec, :daemon, "stop #{args[:worker_name]}"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,33 @@
1
+ require 'thor/rails'
2
+
3
+ module ::RailsDaemons
4
+ class Daemon < Thor
5
+ include Thor::Rails
6
+ namespace :daemon
7
+
8
+ no_commands do
9
+ def get_daemon( name )
10
+ RailsDaemons.qualified_const_get( name.camelize )
11
+ rescue NameError => e
12
+ puts "Unknown daemon '#{name}'"
13
+ end
14
+ end
15
+
16
+ desc "start <worker_name>", "Start background worker"
17
+ def start( name )
18
+ daemon = get_daemon( name )
19
+ return if daemon.nil?
20
+ daemon.new.daemonize
21
+ end
22
+
23
+ desc "restart <worker_name>", "Restart background worker (alias for start command)"
24
+ def restart( name )
25
+ invoke :start, [ name ]
26
+ end
27
+
28
+ desc "stop <worker_name>", "Stop background worker"
29
+ def stop( name )
30
+ get_daemon( name ).stop
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,2 @@
1
+ require 'thor'
2
+ Thor::Util.load_thorfile File.expand_path("../tasks/rails_daemons.thor", __FILE__)
@@ -0,0 +1,25 @@
1
+ module RailsDaemons
2
+ module Utils
3
+ extend self
4
+
5
+ def join( *paths )
6
+ # TODO: remove this dirty code
7
+ return Rails.root.join( *paths ) if Rails.root.to_s !~ /.*\/releases\/\d{14}/
8
+
9
+ paths = [ '..', '..', 'current' ] + paths
10
+
11
+ path = Rails.root.join( *paths )
12
+ FileUtils.mkdir_p( File.dirname( path ) )
13
+ path
14
+ end
15
+
16
+ def logger( file_name )
17
+ logger = Logger.new( join( 'log', file_name ) )
18
+ logger.level = Logger::INFO
19
+ logger.datetime_format = "%Y-%m-%d %H:%M:%S"
20
+ logger.formatter = Logger::Formatter.new
21
+
22
+ logger
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module RailsDaemons
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,214 @@
1
+ require 'rails_daemons/utils'
2
+ require 'unicorn/util'
3
+ require 'active_support/concern'
4
+
5
+ module RailsDaemons
6
+ module Worker
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ def daemonize
11
+ pid = fork do
12
+ $logger = Utils.logger( "#{self.class.worker_name}.#{Rails.env}.log" )
13
+ $logger.level = Logger::INFO
14
+
15
+ working
16
+ end
17
+
18
+ Process.detach( pid )
19
+
20
+ puts "#{self.class.worker_name} (#{pid}) started."
21
+ end
22
+
23
+ def working
24
+ $stop_working = false
25
+ $reopening = false
26
+
27
+ Signal.trap "INT" do
28
+ Thread.new do
29
+ shutdowning
30
+ end
31
+ end
32
+
33
+ Signal.trap "USR1" do
34
+ $reopening = true
35
+ end
36
+
37
+ stop_old_worker
38
+
39
+ starting
40
+
41
+ loop do
42
+ reopen_logs if $reopening
43
+ break if $stop_working
44
+
45
+ work
46
+
47
+ sleep tick
48
+ end
49
+ end
50
+
51
+ def reopen_logs
52
+ pid = self.class.get_pid
53
+
54
+ logger.info "Reopen logs #{self.class.worker_name} (#{pid})"
55
+
56
+ Unicorn::Util.reopen_logs
57
+
58
+ logger.info "Logs reopened #{self.class.worker_name} (#{pid})"
59
+
60
+ $reopening = false
61
+ end
62
+
63
+ def logger
64
+ $logger
65
+ end
66
+
67
+ def starting
68
+ $0 = "RAILS_ENV=#{Rails.env} " + Utils.join( '' ).to_s + " bundle exec thor daemon:start #{self.class}"
69
+
70
+ redirect_io
71
+ start
72
+ store_pid
73
+ end
74
+
75
+ def redirect_io
76
+ # https://github.com/ghazel/daemons/blob/d09e132ea67001ba4d6bf6481fb53c4bd4fd9195/lib/daemons/daemonize.rb#L241
77
+ begin; STDIN.reopen "/dev/null"; rescue ::Exception; end
78
+
79
+ begin
80
+ STDOUT.reopen( Utils.join( 'log', "#{self.class.worker_name}.#{Rails.env}.out.log" ), "a" )
81
+ STDOUT.sync = true
82
+ rescue ::Exception
83
+ begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
84
+ end
85
+
86
+ begin; STDERR.reopen STDOUT; rescue ::Exception; end
87
+ STDERR.sync = true
88
+ end
89
+
90
+ def start
91
+ puts "Start #{self.class.name}"
92
+ end
93
+
94
+ def work
95
+ raise 'Not implemented! Write your own work'
96
+ end
97
+
98
+ def tick
99
+ 1.0
100
+ end
101
+
102
+ def shutdowning
103
+ pid = self.class.get_pid
104
+
105
+ logger.info "Graceful shutdown #{self.class.worker_name} (#{pid})"
106
+ $stop_working = true
107
+
108
+ shutdown
109
+
110
+ puts "#{self.class.worker_name} (#{pid}) stopped."
111
+
112
+ exit 0
113
+
114
+ rescue => e
115
+ logger.error "exiting #{self.class.worker_name}, unable to stop gracefully"
116
+ logger.error e.message
117
+ logger.error e.backtrace.join( "\n" )
118
+
119
+ File.remove( self.class.pid_file ) if File.exists?( self.class.pid_file )
120
+
121
+ exit 1
122
+ end
123
+
124
+ def shutdown
125
+ end
126
+
127
+ def stop_old_worker
128
+ return unless File.file?( self.class.pid_file )
129
+
130
+ pid = self.class.get_pid
131
+
132
+ unless self.class.running?( pid )
133
+ logger.info "Stale pid file (#{pid}), deleting"
134
+ File.delete( self.class.pid_file )
135
+
136
+ return
137
+ end
138
+
139
+ logger.info "Killing old worker (#{pid})"
140
+ Process.kill( "INT", pid )
141
+
142
+ # wait for die
143
+ 32.times do
144
+ sleep 3
145
+
146
+ unless self.class.running?( pid )
147
+ logger.info "Old worker (#{pid}) died by himself"
148
+
149
+ return
150
+ end
151
+ end
152
+
153
+ return unless self.class.running?( pid )
154
+
155
+ logger.error "Old worker (#{pid}) isn't going to die, doing kill -9"
156
+
157
+ Process.kill( "KILL", pid )
158
+ File.delete( self.class.pid_file )
159
+ end
160
+
161
+ def store_pid
162
+ FileUtils.mkdir_p( File.dirname( self.class.pid_file ) )
163
+ IO.write( self.class.pid_file, Process.pid.to_s )
164
+ end
165
+ end
166
+
167
+ module ClassMethods
168
+ def daemonize
169
+ self.new.daemonize
170
+ end
171
+
172
+ def stop
173
+ pid = get_pid
174
+
175
+ if running?( pid )
176
+ Process.kill( 'INT', pid )
177
+ else
178
+ puts "Worker #{name} (#{pid}) not running"
179
+ end
180
+ end
181
+
182
+ def get_pid
183
+ return unless File.exists?( pid_file )
184
+ File.read( pid_file ).to_i
185
+ end
186
+
187
+ def pid_file
188
+ Utils.join( 'tmp', 'pids', "#{worker_name}.#{Rails.env}.pid" )
189
+ end
190
+
191
+ def worker_name
192
+ name.underscore
193
+ end
194
+
195
+ def running?( pid )
196
+ return false if pid.blank?
197
+
198
+ # https://github.com/ghazel/daemons/blob/d09e132ea67001ba4d6bf6481fb53c4bd4fd9195/lib/daemons/pid.rb#L17
199
+ # Check if process is in existence
200
+ # The simplest way to do this is to send signal '0'
201
+ # (which is a single system call) that doesn't actually
202
+ # send a signal
203
+ begin
204
+ Process.kill(0, pid)
205
+ return true
206
+ rescue Errno::ESRCH
207
+ return false
208
+ rescue ::Exception # for example on EPERM (process exists but does not belong to us)
209
+ return true
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'rails_daemons/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rails_daemons"
7
+ spec.version = RailsDaemons::VERSION
8
+ spec.authors = ["Sergey Malykh"]
9
+ spec.email = ["xronos.i.am@gmail.com"]
10
+ spec.description = %q{Daemons for Rails. Can be restarted on the host by Thor or remotely by Capistrano, monitored by Monit}
11
+ spec.summary = %q{Daemons for Rails}
12
+ spec.homepage = "https://github.com/xronos-i-am/rails_daemons"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "capistrano", '~> 3.3'
21
+ spec.add_development_dependency "bundler"
22
+
23
+ spec.add_dependency "unicorn"
24
+ spec.add_dependency "thor-rails"
25
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_daemons
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Sergey Malykh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capistrano
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: unicorn
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: thor-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Daemons for Rails. Can be restarted on the host by Thor or remotely by
70
+ Capistrano, monitored by Monit
71
+ email:
72
+ - xronos.i.am@gmail.com
73
+ executables:
74
+ - daemon
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - ".ruby-gemset"
80
+ - ".ruby-version"
81
+ - Capfile
82
+ - Gemfile
83
+ - LICENSE.txt
84
+ - README.md
85
+ - Rakefile
86
+ - Thorfile
87
+ - bin/daemon
88
+ - lib/rails_daemons.rb
89
+ - lib/rails_daemons/capistrano.rb
90
+ - lib/rails_daemons/railtie.rb
91
+ - lib/rails_daemons/tasks/rails_daemons.cap
92
+ - lib/rails_daemons/tasks/rails_daemons.thor
93
+ - lib/rails_daemons/thor.rb
94
+ - lib/rails_daemons/utils.rb
95
+ - lib/rails_daemons/version.rb
96
+ - lib/rails_daemons/worker.rb
97
+ - rails_daemons.gemspec
98
+ homepage: https://github.com/xronos-i-am/rails_daemons
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.4.4
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Daemons for Rails
122
+ test_files: []