lobster 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lobster (0.1.0)
4
+ lobster (0.1.1.pre)
5
5
  daemons (>= 1.1.4)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -4,17 +4,29 @@ Lobster
4
4
  Simple job service that was originally written to run hadoop jobs, but can be
5
5
  used for any batch-processing scripts that you want to run.
6
6
 
7
- Alpha Version Warning
8
- ---------------------
7
+ Lobster runs as a service (daemon) and regularly checks a schedule in
8
+ `$LOBSTER_DIR/config/schedule.rb`. The goal is to run the scheduled jobs in
9
+ parallel but a job can't run twice at the same time (no overlap). The only
10
+ configuration needed is the delay between 2 job runs.
9
11
 
10
- Lobster has not been fully released and tested yet.
11
-
12
- How It Works
12
+ Get Started
13
13
  ------------
14
14
 
15
+ ### Install
16
+
17
+ gem install lobster
18
+
15
19
  ### Create a `config/schedule.rb` file
16
20
 
21
+ Run `lobsterize` in the directory where you need to setup and run your jobs
22
+ (defined by the LOBSTER_DIR variable)
23
+
24
+ lobsterize
25
+
26
+ Then add a job in `config/schedule.rb`
27
+
17
28
  ~~~~~ ruby
29
+ # config/schedule.rb
18
30
  job "my-job" do
19
31
  cmd "runthis && runthat >> log/here.log"
20
32
  delay 5 # minutes
@@ -23,20 +35,55 @@ end
23
35
 
24
36
  ### Run Lobster
25
37
 
26
- - In the console with `LOBSTER_DIR=/path/to/jobs/directory lobster run`
27
- - As a service with `LOBSTER_DIR=/path/to/jobs/directory sudo lobster start`
38
+ Two environment variables are used (with defaults):
39
+
40
+ - `LOBSTER_DIR` is the directory used for all job commands, and where the
41
+ configuration/schedule files are (default: current
42
+ directory)
43
+ - `LOBSTER_ENV` is a variable used to handle different environments (default:
44
+ development)
45
+
46
+ You need write permission to `/var/run/lobster/` for pids, this path is
47
+ configurable.
48
+
49
+ - `lobster run` will run in the console
50
+ - or `lobster start` as a deamon
51
+
52
+ ### Configuration
53
+
54
+ The lobster configuration file should be located in
55
+ `$LOBSTER_DIR/config/lobster.yml` and has the following layout
28
56
 
29
- The job `my-job` will start in the next 5 minutes, and once it's done,
30
- lobster will wait 5 minutes before starting it again.
57
+ ~~~~ yaml
58
+ # default values
31
59
 
32
- Any log in stderr/stdout will be written in `$LOBSTER_DIR/log/lobster.output`
33
- along with some other useful information for monitoring.
60
+ # monitor the daemon and restart it if it stops
61
+ monitor: true
62
+ # log directory, absolute or relative to the LOBSTER_DIR
63
+ log_dir: log
64
+ # pids directory, absolute or relative to the LOBSTER_DIR
65
+ pid_dir: /var/run/lobster/
66
+ # schedule file, absolute or relative to the LOBSTER_DIR
67
+ schedule_file: config/schedule.rb
34
68
 
35
- The current directory where the job command is run is `$LOBSTER_DIR`.
69
+ # environment overrides, the env variable LOBSTER_ENV has
70
+ # to be set (default: development)
71
+ my_test_env:
72
+ monitor: false
73
+ log_dir: test_los
74
+ my_prod_env:
75
+ pid_dir: /var/run/
76
+ ~~~~
36
77
 
37
- How To Install
38
- --------------
78
+ Any log in stderr/stdout will be written in the log directory as
79
+ `lobster.output`, the actual lobster log is in `lobster.log`
39
80
 
40
- gem install lobster --pre
81
+ Capistrano Deployment
82
+ =====================
41
83
 
84
+ It is very easy to have a lobster project with a proper `config/lobster.yml` to
85
+ handle different environments such as development, testing and production. You
86
+ can simply have a `schedule.rb`file per environment.
42
87
 
88
+ Then you can use capistrano to deploy the new jobs and schedule to your servers
89
+ (the schedule is automatically reloaded).
data/bin/lobster CHANGED
@@ -1,13 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'optparse'
3
4
  require 'lobster'
4
- require 'logger'
5
5
  require 'daemons'
6
6
 
7
7
  lobster_dir = File.expand_path(ENV['LOBSTER_DIR'] || '.')
8
8
  lobster_env = ENV['LOBSTER_ENV'] || 'development'
9
9
 
10
- Lobster.logger = Logger.new(STDOUT)
11
10
  config = Lobster::Configuration.new(lobster_dir, lobster_env)
12
11
 
13
12
  #puts "LOBSTER_DIR set to #{lobster_dir}"
@@ -16,7 +15,6 @@ config = Lobster::Configuration.new(lobster_dir, lobster_env)
16
15
  log_dir = config[:log_dir]
17
16
  Dir.mkdir log_dir unless Dir.exist?(log_dir) || ARGV.first == "run"
18
17
 
19
-
20
18
  daemon_options = {
21
19
  :multiple => false,
22
20
  :monitor => config[:monitor],
data/bin/lobsterize ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ unless Dir.exist?('config')
4
+ puts 'create: config/'
5
+ Dir.mkdir 'config'
6
+ end
7
+
8
+ config = File.join('config', 'lobster.yml')
9
+ schedule = File.join('config', 'schedule.rb')
10
+
11
+ unless File.exist?(config)
12
+ puts "create: #{config}"
13
+ File.open(config,'w') do |f|
14
+ f.write <<-EOF.gsub /^\s+/,''
15
+ ## config/lobster.yml
16
+ ## configuration file for Lobster
17
+ ##
18
+ ## Default values
19
+ ## All paths are absolute or relative to the LOBSTER_DIR
20
+ ##
21
+ ## monitor the daemon and restart it if it stops
22
+ ## (requires a restart if modified)
23
+ #monitor: true
24
+ #
25
+ ## log directory
26
+ ## (requires a restart if modified)
27
+ #log_dir: log
28
+ #
29
+ ## pids directory
30
+ ## (requires a restart if modified)
31
+ #pid_dir: /var/run/lobster/
32
+ #
33
+ ## schedule file location
34
+ #schedule_file: config/schedulr.rb
35
+ #
36
+ ##
37
+ ## Environment values
38
+ ## You can use environement with the LOBSTER_ENV env variable,
39
+ ## the default is set to 'development'
40
+ ##
41
+ ## Example:
42
+ #development:
43
+ # monitor: false
44
+ # pid_dir: pids
45
+ #production:
46
+ # log_dir: /var/log/lobster/
47
+ EOF
48
+ end
49
+ end
50
+
51
+ unless File.exist?(schedule)
52
+ puts "create: #{schedule}"
53
+ File.open(schedule,'w') do |f|
54
+ f.write <<-EOF.gsub /^\s+/,''
55
+ ## config/schedule.rb
56
+ ## schedule file for Lobster
57
+ ##
58
+ ## Example:
59
+ ##
60
+ ## Job named my_job
61
+ #job 'my_job' do
62
+ #
63
+ ## will just sleep for 5 seconds, this command is run from the
64
+ ## LOBSTER_DIR directory, so you can use relative paths from here.
65
+ # command 'sleep 5'
66
+ #
67
+ ## the user my_user will be use to run the command, Lobster needs
68
+ ## password-less sudo access to this user.
69
+ # user 'my_user'
70
+ #
71
+ ## Lobster will wait 2 minutes between 2 runs
72
+ # delay 2
73
+ #
74
+ ## end of job definition
75
+ #end
76
+ EOF
77
+ end
78
+ end
79
+
80
+ puts "edit your schedule and try \"lobster run\""
@@ -14,7 +14,9 @@ module Lobster
14
14
  if File.exist? config_file_path
15
15
  config_file = YAML.load_file(config_file_path)
16
16
  @config.keys.each do |key|
17
- @config[key] = config_file[env][key.to_s] || config_file[key.to_s] || @config[key]
17
+ val = config_file[env][key.to_s] # environment-specific override
18
+ val = config_file[key.to_s] if val.nil?
19
+ @config[key] = val unless val.nil? # keep default if no config
18
20
  end
19
21
  end
20
22
 
data/lib/lobster/job.rb CHANGED
@@ -11,17 +11,16 @@ module Lobster
11
11
  def reload(options)
12
12
  options[:delay] ||= 10
13
13
 
14
- if options[:command] != @command
15
- Lobster.logger.info "Job command updated for #{@name}, was \"#{@command}\", now \"#{options[:command]}\"" if @command
16
- @command = options.delete(:command)
14
+ [:command, :delay, :user].each do |opt|
15
+ val = instance_variable_get "@#{opt}"
16
+ if options[opt] != val
17
+ Lobster.logger.info "Job #{opt} updated for #{@name}, was \"#{val}\", now \"#{options[opt]}\"" if val
18
+ instance_variable_set "@#{opt}", options.delete(opt)
19
+ # special case: reset @next_run if delay is updated
20
+ @next_run = nil if opt == :delay and not running?
21
+ end
17
22
  end
18
23
 
19
- if options[:delay] != @delay
20
- Lobster.logger.info "Job delay updated for #{@name}, was \"#{@delay}\", now \"#{options[:delay]}\"" if @delay
21
- @delay = options.delete(:delay)
22
- @next_run = nil unless running?
23
- end
24
-
25
24
  @name ||= "<unnamed_job_#{command.hash.abs}>"
26
25
  @next_run ||= Time.now + rand(@delay*60)
27
26
  end
@@ -40,8 +39,10 @@ module Lobster
40
39
 
41
40
  def run(out,err,dir)
42
41
  Lobster.logger.info "Starting job #{@name}"
42
+ command_line = @user ? "sudo -nu #{@user} sh -c \"#{@command}\"" : @command
43
+
43
44
  begin
44
- @pid = spawn(@command, :out=>out, :err=>err, :chdir=>dir)
45
+ @pid = spawn(command_line, :out=>out, :err=>err, :chdir=>dir)
45
46
  rescue Exception => e
46
47
  Lobster.logger.error "#{e}: error when starting job #{@name}"
47
48
  @next_run = Time.now + 10
@@ -4,14 +4,12 @@ module Lobster
4
4
 
5
5
  def initialize(file)
6
6
  @file = file
7
- #@options = {}
8
7
  @current_options = nil
9
8
  @jobs = {}
10
9
  end
11
10
 
12
11
  def reload
13
12
  @new_jobs = {}
14
- #@new_options = {}
15
13
 
16
14
  instance_eval(File.read(@file),@file)
17
15
 
@@ -19,12 +17,8 @@ module Lobster
19
17
  @jobs.each do |name, job|
20
18
  Lobster.logger.info "Job #{name} deleted." unless @new_jobs[name]
21
19
  end
22
- #@options.each do |key, value|
23
- # Lobster.logger.info "#{key} unset." unless @new_options[key]
24
- #end
25
20
 
26
21
  @jobs = @new_jobs
27
- #@options = @new_options
28
22
  end
29
23
 
30
24
  def job(name)
@@ -35,21 +29,15 @@ module Lobster
35
29
  @current_options = nil
36
30
  end
37
31
 
38
- def cmd(command)
39
- @current_options[:command] = command
32
+ [:command, :delay, :user].each do |opt|
33
+ define_method opt do |value|
34
+ @current_options[opt] = value
35
+ end
40
36
  end
41
37
 
42
- def delay(delay)
43
- @current_options[:delay] = delay
38
+ # backward compatibility
39
+ def cmd(command)
40
+ @current_options[:command] = command
44
41
  end
45
-
46
- # def set(option, value)
47
- # Lobster.logger.info "set #{option}=#{value}" if value != @options[option]
48
- # @new_options[option] = value
49
- # end
50
- #
51
- # def get(option)
52
- # @options[option]
53
- # end
54
42
  end
55
43
  end
@@ -10,6 +10,7 @@ module Lobster
10
10
  @job_list = nil
11
11
  @running = true
12
12
  @sleeping = false
13
+ @main_thread = Thread.current
13
14
  @config = config
14
15
  @poll_delay = 60
15
16
 
@@ -28,6 +29,16 @@ module Lobster
28
29
  end
29
30
  end
30
31
 
32
+ trap 'HUP' do
33
+ begin
34
+ @config = Configuration.new(@config[:lobster_dir], @config[:environment])
35
+ rescue Exception => e
36
+ Lobster.logger.error "Cannot reload conf, Exception: #{e}"
37
+ break
38
+ end
39
+ Lobster.logger.info "Lobster config reloaded: #{@config}"
40
+ end
41
+
31
42
  at_exit do
32
43
  @running = false
33
44
  sleep 0.01 until @sleeping # make sure no new jobs are created
@@ -36,6 +47,8 @@ module Lobster
36
47
  @job_list.jobs.each_value do |job|
37
48
  job.kill 'INT'
38
49
  end if @job_list
50
+
51
+ @main_thread.wakeup # stop sleeping and exit properly
39
52
  end
40
53
  end
41
54
 
@@ -1,3 +1,3 @@
1
1
  module Lobster
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
data/lib/lobster.rb CHANGED
@@ -1,10 +1,12 @@
1
+ require 'logger'
2
+
1
3
  module Lobster
4
+ def self.logger
5
+ @@logger ||= Logger.new(STDOUT)
6
+ end
7
+
2
8
  autoload :Configuration, 'lobster/configuration'
3
9
  autoload :JobList, 'lobster/job_list'
4
10
  autoload :Job, 'lobster/job'
5
11
  autoload :Service, 'lobster/service'
6
-
7
- class << self
8
- attr_accessor :logger
9
- end
10
12
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lobster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-21 00:00:00.000000000 Z
12
+ date: 2012-01-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: daemons
16
- requirement: &80998950 !ruby/object:Gem::Requirement
16
+ requirement: &84449170 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,12 +21,13 @@ dependencies:
21
21
  version: 1.1.4
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *80998950
24
+ version_requirements: *84449170
25
25
  description: ''
26
26
  email:
27
27
  - m.brugidou@criteo.com
28
28
  executables:
29
29
  - lobster
30
+ - lobsterize
30
31
  extensions: []
31
32
  extra_rdoc_files: []
32
33
  files:
@@ -36,6 +37,7 @@ files:
36
37
  - LICENSE
37
38
  - README.md
38
39
  - bin/lobster
40
+ - bin/lobsterize
39
41
  - lib/lobster.rb
40
42
  - lib/lobster/configuration.rb
41
43
  - lib/lobster/job.rb