cronic 0.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/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: []
|