cronic 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +3 -0
- data/LICENSE +20 -0
- data/README.md +125 -0
- data/lib/cronic.rb +1 -0
- data/lib/cronic/recipes.rb +58 -0
- data/lib/cronic/scheduler.rb +42 -0
- data/lib/cronic/version.rb +3 -0
- data/lib/generators/cronic_generator.rb +14 -0
- data/recipes/cronic.rb +1 -0
- metadata +104 -0
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Jens Krämer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
Cronic
|
2
|
+
======
|
3
|
+
|
4
|
+
Motivation
|
5
|
+
----------
|
6
|
+
|
7
|
+
While nothing is wrong with Unix cron, it is not the best choice for
|
8
|
+
regular jobs that require to be run in the context of your Rails
|
9
|
+
application. Spinning up an instance of the application every 10 minutes
|
10
|
+
for a job that needs to run this frequently is just a waste of CPU cycles, let
|
11
|
+
alone the increased memory usage in case different jobs are running in
|
12
|
+
parallel.
|
13
|
+
|
14
|
+
Building blocks
|
15
|
+
---------------
|
16
|
+
|
17
|
+
Cronic itself is only a tiny bit of glue code and a Rails generator.
|
18
|
+
|
19
|
+
The scheduling itself is done by [Rufus
|
20
|
+
Scheduler](https://github.com/jmettraux/rufus-scheduler) . I like this
|
21
|
+
particular library because it allows you fine grained control over which
|
22
|
+
jobs may be run in parallel and which have to be run in sequence via
|
23
|
+
mutexes. It also can avoid overlapping with long running jobs. These are
|
24
|
+
things that you have to take care of yourself when using Unix cron.
|
25
|
+
The daemonizing part is provided by
|
26
|
+
[Dante](https://github.com/bazaarlabs/dante), which is amazingly easy
|
27
|
+
to use and 'just works'.
|
28
|
+
Optional Airbrake integration is also included.
|
29
|
+
|
30
|
+
|
31
|
+
Usage
|
32
|
+
-----
|
33
|
+
|
34
|
+
Three easy steps:
|
35
|
+
|
36
|
+
**Add Cronic to your Gemfile and run Bundler**
|
37
|
+
|
38
|
+
echo "gem 'cronic'" >> Gemfile
|
39
|
+
bundle install
|
40
|
+
|
41
|
+
**Run the Rails generator and create job definitions**
|
42
|
+
|
43
|
+
rails g cronic
|
44
|
+
|
45
|
+
This will set up `script/cronic`, which you will use to start / stop the
|
46
|
+
daemon. It also creates the `config/cronic.d` directory where you will
|
47
|
+
store your job definitions. Have a look at `config/cronic.d/sample.rb`
|
48
|
+
to get an idea of how to define your jobs. For more information, be sure
|
49
|
+
to visit the Rufus-Scheduler documentation. Every method that is
|
50
|
+
available on a Rufus::Scheduler instance can be called in the job
|
51
|
+
definition files located in `config/cronic.d`.
|
52
|
+
|
53
|
+
**Run it**
|
54
|
+
|
55
|
+
script/cronic -d -l log/cronic.log -P tmp/pids/cronic.pid
|
56
|
+
|
57
|
+
This will run cronic daemonized, logging to log/cronic.log, with a pid
|
58
|
+
file located in tmp/pids. To run in the forground for testing purposes,
|
59
|
+
just run the script without any parameters.
|
60
|
+
|
61
|
+
In order to stop the daemon, run
|
62
|
+
|
63
|
+
script/cronic -k -P tmp/pids/cronic.pid
|
64
|
+
|
65
|
+
|
66
|
+
Error handling
|
67
|
+
--------------
|
68
|
+
|
69
|
+
Any exception thrown during job execution will be caught and logged to
|
70
|
+
STDOUT (which goes into the log file specified on the command line). If
|
71
|
+
you have [Airbrake](https://github.com/airbrake/airbrake) set up for
|
72
|
+
your application, exceptions will also be reported via
|
73
|
+
`Airbrake.notify`.
|
74
|
+
|
75
|
+
|
76
|
+
Capistrano
|
77
|
+
----------
|
78
|
+
|
79
|
+
In order to stop / start / restart Cronic automatically when deploying
|
80
|
+
with capistrano, follow these steps:
|
81
|
+
|
82
|
+
**Include the Cronic recipes in your Capfile or deploy.rb**
|
83
|
+
|
84
|
+
require 'cronic/recipes'
|
85
|
+
|
86
|
+
**Hook Cronic tasks to Capistrano's tasks**
|
87
|
+
|
88
|
+
after "deploy:stop", "cronic:stop"
|
89
|
+
after "deploy:start", "cronic:start"
|
90
|
+
after "deploy:restart", "cronic:restart"
|
91
|
+
|
92
|
+
**Optional: customize task behaviour**
|
93
|
+
|
94
|
+
set :rails_env, 'production' # this is the default
|
95
|
+
|
96
|
+
# relative to current_path, defaults to log/cronic.log
|
97
|
+
set :cronic_log, 'some/log/file'
|
98
|
+
|
99
|
+
# relative to current_path, defaults to tmp/pids/cronic.pid
|
100
|
+
set :cronic_pid, 'some/pid/file'
|
101
|
+
|
102
|
+
# custom role to have it run on a special server
|
103
|
+
role :cron, 'dedicated.cron.server'
|
104
|
+
set :cronic_server_role, :cron
|
105
|
+
|
106
|
+
|
107
|
+
Monitoring
|
108
|
+
----------
|
109
|
+
|
110
|
+
The [Dante docs](https://github.com/bazaarlabs/dante) have an example
|
111
|
+
god script that you can use as a starting point for ensuring your
|
112
|
+
cronic daemon stays up and running.
|
113
|
+
|
114
|
+
|
115
|
+
Copyright
|
116
|
+
---------
|
117
|
+
|
118
|
+
Copyright 2012 Jens Krämer, jk@jkraemer.net
|
119
|
+
See [LICENSE](https://github.com/jkraemer/cronic/blob/master/LICENSE)
|
120
|
+
for details.
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
|
data/lib/cronic.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "cronic/scheduler"
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Capistrano Recipes for managing the cronic daemon
|
2
|
+
#
|
3
|
+
# Add these callbacks to have the cronic process restart when the server
|
4
|
+
# is restarted:
|
5
|
+
#
|
6
|
+
# after "deploy:stop", "cronic:stop"
|
7
|
+
# after "deploy:start", "cronic:start"
|
8
|
+
# after "deploy:restart", "cronic:restart"
|
9
|
+
#
|
10
|
+
# To only spawn the cronic daemon on a specific server specify the
|
11
|
+
# cronic_server_role:
|
12
|
+
#
|
13
|
+
# set :cronic_server_role, :cron
|
14
|
+
#
|
15
|
+
# You may change the log and pid file locations by defining :cronic_log and
|
16
|
+
# :cronic_pid. The RAILS_ENV defaults to production and may be changed by
|
17
|
+
# setting :rails_env.
|
18
|
+
#
|
19
|
+
|
20
|
+
Capistrano::Configuration.instance.load do
|
21
|
+
namespace :cronic do
|
22
|
+
def rails_env
|
23
|
+
"RAILS_ENV=#{fetch(:rails_env, 'production')}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def roles
|
27
|
+
fetch(:cronic_server_role, :app)
|
28
|
+
end
|
29
|
+
|
30
|
+
def cronic_log
|
31
|
+
fetch :cronic_log, 'log/cronic.log'
|
32
|
+
end
|
33
|
+
|
34
|
+
def cronic_pid
|
35
|
+
fetch :cronic_pid, 'tmp/pids/cronic.pid'
|
36
|
+
end
|
37
|
+
|
38
|
+
def cronic_command
|
39
|
+
fetch(:cronic_command, "script/cronic")
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Stop the cronic process"
|
43
|
+
task :stop, :roles => lambda { roles } do
|
44
|
+
run "cd #{current_path};#{rails_env} #{cronic_command} -k -P #{cronic_pid}"
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "Start the cronic process"
|
48
|
+
task :start, :roles => lambda { roles } do
|
49
|
+
run "cd #{current_path};#{rails_env} #{cronic_command} -d -l #{cronic_log} -P #{cronic_pid}"
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Restart the cronic process"
|
53
|
+
task :restart, :roles => lambda { roles } do
|
54
|
+
stop
|
55
|
+
start
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rufus/scheduler'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'airbrake'
|
5
|
+
rescue LoadError
|
6
|
+
# ignore
|
7
|
+
end
|
8
|
+
|
9
|
+
module Cronic
|
10
|
+
class Scheduler
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@rufus_scheduler = Rufus::Scheduler.start_new
|
14
|
+
setup_exception_handler
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_jobs(file)
|
18
|
+
@rufus_scheduler.instance_eval IO.read file
|
19
|
+
end
|
20
|
+
|
21
|
+
# blocks until the scheduler exits for some reason
|
22
|
+
def join
|
23
|
+
@rufus_scheduler.join
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def setup_exception_handler
|
29
|
+
@rufus_scheduler.class_eval do
|
30
|
+
define_method :handle_exception do |job, exception|
|
31
|
+
puts "job #{job.job_id} caught exception '#{exception}'"
|
32
|
+
if defined?(Airbrake)
|
33
|
+
Airbrake.notify exception
|
34
|
+
else
|
35
|
+
puts exception.backtrace.join("\n")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CronicGenerator < Rails::Generators::Base
|
2
|
+
source_root File.expand_path("../../../templates", __FILE__)
|
3
|
+
|
4
|
+
desc "Creates the script/cronic daemon control script and sets up job samples in config/cronic.d"
|
5
|
+
|
6
|
+
def create_scheduler_script
|
7
|
+
copy_file "script/cronic"
|
8
|
+
chmod 'script/cronic', 0755
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_jobs_dir
|
12
|
+
directory "config/cronic.d"
|
13
|
+
end
|
14
|
+
end
|
data/recipes/cronic.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'cronic', 'recipes'))
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cronic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jens Krämer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rufus-scheduler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.0.17
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.0.17
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: dante
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.1.5
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.1.5
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rails
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3'
|
62
|
+
description: Taking advantage of Rufus Scheduler and Dante to provide a long running
|
63
|
+
daemon for cron like jobs to be run in the context of your Rails application, without
|
64
|
+
loading the full environment each and every time a job is run.
|
65
|
+
email:
|
66
|
+
- jk@jkraemer.net
|
67
|
+
executables: []
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- lib/cronic/recipes.rb
|
72
|
+
- lib/cronic/scheduler.rb
|
73
|
+
- lib/cronic/version.rb
|
74
|
+
- lib/cronic.rb
|
75
|
+
- lib/generators/cronic_generator.rb
|
76
|
+
- recipes/cronic.rb
|
77
|
+
- LICENSE
|
78
|
+
- CHANGELOG.md
|
79
|
+
- README.md
|
80
|
+
homepage: http://github.com/jkraemer/cronic
|
81
|
+
licenses: []
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 1.3.6
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project: cronic
|
100
|
+
rubygems_version: 1.8.23
|
101
|
+
signing_key:
|
102
|
+
specification_version: 3
|
103
|
+
summary: Cron like scheduler daemon for Rails applications
|
104
|
+
test_files: []
|