zmq_jobs 0.0.1.alpha → 0.0.1.alpha2

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
- require 'rdoc/task'
4
3
  require 'rspec/core/rake_task'
5
4
 
6
5
  $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
data/config/zmq_jobs.yml CHANGED
@@ -10,5 +10,5 @@ broker:
10
10
  hosts: ['127.0.0.1']
11
11
  ports: [<%= (2200..2202).to_a.join(', ') %>]
12
12
  backend:
13
- host: '127.0.0.1'
14
- port: 2203
13
+ hosts: '127.0.0.1'
14
+ ports: 2203
@@ -14,5 +14,5 @@ broker:
14
14
  hosts: ['127.0.0.1']
15
15
  ports: [<%= (2200..2202).to_a.join(', ') %>]
16
16
  backend:
17
- host: '127.0.0.1'
18
- port: 2203
17
+ hosts: '127.0.0.1'
18
+ ports: 2203
@@ -8,8 +8,8 @@ Signal.trap('INT') do
8
8
  end
9
9
 
10
10
  publisher = ZmqJobs::Socket::Pub.new(
11
- 'host' => '127.0.0.1',
12
- 'port' => 2200
11
+ 'hosts' => '127.0.0.1',
12
+ 'ports' => 2200
13
13
  )
14
14
  publisher.run do |socket|
15
15
  msg = message.call(index)
data/lib/command.rb CHANGED
@@ -6,7 +6,8 @@ require 'erb'
6
6
  module ZmqJobs
7
7
  class Command
8
8
  attr_reader :daemonize, :monitor, :config_file, :execute_dir, :options
9
- DEVICES = {'broker' => Broker, 'balancer' => Balancer}
9
+
10
+ ALLOW_COMMANDS = %W{start stop restart}
10
11
 
11
12
  def self.define_properties options
12
13
  options.each do |property, value|
@@ -25,7 +26,7 @@ module ZmqJobs
25
26
  @config_file = './config/zmq_jobs.yml'
26
27
  @options = read_config_file
27
28
 
28
- if args.empty?
29
+ if args.empty? || !ALLOW_COMMANDS.include?(args.first)
29
30
  puts opts_parser
30
31
  exit 1
31
32
  else
@@ -64,7 +65,7 @@ module ZmqJobs
64
65
  end
65
66
 
66
67
  def opts_banner
67
- "Usage: #{type} <start|stop|restart> [options]"
68
+ "Usage: #{type} <#{ALLOW_COMMANDS.join('|')}> [options]"
68
69
  end
69
70
 
70
71
  def start_daemon daemon_name, config
@@ -85,7 +86,12 @@ module ZmqJobs
85
86
  end
86
87
 
87
88
  def read_config_file
88
- YAML.load(ERB.new(File.new(File.expand_path(config_file, execute_dir)).read).result)
89
+ full_path = File.expand_path(config_file, execute_dir)
90
+ raise(
91
+ "Config file not found in '#{full_path}'. Create config file or define its with -c option"
92
+ ) unless File.exists?(full_path)
93
+
94
+ YAML.load(ERB.new(File.new(full_path).read).result)
89
95
  end
90
96
 
91
97
  def daemon_config name
@@ -117,11 +123,15 @@ module ZmqJobs
117
123
  success = workers_to_start.map{|worker|
118
124
  preload_worker_class(daemon_classname(worker))
119
125
  start_daemon(worker, daemon_config(worker))
120
- }.inject(&:'&&')
126
+ }.inject(true){|result, value|result &&= value}
121
127
 
122
128
  ::ZmqJobs.logger.info('One or more workers do not started') unless success
123
129
  end
124
130
 
131
+ def daemon_class name=nil
132
+ ActiveSupport::Inflector.constantize(daemon_classname(name))
133
+ end
134
+
125
135
  protected
126
136
  def preload_worker_class classname
127
137
  worker_class_dir = File.expand_path(options['workers_dir'], execute_dir)
@@ -145,10 +155,6 @@ module ZmqJobs
145
155
  )
146
156
  end
147
157
 
148
- def daemon_class name=nil
149
- ActiveSupport::Inflector.constantize(daemon_classname(name))
150
- end
151
-
152
158
  def daemon_classname name
153
159
  ActiveSupport::Inflector.camelize(name, true)
154
160
  end
@@ -55,7 +55,7 @@ module ZmqJobs
55
55
 
56
56
  def backend_options
57
57
  options['backend'].
58
- assert_valid_keys('host', 'port')
58
+ assert_valid_keys('hosts', 'ports', 'linger')
59
59
  end
60
60
 
61
61
  def logger
@@ -8,7 +8,7 @@ module ZmqJobs
8
8
  iothreads = options['iothreads'] ? options['iothreads'].to_i : 1
9
9
  @context = options.delete('context') || ZMQ::Context.create(iothreads)
10
10
  raise Error.new('Can not create context') unless @context
11
- @options = default_options.merge(options)
11
+ @options = build_default_options.merge(options)
12
12
  @socket = @context.socket(ZMQ::PUB)
13
13
  @running = false
14
14
  end
@@ -82,11 +82,17 @@ module ZmqJobs
82
82
  options['ports'].is_a?(Array) ? options['ports'] : [options['ports']]
83
83
  end
84
84
 
85
- def default_options
85
+ def build_default_options
86
86
  {
87
+ 'linger' => 0,
87
88
  'hosts' => '*',
88
89
  'ports' => 2200
89
- }
90
+ }.merge(default_options).
91
+ delete_if{|k,v|v.nil?}
92
+ end
93
+
94
+ def default_options
95
+ {}
90
96
  end
91
97
  end
92
98
  end
@@ -4,6 +4,7 @@ module ZmqJobs
4
4
  def initialize options={}
5
5
  super(options)
6
6
  @socket = @context.socket(ZMQ::PUB)
7
+ assert(socket.setsockopt(ZMQ::LINGER, self.options['linger'])) if self.options['linger']
7
8
  end
8
9
 
9
10
  def create_link url
@@ -15,17 +16,16 @@ module ZmqJobs
15
16
 
16
17
  private
17
18
  def hosts
18
- options['host'].is_a?(Array) ? [options['host'].first] : [options['host']]
19
+ options['hosts'].is_a?(Array) ? [options['hosts'].first] : [options['hosts']]
19
20
  end
20
21
 
21
22
  def ports
22
- options['port'].is_a?(Array) ? [options['port'].first] : [options['port']]
23
+ options['ports'].is_a?(Array) ? [options['ports'].first] : [options['ports']]
23
24
  end
24
25
 
25
26
  def default_options
26
27
  {
27
- 'host' => '*',
28
- 'port' => 2200
28
+ 'linger' => nil
29
29
  }
30
30
  end
31
31
  end
@@ -17,10 +17,9 @@ module ZmqJobs
17
17
  protected
18
18
  def default_options
19
19
  {
20
- 'linger' => 0,
21
20
  'subscribe' => '',
22
- 'hosts' => ['127.0.0.1'],
23
- 'ports' => [2200]
21
+ 'hosts' => '127.0.0.1',
22
+ 'ports' => 2200
24
23
  }
25
24
  end
26
25
  end
@@ -1,3 +1,3 @@
1
1
  module ZmqJobs
2
- VERSION = "0.0.1.alpha"
2
+ VERSION = "0.0.1.alpha2"
3
3
  end
@@ -5,11 +5,10 @@ module ZmqJobs
5
5
  class << self
6
6
  def cmd args
7
7
  count = args[2].to_i || 0
8
- options = {
9
- 'hosts' => [args[0]],
10
- 'ports' => (args[1].to_i..(args[1].to_i + count)).to_a
11
- }
12
- options['iothreads'] = args[3] if args[3]
8
+ options = {}
9
+ options['hosts'] = args[0] if args[0]
10
+ options['ports'] = (args[1].to_i..(args[1].to_i + count)).to_a if args[1]
11
+ options['iothreads'] = args[3].to_i if args[3]
13
12
  start(options)
14
13
  end
15
14
 
@@ -1,13 +1,26 @@
1
1
  require 'spec_helper.rb'
2
2
 
3
- describe ZmqJobs::BrokerCommand do
4
- let(:command) do
5
- ZmqJobs::BrokerCommand.any_instance.stub(:read_config_file => options, :start => true)
6
- ZmqJobs::BrokerCommand.new(args)
3
+ class TestWorker
4
+ end
5
+ class AnotherTestWorker
6
+ end
7
+
8
+ describe ZmqJobs::Command do
9
+ describe '.new' do
10
+ let(:command) do
11
+ ZmqJobs::Command.new(['start'])
12
+ end
13
+
14
+ it 'should raise exception' do
15
+ lambda{command}.should raise_error(RuntimeError)
16
+ end
7
17
  end
8
- let(:options){{:key1 => :value1, :key2 => :value2}}
18
+ end
19
+
20
+ shared_examples_for 'initialization' do
21
+ let(:daemon_options){{:key => :value}}
9
22
 
10
- context 'without option' do
23
+ context 'without options' do
11
24
  let(:args){['start']}
12
25
 
13
26
  specify{command.daemonize.should be_false}
@@ -15,8 +28,9 @@ describe ZmqJobs::BrokerCommand do
15
28
  specify{command.config_file.should == './config/zmq_jobs.yml'}
16
29
  specify{command.execute_dir.should == Dir.pwd}
17
30
  specify{command.options.should == options}
18
- specify{command.type.should == 'broker'}
19
- specify{command.daemon_class.should == ZmqJobs::Broker}
31
+ specify{command.type.should == type}
32
+ specify{command.daemon_class(daemon).should == classname}
33
+ specify{command.send(:daemon_config, daemon).should == daemon_options}
20
34
  end
21
35
 
22
36
  context 'with option -d' do
@@ -43,3 +57,159 @@ describe ZmqJobs::BrokerCommand do
43
57
  specify{command.config_file.should == 'bla-bla-bla'}
44
58
  end
45
59
  end
60
+
61
+ shared_examples_for 'daemonization' do
62
+ let(:args){['start']}
63
+ let(:daemon_options){{:key => :value}}
64
+
65
+ specify{command.start}
66
+ end
67
+
68
+ describe ZmqJobs::BrokerCommand do
69
+ before do
70
+ ZmqJobs::BrokerCommand.any_instance.stub(:read_config_file => options)
71
+ end
72
+
73
+ let(:command){ZmqJobs::BrokerCommand.new(args)}
74
+ let(:type){'broker'}
75
+ let(:daemon){type}
76
+ let(:options){{daemon => daemon_options}}
77
+
78
+ describe '.new' do
79
+ before do
80
+ ZmqJobs::BrokerCommand.any_instance.stub(:start => true)
81
+ end
82
+
83
+ let(:classname){ZmqJobs::Broker}
84
+
85
+ it_behaves_like 'initialization'
86
+ end
87
+
88
+ describe '#start' do
89
+ before do
90
+ ZmqJobs::BrokerCommand.any_instance.should_receive(:start_daemon).with(daemon, daemon_options).and_return(true)
91
+ end
92
+
93
+ it_behaves_like 'daemonization'
94
+ end
95
+ end
96
+
97
+ describe ZmqJobs::BalancerCommand do
98
+ before do
99
+ ZmqJobs::BalancerCommand.any_instance.stub(:read_config_file => options)
100
+ end
101
+
102
+ let(:command){ZmqJobs::BalancerCommand.new(args)}
103
+ let(:type){'balancer'}
104
+ let(:daemon){type}
105
+ let(:options){{daemon => daemon_options}}
106
+
107
+ describe '.new' do
108
+ before do
109
+ ZmqJobs::BalancerCommand.any_instance.stub(:start => true)
110
+ end
111
+
112
+ let(:classname){ZmqJobs::Balancer}
113
+
114
+ it_behaves_like 'initialization'
115
+ end
116
+
117
+ describe '#start' do
118
+ before do
119
+ ZmqJobs::BalancerCommand.any_instance.should_receive(:start_daemon).with(daemon, daemon_options).and_return(true)
120
+ end
121
+
122
+ it_behaves_like 'daemonization'
123
+ end
124
+ end
125
+
126
+ describe ZmqJobs::WorkerCommand do
127
+ before do
128
+ ZmqJobs::WorkerCommand.any_instance.stub(:read_config_file => options)
129
+ end
130
+
131
+ let(:command){ZmqJobs::WorkerCommand.new(args)}
132
+ let(:type){'worker'}
133
+
134
+ describe '.new' do
135
+ before do
136
+ ZmqJobs::WorkerCommand.any_instance.stub(:start => true)
137
+ end
138
+
139
+ let(:daemon){'test_worker'}
140
+ let(:classname){TestWorker}
141
+ let(:options){{'workers' => {daemon => daemon_options}}}
142
+
143
+ it_behaves_like 'initialization'
144
+
145
+ context 'test workers initialization' do
146
+ let(:daemon_options){{:key => :value}}
147
+ context do
148
+ let(:workers){%W{worker1 worker2 worker3}}
149
+ let(:args){['start']}
150
+
151
+ specify{command.send(:input_workers).should == nil}
152
+ specify{command.send(:all_workers).should == ['test_worker']}
153
+ specify{command.send(:workers_to_start).should == ['test_worker']}
154
+ end
155
+
156
+ context do
157
+ let(:workers){%W{worker1 worker2 worker3}}
158
+ let(:args){['start', '-w', workers.join(',')]}
159
+
160
+ specify{command.send(:input_workers).should == workers}
161
+ specify{command.send(:all_workers).should == ['test_worker']}
162
+ specify{command.send(:workers_to_start).should == []}
163
+ end
164
+
165
+ context do
166
+ let(:workers){%W{worker1 worker2 worker3 test_worker}}
167
+ let(:args){['start', '-w', workers.join(',')]}
168
+
169
+ specify{command.send(:input_workers).should == workers}
170
+ specify{command.send(:all_workers).should == ['test_worker']}
171
+ specify{command.send(:workers_to_start).should == ['test_worker']}
172
+ end
173
+ end
174
+ end
175
+
176
+ describe '#start' do
177
+ before do
178
+ ZmqJobs::WorkerCommand.any_instance.stub(:workers_to_start => workers)
179
+ ZmqJobs::WorkerCommand.any_instance.stub(:preload_worker_class => true)
180
+ end
181
+
182
+ let(:args){['start', '-d']}
183
+ let(:first_daemon_options){{:key => :first}}
184
+
185
+ context 'daemonization for one worker' do
186
+ let(:workers){%W{test_worker}}
187
+ let(:options){{'workers' => {workers.first => first_daemon_options}}}
188
+
189
+ before do
190
+ command.should_receive(:start_daemon).
191
+ with(workers.first, first_daemon_options).and_return(true)
192
+ end
193
+
194
+ specify{command.start}
195
+ end
196
+
197
+ context 'daemonization for many workers' do
198
+ let(:workers){%W{test_worker another_test_worker}}
199
+ let(:last_daemon_options){{:key => :last}}
200
+ let(:options){{'workers' => {
201
+ workers.first => first_daemon_options,
202
+ workers.last => last_daemon_options
203
+ }}}
204
+
205
+ before do
206
+ command.should_receive(:start_daemon).
207
+ with(workers.first, first_daemon_options).and_return(true)
208
+ command.should_receive(:start_daemon).
209
+ with(workers.last, last_daemon_options).and_return(true)
210
+ end
211
+
212
+ specify{command.start}
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper.rb'
2
+
3
+ TestWorker = Class.new(ZmqJobs::Worker::Base)
4
+
5
+ describe ZmqJobs::Worker::Base do
6
+ describe '.cmd' do
7
+ before do
8
+ worker = mock(:worker, :start => true)
9
+ TestWorker.should_receive(:new).with(result_options).and_return(worker)
10
+ end
11
+
12
+ subject{TestWorker.cmd(options)}
13
+
14
+
15
+ context 'without arguments' do
16
+ let(:options){[]}
17
+ let(:result_options){{}}
18
+
19
+ specify{subject.should be_true}
20
+ end
21
+
22
+ context 'with one argument' do
23
+ let(:options){['127.0.0.1']}
24
+ let(:result_options){{'hosts' => '127.0.0.1'}}
25
+
26
+ specify{subject.should be_true}
27
+ end
28
+
29
+ context 'with two arguments' do
30
+ let(:options){['127.0.0.1', '2200']}
31
+ let(:result_options){{'hosts' => '127.0.0.1', 'ports' => [2200]}}
32
+
33
+ specify{subject.should be_true}
34
+ end
35
+
36
+ context 'with three arguments' do
37
+ let(:options){['127.0.0.1', '2200', '3']}
38
+ let(:result_options){{'hosts' => '127.0.0.1', 'ports' => [2200, 2201, 2202, 2203]}}
39
+
40
+ specify{subject.should be_true}
41
+ end
42
+
43
+ context 'with four arguments' do
44
+ let(:options){['127.0.0.1', '2200', '3', '2']}
45
+ let(:result_options){{'hosts' => '127.0.0.1', 'ports' => [2200, 2201, 2202, 2203], 'iothreads' => 2}}
46
+
47
+ specify{subject.should be_true}
48
+ end
49
+ end
50
+
51
+ describe '.new' do
52
+
53
+ end
54
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: zmq_jobs
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 6
5
- version: 0.0.1.alpha
5
+ version: 0.0.1.alpha2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Undr
@@ -10,12 +10,11 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-11-10 00:00:00 +07:00
13
+ date: 2011-11-11 00:00:00 +07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rspec
18
- prerelease: false
19
18
  requirement: &id001 !ruby/object:Gem::Requirement
20
19
  none: false
21
20
  requirements:
@@ -23,10 +22,10 @@ dependencies:
23
22
  - !ruby/object:Gem::Version
24
23
  version: "2"
25
24
  type: :development
25
+ prerelease: false
26
26
  version_requirements: *id001
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: yard
29
- prerelease: false
30
29
  requirement: &id002 !ruby/object:Gem::Requirement
31
30
  none: false
32
31
  requirements:
@@ -34,10 +33,10 @@ dependencies:
34
33
  - !ruby/object:Gem::Version
35
34
  version: 0.6.0
36
35
  type: :development
36
+ prerelease: false
37
37
  version_requirements: *id002
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: ruby-debug19
40
- prerelease: false
41
40
  requirement: &id003 !ruby/object:Gem::Requirement
42
41
  none: false
43
42
  requirements:
@@ -45,10 +44,10 @@ dependencies:
45
44
  - !ruby/object:Gem::Version
46
45
  version: "0"
47
46
  type: :development
47
+ prerelease: false
48
48
  version_requirements: *id003
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: bundler
51
- prerelease: false
52
51
  requirement: &id004 !ruby/object:Gem::Requirement
53
52
  none: false
54
53
  requirements:
@@ -56,10 +55,10 @@ dependencies:
56
55
  - !ruby/object:Gem::Version
57
56
  version: 1.0.0
58
57
  type: :runtime
58
+ prerelease: false
59
59
  version_requirements: *id004
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: rake
62
- prerelease: false
63
62
  requirement: &id005 !ruby/object:Gem::Requirement
64
63
  none: false
65
64
  requirements:
@@ -67,10 +66,10 @@ dependencies:
67
66
  - !ruby/object:Gem::Version
68
67
  version: "0"
69
68
  type: :runtime
69
+ prerelease: false
70
70
  version_requirements: *id005
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: ffi
73
- prerelease: false
74
73
  requirement: &id006 !ruby/object:Gem::Requirement
75
74
  none: false
76
75
  requirements:
@@ -78,10 +77,10 @@ dependencies:
78
77
  - !ruby/object:Gem::Version
79
78
  version: "0"
80
79
  type: :runtime
80
+ prerelease: false
81
81
  version_requirements: *id006
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: ffi-rzmq
84
- prerelease: false
85
84
  requirement: &id007 !ruby/object:Gem::Requirement
86
85
  none: false
87
86
  requirements:
@@ -89,10 +88,10 @@ dependencies:
89
88
  - !ruby/object:Gem::Version
90
89
  version: "0"
91
90
  type: :runtime
91
+ prerelease: false
92
92
  version_requirements: *id007
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: activesupport
95
- prerelease: false
96
95
  requirement: &id008 !ruby/object:Gem::Requirement
97
96
  none: false
98
97
  requirements:
@@ -100,10 +99,10 @@ dependencies:
100
99
  - !ruby/object:Gem::Version
101
100
  version: "0"
102
101
  type: :runtime
102
+ prerelease: false
103
103
  version_requirements: *id008
104
104
  - !ruby/object:Gem::Dependency
105
105
  name: daemons
106
- prerelease: false
107
106
  requirement: &id009 !ruby/object:Gem::Requirement
108
107
  none: false
109
108
  requirements:
@@ -111,6 +110,7 @@ dependencies:
111
110
  - !ruby/object:Gem::Version
112
111
  version: "0"
113
112
  type: :runtime
113
+ prerelease: false
114
114
  version_requirements: *id009
115
115
  description: ZeroMQ-based queue system for background job
116
116
  email:
@@ -146,6 +146,7 @@ files:
146
146
  - lib/zmq_jobs/version.rb
147
147
  - lib/zmq_jobs/worker/base.rb
148
148
  - spec/lib/command_spec.rb
149
+ - spec/lib/worker/base_spec.rb
149
150
  - spec/spec_helper.rb
150
151
  - zmq_jobs.gemspec
151
152
  has_rdoc: true
@@ -162,6 +163,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
162
163
  requirements:
163
164
  - - ">="
164
165
  - !ruby/object:Gem::Version
166
+ hash: 2610017728678870612
167
+ segments:
168
+ - 0
165
169
  version: "0"
166
170
  required_rubygems_version: !ruby/object:Gem::Requirement
167
171
  none: false
@@ -178,4 +182,5 @@ specification_version: 3
178
182
  summary: ZeroMQ-based queue system for background job
179
183
  test_files:
180
184
  - spec/lib/command_spec.rb
185
+ - spec/lib/worker/base_spec.rb
181
186
  - spec/spec_helper.rb