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 +7 -5
- data/History.txt +3 -0
- data/README.txt +3 -0
- data/Rakefile +7 -6
- data/lib/rplex/client.rb +28 -0
- data/lib/rplex/jobs.rb +35 -0
- data/lib/rplex/server.rb +46 -11
- data/lib/rplex.rb +3 -1
- data/test/test_jobs.rb +50 -5
- data/test/test_rplex.rb +2 -0
- data/test/test_server.rb +19 -2
- metadata +17 -14
data/Gemfile
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
source :rubygems
|
2
|
-
gem "sinatra","~>1.3.
|
2
|
+
gem "sinatra","~>1.3.2"
|
3
3
|
gem 'rest-client',"~>1.6.7"
|
4
|
-
|
5
|
-
gem "
|
6
|
-
gem
|
7
|
-
gem
|
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
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
|
-
# -*-
|
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
|
11
|
-
prj.description = prj.paragraphs_of('README.txt', 1..
|
12
|
-
prj.
|
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.
|
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
|
-
|
36
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
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(
|
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
|
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(
|
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
|
-
|
55
|
+
assert(ov.backlog.include?(['worker2',0]), "worker2 not 0ed")
|
50
56
|
ov.reset(['worker1'])
|
51
|
-
|
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
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
|
44
|
-
|
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.
|
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
|
12
|
+
date: 2012-06-04 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|
16
|
-
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.
|
21
|
+
version: 1.3.2
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2156779420
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rest-client
|
27
|
-
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: *
|
35
|
+
version_requirements: *2156778600
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rdoc
|
38
|
-
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: *
|
46
|
+
version_requirements: *2156777860
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: hoe
|
49
|
-
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: '
|
54
|
+
version: '3.0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
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
|
118
|
+
summary: rplex demultiplexes jobs across multiple workers
|
116
119
|
test_files:
|
117
120
|
- test/test_jobs.rb
|
118
121
|
- test/test_rplex.rb
|