djinn 0.0.1 → 0.0.2

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 CHANGED
@@ -19,3 +19,6 @@ rdoc
19
19
  pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
+ *.log
23
+ log
24
+ **/*.log
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "djinn"
8
- gem.summary = %Q{Poorly-named Daemon Helper}
8
+ gem.summary = %Q{Simple helper for creating daemons}
9
9
  gem.description = %Q{Helper for creating custom daemon, mostly for rails}
10
10
  gem.email = "darksavant@gmail.com"
11
11
  gem.homepage = "http://github.com/craigp/djinn"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
data/djinn.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{djinn}
8
- s.version = "0.0.1"
8
+ s.version = "0.0.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Craig Paterson"]
@@ -24,7 +24,14 @@ Gem::Specification.new do |s|
24
24
  "Rakefile",
25
25
  "VERSION",
26
26
  "djinn.gemspec",
27
+ "example/basic.rb",
28
+ "example/em.rb",
27
29
  "lib/djinn.rb",
30
+ "lib/djinn/logging_helpers.rb",
31
+ "lib/djinn/pid_file.rb",
32
+ "lib/djinn/rails/boot_daemon.rb",
33
+ "lib/djinn/rails/daemon_base.rb",
34
+ "lib/djinn/tonic.rb",
28
35
  "test/helper.rb",
29
36
  "test/test_djinn.rb"
30
37
  ]
@@ -32,7 +39,7 @@ Gem::Specification.new do |s|
32
39
  s.rdoc_options = ["--charset=UTF-8"]
33
40
  s.require_paths = ["lib"]
34
41
  s.rubygems_version = %q{1.3.7}
35
- s.summary = %q{Poorly-named Daemon Helper}
42
+ s.summary = %q{Simple helper for creating daemons}
36
43
  s.test_files = [
37
44
  "test/helper.rb",
38
45
  "test/test_djinn.rb"
data/example/basic.rb ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "../lib/"))
4
+
5
+ require 'djinn'
6
+ require 'rubygems'
7
+
8
+ class Basic
9
+
10
+ include Djinn
11
+
12
+ # not providing a "perform" method falls back to the
13
+ # base method in Djinn..
14
+
15
+ def handle_exit
16
+ puts "Handling a nice graceful exit myself.."
17
+ super
18
+ end
19
+
20
+ end
21
+
22
+ puts "Running for 10 secs and then stopping.."
23
+
24
+ djinn = Basic.new
25
+ # djinn.run
26
+ djinn.start
27
+ sleep(10)
28
+ djinn.stop
data/example/em.rb ADDED
@@ -0,0 +1,58 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), "../lib/"))
2
+
3
+ require 'djinn'
4
+ require 'rubygems'
5
+ require 'eventmachine'
6
+
7
+ WORKER_INTERVAL = 5
8
+
9
+ class Worker
10
+
11
+ include EM::Deferrable
12
+
13
+ def do_stuff
14
+ puts "Worker doing stuff.."
15
+ succeed(Time.now)
16
+ rescue => e
17
+ fail(e)
18
+ end
19
+
20
+ end
21
+
22
+ class EventMachineDjinn
23
+
24
+ include Djinn
25
+
26
+ def perform
27
+
28
+ worker = EM.spawn do
29
+ worker = Worker.new
30
+ worker.callback { |time| puts "Worker completed at: #{time}" }
31
+ worker.errback { |ex| puts "Twitter worker failed: #{ex}" }
32
+ worker.do_stuff
33
+ end
34
+
35
+ EM.run do
36
+ log "Workers will run every #{WORKER_INTERVAL} secs"
37
+ EM::PeriodicTimer.new(WORKER_INTERVAL) do
38
+ worker.notify
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ def handle_exit
45
+ EM.stop
46
+ super
47
+ end
48
+
49
+ end
50
+
51
+ puts "Running for 30 secs and then stopping.."
52
+
53
+ djinn = EventMachineDjinn.new
54
+ djinn.start
55
+ sleep(30)
56
+ djinn.stop
57
+
58
+
data/lib/djinn.rb CHANGED
@@ -0,0 +1,104 @@
1
+ module Djinn
2
+
3
+ require 'djinn/tonic'
4
+ require 'djinn/pid_file'
5
+ require 'djinn/logging_helpers'
6
+
7
+ include Djinn::Tonic
8
+ include Djinn::LoggingHelpers
9
+
10
+ attr_reader :config
11
+
12
+ def log msg
13
+ puts "#{Time.now.strftime("%m/%d/%Y %H:%M:%S")}: #{msg}"
14
+ STDOUT.flush
15
+ end
16
+
17
+ def perform
18
+ # base implementation does nothing worthwhile
19
+ trap('TERM') { handle_exit }
20
+ trap('INT') { handle_exit }
21
+ while true
22
+ log("[#{name}] Djinn is running..")
23
+ sleep(5)
24
+ end
25
+ end
26
+
27
+ def handle_exit
28
+ # override this with useful exit code if you need it
29
+ exit(0)
30
+ end
31
+
32
+ def start config={}
33
+ @config = (config.empty?) ? load_config : config.empty?
34
+ log "Starting #{underscore(name)} in the background.."
35
+ logfile = get_logfile(config)
36
+ daemonize(logfile, get_pidfile(config)) do
37
+ trap('TERM') { handle_exit }
38
+ trap('INT') { handle_exit }
39
+ perform
40
+ end
41
+ end
42
+
43
+ def run config={}
44
+ @config = (config.empty?) ? load_config : config.empty?
45
+ log "Starting #{underscore(name)} in the foreground.."
46
+ trap('TERM') { handle_exit }
47
+ trap('INT') { handle_exit }
48
+ perform
49
+ end
50
+
51
+ def restart
52
+ stop
53
+ start
54
+ end
55
+
56
+ def stop
57
+ pidfile = get_pidfile(load_config)
58
+ log 'No such process' and exit unless pidfile.pid
59
+ begin
60
+ log "Sending TERM signal to process #{pidfile.pid}"
61
+ Process.kill("TERM", pidfile.pid)
62
+ rescue
63
+ log 'Could not find process'
64
+ ensure
65
+ pidfile.remove
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def name
72
+ self.class
73
+ end
74
+
75
+ def get_pidfile config
76
+ pid_file_path = config[:pid_file_path] ||
77
+ File.join(Dir.pwd, "#{underscore(name)}.pid")
78
+ PidFile.new(pid_file_path)
79
+ end
80
+
81
+ def get_logfile config
82
+ log_file_path = config[:log_file_path] ||
83
+ File.join(Dir.pwd, "#{underscore(name)}.log")
84
+ log_file_path
85
+ end
86
+
87
+ def load_config
88
+ config_path = File.join(Dir.pwd, "#{underscore(name)}.yml")
89
+ if File.exists?(config_path)
90
+ YAML.load_file(config_path)
91
+ else
92
+ {}
93
+ end
94
+ end
95
+
96
+ def underscore(camel_cased_word)
97
+ camel_cased_word.to_s.gsub(/::/, '/').
98
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
99
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
100
+ tr("-", "_").
101
+ downcase
102
+ end
103
+
104
+ end
@@ -0,0 +1,21 @@
1
+ module Djinn
2
+ module LoggingHelpers
3
+
4
+ def green text
5
+ colorize 32, text
6
+ end
7
+
8
+ def red text
9
+ colorize 31, text
10
+ end
11
+
12
+ def cyan text
13
+ colorize 36, text
14
+ end
15
+
16
+ def colorize color, text
17
+ "\033[#{color}m#{text}\033[0m"
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ module Djinn
2
+ class PidFile
3
+
4
+ attr_reader :file
5
+
6
+ def initialize(file)
7
+ @file = file
8
+ end
9
+
10
+ def pid
11
+ File.exists?(@file) and IO.read(@file).to_i
12
+ end
13
+
14
+ def remove
15
+ File.unlink(@file) if pid
16
+ end
17
+
18
+ def create
19
+ File.open(@file, "w") { |f| f.write($$) }
20
+ end
21
+
22
+ def ensure_empty!(msg = nil)
23
+ if self.pid
24
+ $stdout.puts msg if msg
25
+ exit 1
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.dirname(__FILE__))
4
+
5
+ require 'rubygems'
6
+ require 'optparse'
7
+
8
+ environment = ENV["RAILS_ENV"] || "development"
9
+ @action = "run"
10
+
11
+ OptionParser.new do |opts|
12
+ opts.banner = "Usage: social_daemon [options] {start|stop|restart|run}"
13
+
14
+ opts.on("-e", "--environment ENV", "Run in specific Rails environment") do |e|
15
+ environment = e
16
+ end
17
+
18
+ @action = opts.permute!(ARGV)
19
+ # (puts opts; exit(1)) unless action.size == 1
20
+
21
+ @action = @action.first || "run"
22
+ (puts opts; exit(1)) unless %w(start stop restart run).include?(@action)
23
+
24
+ end.parse!
25
+
26
+ ENV["RAILS_ENV"] = environment
27
+
28
+ require 'daemon_base'
29
+
@@ -0,0 +1,99 @@
1
+ module Djinn
2
+ module Rails
3
+ class Base
4
+
5
+ require 'yaml'
6
+ require 'daemon'
7
+ require 'pid_file'
8
+ require 'daemon_logging'
9
+
10
+ extend Djinn::Daemon
11
+ include Djinn::LoggingHelpers
12
+
13
+ def log m
14
+ DaemonBase.log m
15
+ end
16
+
17
+ class << self
18
+
19
+ def log m
20
+ puts "#{Time.now.strftime("%m/%d/%Y %H:%M:%S")}: #{m}"
21
+ STDOUT.flush
22
+ end
23
+
24
+ def perform config
25
+ raise "Not implemented"
26
+ end
27
+
28
+ def start
29
+ log "Starting #{underscore(self.name)} in the background.."
30
+ config = load_config
31
+ logfile = get_logfile(config)
32
+ daemonize(config, logfile, get_pidfile(config)) do
33
+ load_rails
34
+ self.new(config).do_stuff
35
+ end
36
+ end
37
+
38
+ def run
39
+ log "Starting #{underscore(self.name)} in the foreground.."
40
+ load_rails
41
+ self.new(load_config).do_stuff
42
+ end
43
+
44
+ def restart
45
+ stop
46
+ start
47
+ end
48
+
49
+ def stop
50
+ pidfile = get_pidfile(load_config)
51
+ log 'No such process' and exit unless pidfile.pid
52
+ begin
53
+ log "Sending TERM signal to process #{pidfile.pid}"
54
+ Process.kill("TERM", pidfile.pid)
55
+ rescue
56
+ log 'Could not find process'
57
+ ensure
58
+ pidfile.remove
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def get_pidfile(config)
65
+ PidFile.new(File.join(File.dirname(__FILE__), '..', '..', 'log', config['pid_file']))
66
+ end
67
+
68
+ def get_logfile(config)
69
+ File.join(File.dirname(__FILE__), '..', '..', 'log', config['log_file'])
70
+ end
71
+
72
+ def load_rails
73
+ log "Loading Rails in #{ENV['RAILS_ENV']} environment"
74
+ require File.join(File.dirname(__FILE__), '..', '..', 'config', 'environment')
75
+ end
76
+
77
+ def load_config
78
+ path = File.join(File.dirname(__FILE__), '..', '..', 'config', "#{underscore(self.name)}.yml")
79
+ unless File.exists?(path)
80
+ log "No config file for daemon: #{path}"
81
+ exit(1)
82
+ else
83
+ YAML.load_file(path)[ENV['RAILS_ENV']]
84
+ end
85
+ end
86
+
87
+ def underscore(camel_cased_word)
88
+ camel_cased_word.to_s.gsub(/::/, '/').
89
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
90
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
91
+ tr("-", "_").
92
+ downcase
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,55 @@
1
+ module Djinn
2
+ module Tonic
3
+
4
+ def daemonize(logfile, pidfile, &block)
5
+
6
+ pidfile.ensure_empty! "ERROR: It looks like I'm already running. Not starting."
7
+
8
+ puts "Djinn is leaving process #{$$}"
9
+
10
+ srand # Split rand streams between spawning and daemonized process
11
+ #fork and exit # Fork and exit from the parent
12
+ fork do
13
+
14
+ puts "Daemonizing on process #{$$}"
15
+ puts system("ps aux | grep #{$$}")
16
+
17
+ # trap('TERM') { do_exit }
18
+ # trap('INT') { do_exit }
19
+
20
+ #Dir.chdir "/" # Release old working directory
21
+ File.umask 0000 # Ensure sensible umask
22
+
23
+ puts 'Making sure all file descriptors are closed'
24
+ ObjectSpace.each_object(IO) do |io|
25
+ unless [STDIN, STDOUT, STDERR].include?(io)
26
+ begin
27
+ io.close unless io.closed?
28
+ rescue ::Exception
29
+ end
30
+ end
31
+ end
32
+
33
+ puts "Writing PID file: #{pidfile.file}"
34
+ pidfile.create
35
+
36
+ puts 'Detaching from the controlling terminal'
37
+ unless sess_id = Process.setsid
38
+ raise 'cannot detach from controlling terminal'
39
+ end
40
+
41
+ # Redirect IO
42
+ puts "Logging to: #{logfile}"
43
+ STDIN.reopen('/dev/null')
44
+ STDOUT.reopen(logfile, 'a')
45
+ STDERR.reopen(STDOUT)
46
+
47
+ yield
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
55
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: djinn
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Craig Paterson
@@ -51,7 +51,14 @@ files:
51
51
  - Rakefile
52
52
  - VERSION
53
53
  - djinn.gemspec
54
+ - example/basic.rb
55
+ - example/em.rb
54
56
  - lib/djinn.rb
57
+ - lib/djinn/logging_helpers.rb
58
+ - lib/djinn/pid_file.rb
59
+ - lib/djinn/rails/boot_daemon.rb
60
+ - lib/djinn/rails/daemon_base.rb
61
+ - lib/djinn/tonic.rb
55
62
  - test/helper.rb
56
63
  - test/test_djinn.rb
57
64
  has_rdoc: true
@@ -87,7 +94,7 @@ rubyforge_project:
87
94
  rubygems_version: 1.3.7
88
95
  signing_key:
89
96
  specification_version: 3
90
- summary: Poorly-named Daemon Helper
97
+ summary: Simple helper for creating daemons
91
98
  test_files:
92
99
  - test/helper.rb
93
100
  - test/test_djinn.rb