daemonic 0.0.2 → 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.
@@ -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