daemonic 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,49 @@
1
+ module Daemonic
2
+ class Producer
3
+
4
+ attr_reader :worker, :queue, :concurrency, :options
5
+
6
+ def initialize(worker, options)
7
+ @worker = worker
8
+ @options = options
9
+ @concurrency = options.fetch(:concurrency) { 4 }
10
+
11
+ @queue = SizedQueue.new(concurrency) { concurrency + 1 }
12
+ @running = true
13
+ end
14
+
15
+ def run
16
+ logger.info "Starting producer with #{concurrency} consumer threads."
17
+
18
+ Signal.trap("INT") { stop }
19
+ Signal.trap("TERM") { stop }
20
+
21
+ pool = Pool.new(concurrency, worker, logger)
22
+
23
+ producer = Thread.new do
24
+ while @running
25
+ worker.produce(pool)
26
+ Thread.pass
27
+ end
28
+ logger.info { "Producer has been shut down. Stopping the thread pool" }
29
+ pool.stop
30
+ end
31
+
32
+ producer.join
33
+
34
+ logger.info { "Shutting down" }
35
+
36
+ end
37
+
38
+ def stop
39
+ @running = false
40
+ end
41
+
42
+ def logger
43
+ @logger ||= Logger.new(@options[:log] || STDOUT).tap { |logger|
44
+ logger.level = @options[:log_level] || Logger::INFO
45
+ }
46
+ end
47
+
48
+ end
49
+ end
@@ -1,3 +1,3 @@
1
1
  module Daemonic
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,71 +1,109 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: daemonic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - iain
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-07 00:00:00.000000000 Z
11
+ date: 2014-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.3'
19
+ version: '1.6'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.3'
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - '>='
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
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: cucumber
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: aruba
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
32
74
  - !ruby/object:Gem::Version
33
75
  version: '0'
34
76
  type: :development
35
77
  prerelease: false
36
78
  version_requirements: !ruby/object:Gem::Requirement
37
79
  requirements:
38
- - - '>='
80
+ - - ">="
39
81
  - !ruby/object:Gem::Version
40
82
  version: '0'
41
- description: Manages daemonizing your workers with basic monitoring and restart behavior.
83
+ description: Daemonic makes multi-threaded daemons easy.
42
84
  email:
43
85
  - iain@iain.nl
44
- executables:
45
- - daemonic
86
+ executables: []
46
87
  extensions: []
47
88
  extra_rdoc_files: []
48
89
  files:
49
- - .gitignore
90
+ - ".gitignore"
91
+ - ".travis.yml"
50
92
  - Gemfile
51
- - LICENSE.txt
93
+ - MIT-LICENSE.txt
52
94
  - README.md
53
95
  - Rakefile
54
- - bin/daemonic
55
96
  - daemonic.gemspec
97
+ - examples/init-d.sh
98
+ - examples/rss
99
+ - features/support/env.rb
100
+ - features/worker.feature
56
101
  - lib/daemonic.rb
57
102
  - lib/daemonic/cli.rb
58
- - lib/daemonic/configuration.rb
59
- - lib/daemonic/logging.rb
60
- - lib/daemonic/master.rb
61
- - lib/daemonic/pidfile.rb
103
+ - lib/daemonic/daemon.rb
62
104
  - lib/daemonic/pool.rb
105
+ - lib/daemonic/producer.rb
63
106
  - lib/daemonic/version.rb
64
- - lib/daemonic/worker.rb
65
- - test/config
66
- - test/crappy_daemon.rb
67
- - test/integration_test.rb
68
- - test/test_daemon.rb
69
107
  homepage: https://github.com/yourkarma/daemonic
70
108
  licenses:
71
109
  - MIT
@@ -76,22 +114,21 @@ require_paths:
76
114
  - lib
77
115
  required_ruby_version: !ruby/object:Gem::Requirement
78
116
  requirements:
79
- - - '>='
117
+ - - ">="
80
118
  - !ruby/object:Gem::Version
81
119
  version: '0'
82
120
  required_rubygems_version: !ruby/object:Gem::Requirement
83
121
  requirements:
84
- - - '>='
122
+ - - ">="
85
123
  - !ruby/object:Gem::Version
86
124
  version: '0'
87
125
  requirements: []
88
126
  rubyforge_project:
89
- rubygems_version: 2.1.0
127
+ rubygems_version: 2.2.2
90
128
  signing_key:
91
129
  specification_version: 4
92
- summary: Manages daemonizing your workers with basic monitoring and restart behavior.
130
+ summary: Daemonic makes multi-threaded daemons easy.
93
131
  test_files:
94
- - test/config
95
- - test/crappy_daemon.rb
96
- - test/integration_test.rb
97
- - test/test_daemon.rb
132
+ - features/support/env.rb
133
+ - features/worker.feature
134
+ has_rdoc:
data/bin/daemonic DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
- $LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
3
-
4
- require 'daemonic'
5
- options = Daemonic::CLI.parse(ARGV)
6
- Daemonic.start(options)
@@ -1,110 +0,0 @@
1
- require 'logger'
2
- require 'shellwords'
3
-
4
- module Daemonic
5
- class Configuration
6
-
7
- Invalid = Class.new(ArgumentError)
8
-
9
- attr_reader :eventual_config, :given_options
10
-
11
- def initialize(given_options, pwd)
12
- @given_options = given_options
13
- @pwd = pwd
14
- @eventual_config = {}
15
- end
16
-
17
- def command
18
- self[:command]
19
- end
20
-
21
- def daemonize?
22
- self[:daemonize]
23
- end
24
-
25
- def config_file
26
- self[:config_file]
27
- end
28
-
29
- def workers
30
- Integer(self[:workers] || "1")
31
- end
32
-
33
- def reload
34
- @eventual_config = {}
35
- @logger = nil
36
- load_options defaults
37
- load_options given_options
38
- load_options config_file_options if config_file
39
- load_options given_options
40
- logger.debug { to_h.inspect }
41
- validate
42
- end
43
-
44
- def working_dir
45
- self[:working_dir]
46
- end
47
-
48
- def program_name
49
- self[:program_name] || File.basename(working_dir)
50
- end
51
-
52
- def pidfile
53
- self[:pidfile] || File.join(working_dir, "tmp/#{program_name}.pid")
54
- end
55
-
56
- def logfile
57
- self[:logfile] || STDOUT
58
- end
59
-
60
- def logger
61
- @logger ||= ::Logger.new(logfile).tap { |logger|
62
- logger.formatter = proc { |severity, datetime, progname, msg|
63
- "[#{severity}] [#{datetime}] [#{program_name}] [#{Process.pid}] #{msg}\n"
64
- }
65
- logger.level = ::Logger.const_get(loglevel)
66
- }
67
- end
68
-
69
- def to_h
70
- eventual_config
71
- end
72
-
73
- def loglevel
74
- (self[:loglevel] || "INFO").to_s.upcase
75
- end
76
-
77
- protected
78
-
79
- def [](key)
80
- eventual_config[key.to_s]
81
- end
82
-
83
- def []=(key, value)
84
- eventual_config[key.to_s] = value
85
- end
86
-
87
- private
88
-
89
- def load_options(options)
90
- options.each do |key, value|
91
- self[key] = value
92
- end
93
- end
94
-
95
- def config_file_options
96
- contents = File.open(config_file, 'r:utf-8').read
97
- args = Shellwords.split(contents)
98
- CLI.parse(args)
99
- end
100
-
101
- def validate
102
- raise Invalid, "No command specified" if command.nil?
103
- end
104
-
105
- def defaults
106
- { :workers => 1, :working_dir => @pwd }
107
- end
108
-
109
- end
110
- end
@@ -1,14 +0,0 @@
1
- require 'forwardable'
2
-
3
- module Daemonic
4
- module Logging
5
- extend Forwardable
6
-
7
- def_delegators :logger, :info, :debug, :warn, :fatal
8
-
9
- def logger
10
- config.logger
11
- end
12
-
13
- end
14
- end
@@ -1,119 +0,0 @@
1
- require 'thread'
2
- require 'daemonic/version'
3
- require 'daemonic/logging'
4
- require 'daemonic/pidfile'
5
-
6
- Thread.abort_on_exception = true
7
-
8
- module Daemonic
9
- class Master
10
- include Logging
11
-
12
- attr_reader :config, :pidfile
13
-
14
- def initialize(config)
15
- @config = config
16
- @shutting_down = false
17
- @current_status = nil
18
- config.reload
19
- update_program_name("booting")
20
- @pidfile = Pidfile.new(
21
- pid: Process.pid,
22
- config: config,
23
- )
24
- end
25
-
26
- def start
27
- Dir.chdir(config.working_dir)
28
- write_pidfile
29
- at_exit { clean_pidfile }
30
- trap_signals
31
- start_workers
32
- update_program_name(nil)
33
- wait_until_done
34
- update_program_name
35
- fatal "Shutting down master"
36
- end
37
-
38
- def restart
39
- @monitor = false
40
- update_program_name("restarting")
41
- pool.restart { update_program_name }
42
- update_program_name(nil)
43
- @monitor = true
44
- end
45
-
46
- def stop
47
- @monitor = false
48
- update_program_name("shutting down")
49
- pool.stop { update_program_name }
50
- @shutting_down = true
51
- end
52
-
53
- def hup
54
- config.reload
55
- pool.start
56
- pool.hup
57
- end
58
-
59
- private
60
-
61
- def write_pidfile
62
- pidfile.write
63
- end
64
-
65
- def clean_pidfile
66
- pidfile.clean
67
- end
68
-
69
- def start_workers
70
- pool.start { update_program_name }
71
- @monitor = true
72
- end
73
-
74
- def pool
75
- @pool ||= Pool.new(config)
76
- end
77
-
78
- def trap_signals
79
- trap("USR2") { Thread.new { info "USR2 received!"; restart } }
80
- trap("TERM") { Thread.new { info "TERM received!"; stop } }
81
- trap("INT") { Thread.new { info "INT received!"; stop } }
82
- trap("HUP") { Thread.new { info "HUP received!"; hup } }
83
- trap("TTIN") { Thread.new { info "TTIN received!"; ttin } }
84
- trap("TTOU") { Thread.new { info "TTOU received!"; ttou } }
85
- end
86
-
87
- def ttin
88
- pool.increase!
89
- end
90
-
91
- def ttou
92
- pool.decrease!
93
- end
94
-
95
- def wait_until_done
96
- while keep_running?
97
- pool.monitor if @monitor
98
- update_program_name
99
- sleep 0.1
100
- end
101
- end
102
-
103
- def keep_running?
104
- not @shutting_down
105
- end
106
-
107
- def update_program_name(additional = :unchanged)
108
- @current_status = additional if additional != :unchanged
109
- base = "#{config.program_name} master [version #{VERSION}; #{pool.count}/#{pool.desired_workers} workers]"
110
- if @current_status
111
- $PROGRAM_NAME = "#{base} (#{@current_status})"
112
- else
113
- $PROGRAM_NAME = base
114
- end
115
- $PROGRAM_NAME
116
- end
117
-
118
- end
119
- end