rplex 0.0.3 → 0.0.4

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/Gemfile CHANGED
@@ -1,7 +1,9 @@
1
1
  source :rubygems
2
- gem "sinatra","~>1.3.1"
2
+ gem "sinatra","~>1.3.2"
3
3
  gem 'rest-client',"~>1.6.7"
4
- gem "hoe","~>2.12.4"
5
- gem "rack-test","~>0.6.1"
6
- gem 'rcov',"~>0.9.11"
7
- gem 'rdoc',"~>3.11"
4
+ group :development do
5
+ gem "rake","~>0.9.2.2"
6
+ gem "hoe","~>3.0.6"
7
+ gem "rack-test","~>0.6.1"
8
+ gem 'rdoc',"~>3.12"
9
+ end
data/History.txt CHANGED
@@ -1,3 +1,6 @@
1
+ === 0.0.4 / 2012-05-31
2
+ * Added ability to limit queue sizes and a general configuration mechanism for the API
3
+ * Queues can be removed
1
4
  === 0.0.3 / 2012-02-24
2
5
  * Added reset queue functionality
3
6
  === 0.0.2 / 2012-01-04
data/README.txt CHANGED
@@ -22,6 +22,9 @@ Each worker polls the rplex queue, and then uses the information to grab the bui
22
22
  === Is that all?
23
23
  Queues are created automatically when a worker tries to get data from the queue, data can be posted to a subset of the workers if necessary and that as they say is it.
24
24
 
25
+ === Really?
26
+ Well, it used to be all of it. Now, you can also limit the size of the queues and remove queues using the client (and the API)
27
+
25
28
  == Example
26
29
  Start the rplex service.
27
30
 
data/Rakefile CHANGED
@@ -1,17 +1,18 @@
1
- # -*- ruby -*-
1
+ # -*- coding: utf-8 -*-
2
+ # encoding: utf-8
2
3
  $:.unshift File.join(File.dirname(__FILE__),"lib")
4
+ require 'rplex'
3
5
  require 'rubygems'
4
6
  require 'hoe'
5
- require 'rplex'
6
7
 
7
8
  Hoe.spec 'rplex' do |prj|
8
9
  developer('Vassilis Rizopoulos', 'var@zuehlke.com')
9
10
  prj.version=Rplex::Version::STRING
10
- prj.summary = 'rplex multiplexes jobs across multiple workers'
11
- prj.description = prj.paragraphs_of('README.txt', 1..4).join("\n\n")
12
- prj.url = "http://github.com/damphyr/rplex"
11
+ prj.summary = 'rplex demultiplexes jobs across multiple workers'
12
+ prj.description = prj.paragraphs_of('README.txt', 1..5).join("\n\n")
13
+ prj.urls = ["http://github.com/damphyr/rplex"]
13
14
  prj.changes = prj.paragraphs_of('History.txt', 0..1).join("\n\n")
14
- prj.extra_deps<<["sinatra", "~>1.3.1"]
15
+ prj.extra_deps<<["sinatra", "~>1.3.2"]
15
16
  prj.extra_deps<<['rest-client',"~>1.6.7"]
16
17
  end
17
18
 
data/lib/rplex/client.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+ # encoding: utf-8
1
3
  require 'rest_client'
2
4
  require 'json'
3
5
  module Rplex
@@ -52,6 +54,32 @@ module Rplex
52
54
  raise ClientError, $!.message
53
55
  end
54
56
 
57
+ def configuration
58
+ srv="#{@service}/configuration/#{@name}"
59
+ response=RestClient.get(srv,:accept => :json)
60
+ unless response.empty?
61
+ return JSON.parse(response)
62
+ else
63
+ return {}
64
+ end
65
+ rescue
66
+ raise ClientError, $!.message
67
+ end
68
+
69
+ def configure max_size
70
+ response=RestClient.post("#{@service}/configuration", {"worker"=>@name, "maximum_size" => max_size}, :content_type => :json, :accept => :json)
71
+ return response
72
+ rescue
73
+ raise ClientError, $!.message
74
+ end
75
+
76
+ def remove
77
+ response=RestClient.delete("#{@service}/configuration/#{worker}")
78
+ return response
79
+ rescue
80
+ raise ClientError, $!.message
81
+ end
82
+
55
83
  def to_s
56
84
  "#{@name} working with #{@service}"
57
85
  end
data/lib/rplex/jobs.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+ # encoding: utf-8
1
3
  require 'thread'
2
4
 
3
5
  module Rplex
@@ -22,6 +24,10 @@ module Rplex
22
24
  if valid?(job_data)
23
25
  @queues.each do |w,q|
24
26
  if workers.include?(w)
27
+ #this handles a SizedQueue without blocking
28
+ if q.respond_to?(:max) && q.size == q.max
29
+ q.pop
30
+ end
25
31
  q.push(job_data)
26
32
  queued_in+=1
27
33
  end
@@ -56,5 +62,34 @@ module Rplex
56
62
  def reset workers
57
63
  workers.each{|worker| @queues[worker].clear if @queues[worker]}
58
64
  end
65
+ #Configures the named worker
66
+ #
67
+ #worker_config is a Hash with possible keys:
68
+ # "maximum_size" - when 0 then it's unlimited
69
+ #
70
+ #Will create a queue for the worker if it doesn't exist
71
+ #
72
+ #Configuring a worker will reset it's queue
73
+ def configure worker,worker_config
74
+ if worker_config["maximum_size"]>0
75
+ @queues[worker]=SizedQueue.new(worker_config["maximum_size"])
76
+ else
77
+ @queues[worker]=Queue.new
78
+ end
79
+ configuration(worker)
80
+ end
81
+ #Returns the worker's configuration
82
+ def configuration worker
83
+ if @queues[worker]
84
+ @queues[worker].respond_to?(:max) ? max_size=@queues[worker].max : max_size=0
85
+ {'worker'=>worker,'maximum_size'=>max_size}
86
+ else
87
+ raise InvalidData,"non existent queue"
88
+ end
89
+ end
90
+ #Removes a queue
91
+ def remove worker
92
+ @queues.delete(worker)
93
+ end
59
94
  end
60
95
  end
data/lib/rplex/server.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+ # encoding: utf-8
1
3
  require 'sinatra/base'
2
4
  require 'rplex'
3
5
  require 'rplex/jobs'
@@ -9,6 +11,24 @@ module Rplex
9
11
  super
10
12
  @overseer = Rplex::Overseer.new
11
13
  end
14
+ get '/' do
15
+ [200,{'Content-Type' => 'application/json'},{"version"=>Rplex::Version::STRING}.to_json]
16
+ end
17
+ get '/backlog' do
18
+ [200,{'Content-Type' => 'application/json'},@overseer.backlog.to_json]
19
+ end
20
+ post '/reset' do
21
+ begin
22
+ reply={}
23
+ workers= params["workers"] ? params["workers"] : @overseer.workers
24
+ @overseer.reset(workers)
25
+ [200,{'Content-Type' => 'application/json'},@overseer.backlog.to_json]
26
+ rescue
27
+ status 500
28
+ end
29
+ end
30
+ ###########
31
+ # /job
12
32
  post '/job' do
13
33
  begin
14
34
  reply={}
@@ -25,27 +45,42 @@ module Rplex
25
45
  if reply
26
46
  [200,{'Content-Type' => 'application/json'},reply.to_json]
27
47
  else
48
+ #No jobs. No change
49
+ #if the worker was not there before it has now been created, so no 404
28
50
  status 204
29
51
  end
30
52
  end
31
- get '/' do
32
- [200,{'Content-Type' => 'application/json'},{"version"=>Rplex::Version::STRING}.to_json]
33
- end
34
53
 
35
- get '/backlog' do
36
- [200,{'Content-Type' => 'application/json'},@overseer.backlog.to_json]
54
+ ###########
55
+ # /configuration
56
+ get '/configuration' do
57
+ config=@overseer.workers.map{|worker| @overseer.configuration(worker)}
58
+ [200,{'Content-Type' => 'application/json'},config.to_json]
37
59
  end
38
-
39
- post '/reset' do
60
+ get '/configuration/:worker' do |worker|
40
61
  begin
41
- reply={}
42
- workers= params["workers"] ? params["workers"] : @overseer.workers
43
- @overseer.reset(workers)
44
- [200,{'Content-Type' => 'application/json'},@overseer.backlog.to_json]
62
+ [200,{'Content-Type' => 'application/json'},@overseer.configuration(worker).to_json]
63
+ rescue InvalidData
64
+ [404,{'Content-Type' => 'application/json'},$!.message]
65
+ end
66
+ end
67
+ post '/configuration' do
68
+ begin
69
+ worker=params['worker']
70
+ if params['maximum_size']
71
+ max_size=params['maximum_size'].to_i
72
+ @overseer.configure(worker,{'maximum_size'=>max_size})
73
+ [200,{'Content-Type' => 'application/json'},@overseer.configuration(worker).to_json]
74
+ else
75
+ status 500
76
+ end
45
77
  rescue
46
78
  status 500
47
79
  end
48
80
  end
81
+ delete '/configuration/:worker' do |worker|
82
+ @overseer.remove(worker)
83
+ end
49
84
 
50
85
  def self.define_settings cfg={}
51
86
  cfg||={}
data/lib/rplex.rb CHANGED
@@ -1,8 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+ # encoding: utf-8
1
3
  module Rplex
2
4
  module Version
3
5
  MAJOR = 0
4
6
  MINOR = 0
5
- TINY = 3
7
+ TINY = 4
6
8
  STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
7
9
  end
8
10
  end
data/test/test_jobs.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+ # encoding: utf-8
1
3
  $:.unshift File.join(File.dirname(__FILE__),"..","lib")
2
4
  require "test/unit"
3
5
  require "rplex/jobs"
@@ -32,10 +34,12 @@ class TestOverseer < Test::Unit::TestCase
32
34
  ov['worker1']
33
35
  ov['worker2']
34
36
  ov<<job_data
35
- assert_equal([['worker1',1],['worker2',1]], ov.backlog)
37
+ assert_equal(2, ov.backlog.size)
38
+ assert(ov.backlog.include?(['worker1',1]), "worker1 not present")
39
+ assert(ov.backlog.include?(['worker2',1]), "worker2 not present")
36
40
  end
37
41
 
38
- def test_reset
42
+ def test_reset_remove
39
43
  ov=Rplex::Overseer.new
40
44
  assert(ov.backlog.empty?)
41
45
  jd1={"identifier"=>"8888","data"=>{:foo=>"bar",:bar=>"foo"}}
@@ -44,10 +48,51 @@ class TestOverseer < Test::Unit::TestCase
44
48
  ov['worker2']
45
49
  ov<<jd1
46
50
  ov<<jd2
47
- assert_equal([['worker1',2],['worker2',2]], ov.backlog)
51
+ assert_equal(2, ov.backlog.size)
52
+ assert(ov.backlog.include?(['worker1',2]), "worker1 not present")
53
+ assert(ov.backlog.include?(['worker2',2]), "worker2 not present")
48
54
  ov.reset(['worker2'])
49
- assert_equal([['worker1',2],['worker2',0]], ov.backlog)
55
+ assert(ov.backlog.include?(['worker2',0]), "worker2 not 0ed")
50
56
  ov.reset(['worker1'])
51
- assert_equal([['worker1',0],['worker2',0]], ov.backlog)
57
+ assert(ov.backlog.include?(['worker1',0]), "worker1 not 0ed")
58
+ ov.remove('worker1')
59
+ assert_equal([['worker2',0]], ov.backlog)
60
+ end
61
+
62
+ def test_configure
63
+ ret=nil
64
+ ov=Rplex::Overseer.new
65
+ assert_nothing_raised() { ret=ov.configure('worker1',{'maximum_size'=>2}) }
66
+ assert_equal({'worker'=>'worker1','maximum_size'=>2}, ret)
67
+ assert_equal([['worker1',0]], ov.backlog)
68
+ ov<<{"identifier"=>"8888","data"=>{:foo=>"bar",:bar=>"foo"}}
69
+ assert_equal([['worker1',1]], ov.backlog)
70
+ ov<<{"identifier"=>"8889","data"=>{:foo=>"bar",:bar=>"foo"}}
71
+ assert_equal([['worker1',2]], ov.backlog)
72
+ ov<<{"identifier"=>"8899","data"=>{:foo=>"bar",:bar=>"foo"}}
73
+ assert_equal([['worker1',2]], ov.backlog)
74
+ assert_nothing_raised() { ret=ov.configure('worker1',{'maximum_size'=>0}) }
75
+ assert_equal({'worker'=>'worker1','maximum_size'=>0}, ret)
76
+ assert_equal([['worker1',0]], ov.backlog)
77
+ #and now the ugly stuff
78
+ assert_raise(ArgumentError) { ov.configure('worker1','maximum_size'=>"foo") }
79
+ end
80
+
81
+ def test_configuration
82
+ assert_raise(Rplex::InvalidData) { Rplex::Overseer.new.configuration('worker1') }
83
+ end
84
+ def test_full_sized_queue
85
+ ov=Rplex::Overseer.new
86
+ jd1={"identifier"=>"8888","data"=>{:foo=>"bar",:bar=>"foo"}}
87
+ jd2={"identifier"=>"9999","data"=>{:foo=>"bar",:bar=>"foo"}}
88
+ jd3={"identifier"=>"7777","data"=>{:foo=>"bar",:bar=>"foo"}}
89
+ ov.configure('worker1',{'maximum_size'=>2})
90
+ ov<<jd1
91
+ ov<<jd2
92
+ ov<<jd3
93
+ assert_equal([['worker1',2]], ov.backlog)
94
+ assert_equal(jd2,ov['worker1'])
95
+ assert_equal(jd3,ov['worker1'])
96
+ assert_nil(ov['worker1'])
52
97
  end
53
98
  end
data/test/test_rplex.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+ # encoding: utf-8
1
3
  $:.unshift File.join(File.dirname(__FILE__),"..","lib")
2
4
  require "test/unit"
3
5
  require "rplex"
data/test/test_server.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+ # encoding: utf-8
1
3
  $:.unshift File.join(File.dirname(__FILE__),"..","lib")
2
4
  require 'test/unit'
3
5
  require 'rubygems'
@@ -40,8 +42,9 @@ class ServerTest < Test::Unit::TestCase
40
42
  assert_equal(200, last_response.status)
41
43
  end
42
44
 
43
- def test_reset
44
- get '/job/worker'
45
+ def test_reset_remove
46
+ #do this because tests are otherwise exec sequence dependent
47
+ post '/configuration', {'worker'=>'worker','maximum_size'=>0}
45
48
  payload={"identifier"=>"8888","data"=>{"url"=>"http://foo.bar/drops","revision"=>"8888"}}
46
49
  post '/job', payload
47
50
  post '/job', payload
@@ -50,5 +53,19 @@ class ServerTest < Test::Unit::TestCase
50
53
  post '/reset',{"workers"=>['worker']}
51
54
  get '/backlog'
52
55
  assert_equal([["worker",0]], JSON.parse(last_response.body))
56
+ delete '/configuration/worker'
57
+ get '/backlog'
58
+ assert_equal([], JSON.parse(last_response.body))
59
+ end
60
+
61
+ def test_configuration
62
+ get '/configuration'
63
+ assert_equal([], JSON.parse(last_response.body))
64
+ get '/job/worker'
65
+ get '/configuration'
66
+ assert_equal([{'worker'=>'worker','maximum_size'=>0}], JSON.parse(last_response.body))
67
+ post '/configuration', {'worker'=>'worker','maximum_size'=>1}
68
+ get '/configuration/worker'
69
+ assert_equal({'worker'=>'worker','maximum_size'=>1}, JSON.parse(last_response.body))
53
70
  end
54
71
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rplex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-20 00:00:00.000000000Z
12
+ date: 2012-06-04 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra
16
- requirement: &2153566880 !ruby/object:Gem::Requirement
16
+ requirement: &2156779420 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 1.3.1
21
+ version: 1.3.2
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2153566880
24
+ version_requirements: *2156779420
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rest-client
27
- requirement: &2153565980 !ruby/object:Gem::Requirement
27
+ requirement: &2156778600 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.6.7
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2153565980
35
+ version_requirements: *2156778600
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rdoc
38
- requirement: &2153565160 !ruby/object:Gem::Requirement
38
+ requirement: &2156777860 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,18 +43,18 @@ dependencies:
43
43
  version: '3.10'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2153565160
46
+ version_requirements: *2156777860
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: hoe
49
- requirement: &2153564380 !ruby/object:Gem::Requirement
49
+ requirement: &2156776880 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: '2.12'
54
+ version: '3.0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2153564380
57
+ version_requirements: *2156776880
58
58
  description: ! 'https://github.com/damphyr/rplex
59
59
 
60
60
 
@@ -64,7 +64,10 @@ description: ! 'https://github.com/damphyr/rplex
64
64
  Simple asynchronous data based job management
65
65
 
66
66
 
67
- == INSTALL:'
67
+ == INSTALL:
68
+
69
+
70
+ * sudo gem install rplex'
68
71
  email:
69
72
  - var@zuehlke.com
70
73
  executables: []
@@ -112,7 +115,7 @@ rubyforge_project: rplex
112
115
  rubygems_version: 1.8.12
113
116
  signing_key:
114
117
  specification_version: 3
115
- summary: rplex multiplexes jobs across multiple workers
118
+ summary: rplex demultiplexes jobs across multiple workers
116
119
  test_files:
117
120
  - test/test_jobs.rb
118
121
  - test/test_rplex.rb