noda 0.0.1 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +4 -2
- data/VERSION +1 -1
- data/bin/noda_job_server +30 -0
- data/bin/noda_job_worker +27 -0
- data/lib/noda/job_monitor.rb +71 -0
- data/lib/noda/job_server.rb +39 -0
- data/lib/noda/job_worker.rb +60 -0
- data/lib/noda/rqueue.rb +53 -0
- data/lib/noda/table.rb +54 -0
- data/lib/noda/table_auto_saver.rb +43 -0
- data/lib/noda/task.rb +21 -0
- data/lib/noda.rb +3 -1
- data/noda.gemspec +21 -3
- data/test/test_helper.rb +14 -0
- data/test/test_job_monitor.rb +63 -0
- data/test/test_job_server.rb +85 -0
- data/test/test_job_worker.rb +55 -0
- data/test/test_rqueue.rb +51 -0
- data/test/test_table.rb +50 -0
- data/test/test_table_saver_woker.rb +46 -0
- data/test/test_task.rb +10 -0
- metadata +24 -6
data/README.rdoc
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
= noda
|
2
2
|
|
3
|
-
|
3
|
+
Noda �̓V���v���ȃW���u�L���[�T�[�o�[�ł�.
|
4
|
+
|
5
|
+
druby���g�p���āC�}���`�X���b�h�U�T�[�o�Ŏ������Ă��܂��D
|
4
6
|
|
5
7
|
== Contributing to noda
|
6
8
|
|
@@ -14,6 +16,6 @@ Description goes here.
|
|
14
16
|
|
15
17
|
== Copyright
|
16
18
|
|
17
|
-
Copyright (c) 2011
|
19
|
+
Copyright (c) 2011 takuya_1st. See LICENSE.txt for
|
18
20
|
further details.
|
19
21
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.5
|
data/bin/noda_job_server
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created on 2011-5-12.
|
4
|
+
# Copyright (c) 2011. All rights reserved.
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'daemons'
|
9
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/noda")
|
10
|
+
KCODE='s'
|
11
|
+
options = {
|
12
|
+
:dir_mode => :script,
|
13
|
+
:dir => '/var/run',
|
14
|
+
:multiple => true,
|
15
|
+
:ontop => false,
|
16
|
+
:mode => :exec,
|
17
|
+
:backtrace => true,
|
18
|
+
:monitor => true
|
19
|
+
}
|
20
|
+
require "socket"
|
21
|
+
ip= IPSocket::getaddress(Socket::gethostname)
|
22
|
+
STDOUT.puts " job_monitor at http://#{ip}:10080"
|
23
|
+
STDOUT.puts " job_server at druby://#{ip}:10001"
|
24
|
+
Daemons.run_proc("job_server",options){
|
25
|
+
m=Noda::JobMonitor.new("#{ip}","10080","druby://#{ip}:10001")
|
26
|
+
m.start_monitor
|
27
|
+
s=Noda::JobServer.new("#{ip}", "10001")
|
28
|
+
s.start_service
|
29
|
+
}
|
30
|
+
|
data/bin/noda_job_worker
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created on 2011-5-12.
|
4
|
+
# Copyright (c) 2011. All rights reserved.
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'daemons'
|
9
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/noda")
|
10
|
+
KCODE='s'
|
11
|
+
options = {
|
12
|
+
:dir_mode => :script,
|
13
|
+
:dir => '/var/run',
|
14
|
+
:multiple => true,
|
15
|
+
:ontop => false,
|
16
|
+
:mode => :exec,
|
17
|
+
:backtrace => true,
|
18
|
+
:monitor => true
|
19
|
+
}
|
20
|
+
require "socket"
|
21
|
+
ip= IPSocket::getaddress(Socket::gethostname)
|
22
|
+
STDOUT.puts " connect to job_server at druby://#{ip}:10001"
|
23
|
+
Daemons.call(options){
|
24
|
+
s=Noda::JobWorker.new("#{ip}", "10001")
|
25
|
+
s.start_service
|
26
|
+
}
|
27
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
module Noda
|
3
|
+
|
4
|
+
class JobMonitor
|
5
|
+
require 'webrick'
|
6
|
+
require 'drb/drb'
|
7
|
+
attr_accessor :job_server, :web_server
|
8
|
+
def initialize(addr="localhost",port="10080",job_server="druby://localhost:10001")
|
9
|
+
@job_server = DRbObject.new_with_uri(job_server)
|
10
|
+
@addr = addr
|
11
|
+
@port = port
|
12
|
+
self.init_webrick
|
13
|
+
end
|
14
|
+
def start_monitor
|
15
|
+
trap("INT"){ @web_server.shutdown }
|
16
|
+
@thread = Thread.new{ @web_server.start}
|
17
|
+
end
|
18
|
+
def stop_monitor
|
19
|
+
@web_server.stop
|
20
|
+
end
|
21
|
+
def init_webrick
|
22
|
+
config = WEBrick::Config::HTTP
|
23
|
+
config[:Port] = @port
|
24
|
+
config[:BindAddress]=@addr
|
25
|
+
config[:AccessLog] = WEBrick::Log.new("/dev/null",1) #���O�v��Ȃ��D
|
26
|
+
config[:Logger] = Logger.new("/dev/null") #���O�v��Ȃ��D
|
27
|
+
@web_server = WEBrick::HTTPServer.new(config)
|
28
|
+
@web_server.mount_proc '/' do |req,res|
|
29
|
+
res.content_type="text/plain"
|
30
|
+
res.body = "running" if @job_server.alive?
|
31
|
+
res.body = "stopped" unless @job_server.alive?
|
32
|
+
end
|
33
|
+
@web_server.mount_proc '/in_queue' do |req,res|
|
34
|
+
res.content_type="text/plain"
|
35
|
+
if req.path_info =~ %r'^/(\d+)$' then
|
36
|
+
num = $1.to_i
|
37
|
+
res.body = @job_server.input._at(num).to_s
|
38
|
+
end
|
39
|
+
if req.path_info =~ %r'^/$' then
|
40
|
+
res.body = @job_server.input.size.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
@web_server.mount_proc '/out_queue' do |req,res|
|
44
|
+
res.content_type="text/plain"
|
45
|
+
if req.path_info =~ %r'^/(\d+)$' then
|
46
|
+
num = $1.to_i
|
47
|
+
res.body = @job_server.output._at(num).to_s
|
48
|
+
end
|
49
|
+
if req.path_info =~ %r'^/$' then
|
50
|
+
res.body = @job_server.output.size.to_s
|
51
|
+
end
|
52
|
+
end
|
53
|
+
@web_server.mount_proc '/hash_table' do |req,res|
|
54
|
+
res.content_type="text/plain"
|
55
|
+
res.body = @job_server.hash_table.size.to_s
|
56
|
+
end
|
57
|
+
@web_server.mount_proc '/hash_table/keys' do |req,res|
|
58
|
+
res.content_type="text/plain"
|
59
|
+
res.body = @job_server.hash_table.keys.inspect
|
60
|
+
end
|
61
|
+
@web_server.mount_proc '/hash_table/fetch' do |req,res|
|
62
|
+
res.content_type="text/plain"
|
63
|
+
if req.path_info =~ %r'^/([^/]+)$' then
|
64
|
+
key = $1.to_s
|
65
|
+
res.body = @job_server.hash_table.get(key).to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Noda
|
2
|
+
|
3
|
+
class JobServer
|
4
|
+
include DRb::DRbUndumped
|
5
|
+
attr_reader :thread, :server
|
6
|
+
def initialize( addr='localhost', port='10001',acl=nil,log_file=STDOUT )
|
7
|
+
@q_in = RQueue.new()
|
8
|
+
@q_out = RQueue.new()
|
9
|
+
@hash_table = Table.new()
|
10
|
+
@server = DRb.start_service("druby://#{addr}:#{port}",self)
|
11
|
+
@thread = @server.thread
|
12
|
+
@logger = Logger.new(log_file)
|
13
|
+
end
|
14
|
+
def stop
|
15
|
+
@server.stop_service
|
16
|
+
end
|
17
|
+
def alive?
|
18
|
+
@server.alive?
|
19
|
+
end
|
20
|
+
def input
|
21
|
+
#�T�[�o�[�͕K���C���v�b�g�L���[��Ԃ�
|
22
|
+
@q_in
|
23
|
+
end
|
24
|
+
def output
|
25
|
+
@q_out
|
26
|
+
end
|
27
|
+
def hash_table
|
28
|
+
@hash_table
|
29
|
+
end
|
30
|
+
def start_service
|
31
|
+
@thread.join
|
32
|
+
end
|
33
|
+
def logger
|
34
|
+
@logger
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Noda
|
2
|
+
|
3
|
+
|
4
|
+
class JobWorker
|
5
|
+
attr_reader :thread
|
6
|
+
attr_accessor :max_retry_connect , :wait_time_to_retry
|
7
|
+
def initialize( job_server_addr="localhost",job_server_port="10001" )
|
8
|
+
@server_uri = "druby://#{job_server_addr}:#{job_server_port}"
|
9
|
+
@max_retry_connect = 30
|
10
|
+
@wait_time_to_retry = 2
|
11
|
+
require "socket"
|
12
|
+
@local_addr = IPSocket::getaddress(Socket::gethostname)
|
13
|
+
self.connect
|
14
|
+
end
|
15
|
+
def connect_job_server
|
16
|
+
error_conter = 0
|
17
|
+
begin
|
18
|
+
@job =DRbObject.new_with_uri(@server_uri)
|
19
|
+
@job.hash_table
|
20
|
+
@logger = @job.logger
|
21
|
+
rescue DRb::DRbConnError => e
|
22
|
+
error_conter +=1
|
23
|
+
raise e if error_conter > @max_retry_connect
|
24
|
+
sleep @wait_time_to_retry
|
25
|
+
retry
|
26
|
+
end
|
27
|
+
end
|
28
|
+
def handle_task()
|
29
|
+
# @logger.info("self.class@#{@local_addr}#{self.object_id}"){"i try to pop a task."}
|
30
|
+
task = @job.input.pop
|
31
|
+
# @logger.info("self.class@#{@local_addr}#{self.object_id}"){"i got a task-#{task.name}"}
|
32
|
+
# @logger.info("self.class@#{@local_addr}#{self.object_id}"){"i start handling a task-#{task.name}"}
|
33
|
+
result = task.do_task(@job.hash_table)
|
34
|
+
@job.output.push result
|
35
|
+
end
|
36
|
+
def init_thread
|
37
|
+
@table = @job.hash_table
|
38
|
+
@thread= Thread.new{
|
39
|
+
loop{
|
40
|
+
self.handle_task()
|
41
|
+
sleep 0.001
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
def connect
|
46
|
+
self.connect_job_server
|
47
|
+
end
|
48
|
+
def start
|
49
|
+
self.init_thread
|
50
|
+
@thread.join
|
51
|
+
end
|
52
|
+
def status
|
53
|
+
@thread.status if @thread
|
54
|
+
end
|
55
|
+
def stop
|
56
|
+
@thread.kill
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/lib/noda/rqueue.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- utf8 -*-
|
2
|
+
|
3
|
+
module Noda
|
4
|
+
require 'monitor'
|
5
|
+
class RQueue
|
6
|
+
include DRb::DRbUndumped
|
7
|
+
attr_reader :name
|
8
|
+
def initialize( max=nil, name=nil )
|
9
|
+
@name = name
|
10
|
+
@list = []
|
11
|
+
@max = nil
|
12
|
+
@max = max if max
|
13
|
+
self.extend(MonitorMixin)
|
14
|
+
@m_empty = self.new_cond
|
15
|
+
@m_full = self.new_cond
|
16
|
+
end
|
17
|
+
def push obj
|
18
|
+
self.synchronize{
|
19
|
+
@m_full.wait_while{ self.full? } if @max
|
20
|
+
@list.push obj
|
21
|
+
@m_empty.broadcast
|
22
|
+
}
|
23
|
+
end
|
24
|
+
def pop
|
25
|
+
self.synchronize{
|
26
|
+
@m_empty.wait_while{ self.empty? }
|
27
|
+
obj = @list.shift
|
28
|
+
@m_full.broadcast if @max
|
29
|
+
obj
|
30
|
+
}
|
31
|
+
end
|
32
|
+
def include?(v) @list.include? v end
|
33
|
+
alias exists? include?
|
34
|
+
def firsts(n=1) (0...n).map{self.pop} end
|
35
|
+
def first() self.pop end
|
36
|
+
def size() @list.size end
|
37
|
+
def max_size() @max end
|
38
|
+
def empty?() @list.empty? end
|
39
|
+
def close_to_full?() @list.size >= @max-5 end
|
40
|
+
def full?()
|
41
|
+
# max=nil �Ȃ�Limitless�B�܂薳����
|
42
|
+
@list.size >= @max if @max
|
43
|
+
end
|
44
|
+
def all() self.firsts(self.size) end
|
45
|
+
# �P����m�܂ł̒l�����B�O�n�܂�łȂ����Ƃɒ���
|
46
|
+
def _at(pos)
|
47
|
+
i = pos - 1
|
48
|
+
return @list.at(i) if (i) < self.size
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
end
|
data/lib/noda/table.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#
|
2
|
+
module Noda
|
3
|
+
#スレッドセーフなHASHテーブルを作ってる
|
4
|
+
#内部的にはHashにしている
|
5
|
+
#KVSとして使っている
|
6
|
+
#TODO::HASHとして動くようにEnumerableを実装したい
|
7
|
+
#TODO::DBやファイルに保存する。このクラスAPIでアクセス出来るアダプタを作りたい
|
8
|
+
class Table
|
9
|
+
include DRb::DRbUndumped
|
10
|
+
include Enumerable
|
11
|
+
attr_reader :name
|
12
|
+
def initialize(name=nil)
|
13
|
+
@hash = {}
|
14
|
+
@name = name
|
15
|
+
self.extend(MonitorMixin)
|
16
|
+
@m_lock = self.new_cond
|
17
|
+
@saved_keys = []
|
18
|
+
end
|
19
|
+
def get(key)
|
20
|
+
@hash[key][:data]
|
21
|
+
end
|
22
|
+
def put(key, obj)
|
23
|
+
self.synchronize{
|
24
|
+
@hash[key] = {:data=>obj,:saved=>false}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
def has_key?(key) @hash.has_key? key end
|
28
|
+
alias :exists? :has_key?
|
29
|
+
def keys() @hash.keys end
|
30
|
+
def size() @hash.size end
|
31
|
+
def each
|
32
|
+
@hash.each_pair{|k,v| yield( k,v[:data] ) }
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
def saved?(key)
|
36
|
+
@hash[key][:saved]
|
37
|
+
end
|
38
|
+
def update_saved_at(key,status=true)
|
39
|
+
self.synchronize{
|
40
|
+
@hash[key][:saved]=status
|
41
|
+
}
|
42
|
+
end
|
43
|
+
def each_unsaved_pair
|
44
|
+
@hash.each_pair{|k,v| next if v[:saved]; yield( k, v[:data] ) }
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
def has_unsaved_key?
|
48
|
+
return true if @hash.find{|k,v| v[:saved]==false}
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Noda
|
2
|
+
|
3
|
+
class TableAutoSaver < JobWorker
|
4
|
+
attr_reader :thread
|
5
|
+
attr_accessor :max_retry_connect , :wait_time_to_retry
|
6
|
+
def initialize( job_server_addr="localhost",job_server_port="10001" )
|
7
|
+
super
|
8
|
+
@interval = 2
|
9
|
+
require 'tmpdir'
|
10
|
+
@save_dir = Dir.tmpdir
|
11
|
+
end
|
12
|
+
def save_dir=(dirname)
|
13
|
+
raise ArgumentError, "#{dirname} is not direcotry." unless FileTest.directory? dirname
|
14
|
+
@save_dir=dirname
|
15
|
+
end
|
16
|
+
def save_dir
|
17
|
+
@save_dir
|
18
|
+
end
|
19
|
+
def handle_task()
|
20
|
+
sleep @interval
|
21
|
+
return unless @table.has_unsaved_key?
|
22
|
+
@table.each_unsaved_pair{|k,v|
|
23
|
+
self.save(k,v)
|
24
|
+
@table.update_saved_at(k,true)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
def save(key,val)
|
28
|
+
Dir.chdir(@save_dir){
|
29
|
+
open(key.to_s, "w"){|f|
|
30
|
+
f.write(Marshal.dump({:key=>key, :data=>val}))
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
def interval=(sec)
|
35
|
+
@interval=sec
|
36
|
+
end
|
37
|
+
def interval()
|
38
|
+
@interval
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
end
|
data/lib/noda/task.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Noda
|
2
|
+
|
3
|
+
class Task
|
4
|
+
#�Q�Ɠn���ɂ������Ƃ��� ���� include ���g��
|
5
|
+
# objects-by-reference
|
6
|
+
#def by_reference() include DRb::DRbUndumped end
|
7
|
+
|
8
|
+
#this should be overwrite
|
9
|
+
def do_task(hash_table)
|
10
|
+
end
|
11
|
+
#this should be overwrite
|
12
|
+
def name
|
13
|
+
return self.object_id unless @name
|
14
|
+
return @name if @name
|
15
|
+
end
|
16
|
+
def name=(str) @name=str end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
end
|
21
|
+
|
data/lib/noda.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'drb/drb'
|
3
|
-
|
3
|
+
require 'logger'
|
4
4
|
|
5
5
|
$:.unshift(File.dirname(__FILE__)) unless
|
6
6
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
7
7
|
require 'noda/rqueue'
|
8
8
|
require 'noda/job_server'
|
9
|
+
require 'noda/job_monitor'
|
9
10
|
require 'noda/job_worker'
|
10
11
|
require 'noda/table'
|
11
12
|
require 'noda/task'
|
12
13
|
require 'noda/table'
|
14
|
+
require 'noda/table_auto_saver'
|
13
15
|
|
14
16
|
module Noda
|
15
17
|
#VERSION = '0.0.1'
|
data/noda.gemspec
CHANGED
@@ -5,13 +5,14 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{noda}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["takuya"]
|
12
|
-
s.date = %q{2011-05-
|
12
|
+
s.date = %q{2011-05-28}
|
13
13
|
s.description = %q{noda is job queue system using druby }
|
14
14
|
s.email = %q{takuya.1st@gmail}
|
15
|
+
s.executables = ["noda_job_worker", "noda_job_server"]
|
15
16
|
s.extra_rdoc_files = [
|
16
17
|
"LICENSE.txt",
|
17
18
|
"README.rdoc"
|
@@ -24,9 +25,26 @@ Gem::Specification.new do |s|
|
|
24
25
|
"README.rdoc",
|
25
26
|
"Rakefile",
|
26
27
|
"VERSION",
|
28
|
+
"bin/noda_job_server",
|
29
|
+
"bin/noda_job_worker",
|
27
30
|
"lib/noda.rb",
|
31
|
+
"lib/noda/job_monitor.rb",
|
32
|
+
"lib/noda/job_server.rb",
|
33
|
+
"lib/noda/job_worker.rb",
|
34
|
+
"lib/noda/rqueue.rb",
|
35
|
+
"lib/noda/table.rb",
|
36
|
+
"lib/noda/table_auto_saver.rb",
|
37
|
+
"lib/noda/task.rb",
|
28
38
|
"noda.gemspec",
|
29
|
-
"test/
|
39
|
+
"test/test_helper.rb",
|
40
|
+
"test/test_job_monitor.rb",
|
41
|
+
"test/test_job_server.rb",
|
42
|
+
"test/test_job_worker.rb",
|
43
|
+
"test/test_noda.rb",
|
44
|
+
"test/test_rqueue.rb",
|
45
|
+
"test/test_table.rb",
|
46
|
+
"test/test_table_saver_woker.rb",
|
47
|
+
"test/test_task.rb"
|
30
48
|
]
|
31
49
|
s.homepage = %q{http://github.com/takuya/noda}
|
32
50
|
s.licenses = ["MIT"]
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'drb/drb'
|
5
|
+
require File.dirname(__FILE__) + '/../lib/noda'
|
6
|
+
|
7
|
+
require 'noda'
|
8
|
+
require 'noda/job_server'
|
9
|
+
require 'noda/job_worker'
|
10
|
+
require 'noda/job_monitor'
|
11
|
+
require 'noda/rqueue'
|
12
|
+
require 'noda/table'
|
13
|
+
require 'noda/task'
|
14
|
+
include Noda
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
class TestJobMonitor < Test::Unit::TestCase
|
3
|
+
#�e�X�g�̓}���`�X���b�h�ōs����̂ŁA�|�[�g�Փ˂���Error�ɂȂ�܂��D
|
4
|
+
def test_start_monitor
|
5
|
+
#���j�^���N�����邩�ǂ���
|
6
|
+
m = JobMonitor.new("localhost","10081")
|
7
|
+
t = m.start_monitor
|
8
|
+
sleep 0.01
|
9
|
+
assert m.web_server.status == :Running
|
10
|
+
m.stop_monitor
|
11
|
+
sleep 0.01
|
12
|
+
assert m.web_server.status == :Shutdown
|
13
|
+
end
|
14
|
+
def test_monitor_in_queue
|
15
|
+
require 'open-uri'
|
16
|
+
|
17
|
+
m = JobMonitor.new("localhost", "10080")
|
18
|
+
t = m.start_monitor
|
19
|
+
sleep 0.01
|
20
|
+
assert m.web_server.status == :Running
|
21
|
+
s = JobServer.new
|
22
|
+
s.input.push 1234
|
23
|
+
assert open("http://localhost:10080/").read == "running"
|
24
|
+
assert open("http://localhost:10080/in_queue/").read == "1"
|
25
|
+
s.input.push 1111
|
26
|
+
assert open("http://localhost:10080/in_queue/").read == "2"
|
27
|
+
assert open("http://localhost:10080/in_queue/1").read == "1234"
|
28
|
+
assert open("http://localhost:10080/in_queue/2").read == "1111"
|
29
|
+
d = s.input.pop
|
30
|
+
assert open("http://localhost:10080/in_queue/").read == "1"
|
31
|
+
end
|
32
|
+
def test_monitor_out_queue
|
33
|
+
require 'open-uri'
|
34
|
+
|
35
|
+
s = JobServer.new("localhost","100011")
|
36
|
+
m = JobMonitor.new("localhost", "10083","druby://localhost:100011")
|
37
|
+
t = m.start_monitor
|
38
|
+
sleep 0.01
|
39
|
+
assert m.web_server.status == :Running
|
40
|
+
s.output.push 1234
|
41
|
+
assert open("http://localhost:10083/").read == "running"
|
42
|
+
assert open("http://localhost:10083/out_queue/").read == "1"
|
43
|
+
s.output.push 1111
|
44
|
+
assert open("http://localhost:10083/out_queue/").read == "2"
|
45
|
+
assert open("http://localhost:10083/out_queue/1").read == "1234"
|
46
|
+
assert open("http://localhost:10083/out_queue/2").read == "1111"
|
47
|
+
end
|
48
|
+
def test_monitor_in_queue
|
49
|
+
require 'open-uri'
|
50
|
+
|
51
|
+
s = JobServer.new("localhost","100012")
|
52
|
+
m = JobMonitor.new("localhost", "10084","druby://localhost:100012")
|
53
|
+
t = m.start_monitor
|
54
|
+
sleep 0.01
|
55
|
+
assert m.web_server.status == :Running
|
56
|
+
assert open("http://localhost:10084/").read == "running"
|
57
|
+
assert open("http://localhost:10084/hash_table/").read == "0"
|
58
|
+
s.hash_table.put "1234", "abcdefg"
|
59
|
+
assert open("http://localhost:10084/hash_table/").read == "1"
|
60
|
+
assert open("http://localhost:10084/hash_table/fetch/1234").read == "abcdefg"
|
61
|
+
assert open("http://localhost:10084/hash_table/keys").read == "[\"1234\"]"
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
|
4
|
+
class TestJobServer < Test::Unit::TestCase
|
5
|
+
def test_start_stop_job_server
|
6
|
+
#�W���u�}�X�^���N�����邩�ǂ���
|
7
|
+
s = JobServer.new
|
8
|
+
assert s.alive? == true
|
9
|
+
s.stop
|
10
|
+
assert s.alive? == false
|
11
|
+
end
|
12
|
+
def test_job_server_input_queue
|
13
|
+
#druby�o�R�Ő������u���b�N����邩�ǂ���
|
14
|
+
test_str = "hello world"
|
15
|
+
s=JobServer.new
|
16
|
+
m = m = DRbObject.new_with_uri('druby://localhost:10001')
|
17
|
+
t1 = Thread.new{
|
18
|
+
m1 = DRbObject.new_with_uri('druby://localhost:10001')
|
19
|
+
q1 = m1.input
|
20
|
+
q1.pop
|
21
|
+
|
22
|
+
}
|
23
|
+
#�u���b�N����Ă��邩
|
24
|
+
assert t1.status == "sleep"
|
25
|
+
m2 = DRbObject.new_with_uri('druby://localhost:10001')
|
26
|
+
q2 = m2.input
|
27
|
+
q2.push test_str
|
28
|
+
#�u���b�N��������ꂩ�ǂ���
|
29
|
+
assert t1.status == "run"
|
30
|
+
#�T�[�o�[���~
|
31
|
+
s.stop
|
32
|
+
end
|
33
|
+
def test_job_server_output_queue
|
34
|
+
#druby�o�R�Ő������u���b�N����邩�ǂ���
|
35
|
+
test_str = "hello world"
|
36
|
+
s=JobServer.new
|
37
|
+
m = m = DRbObject.new_with_uri('druby://localhost:10001')
|
38
|
+
t1 = Thread.new{
|
39
|
+
m1 = DRbObject.new_with_uri('druby://localhost:10001')
|
40
|
+
q1 = m1.output
|
41
|
+
q1.pop
|
42
|
+
|
43
|
+
}
|
44
|
+
#�u���b�N����Ă��邩
|
45
|
+
assert t1.status == "sleep"
|
46
|
+
m2 = DRbObject.new_with_uri('druby://localhost:10001')
|
47
|
+
q2 = m2.output
|
48
|
+
q2.push test_str
|
49
|
+
#�u���b�N��������ꂩ�ǂ���
|
50
|
+
assert t1.status == "run"
|
51
|
+
#�T�[�o�[���~
|
52
|
+
s.stop
|
53
|
+
end
|
54
|
+
def test_job_server_input_queue_data
|
55
|
+
s=JobServer.new
|
56
|
+
m = m = DRbObject.new_with_uri('druby://localhost:10001')
|
57
|
+
t1 = Thread.new{
|
58
|
+
m1 = DRbObject.new_with_uri('druby://localhost:10001')
|
59
|
+
q1 = m1.input
|
60
|
+
q1.push "hello world"
|
61
|
+
|
62
|
+
}
|
63
|
+
m2 = DRbObject.new_with_uri('druby://localhost:10001')
|
64
|
+
q2 = m2.input
|
65
|
+
ret = q2.pop
|
66
|
+
assert ret == "hello world"
|
67
|
+
s.stop
|
68
|
+
end
|
69
|
+
def test_job_server_output_queue_data
|
70
|
+
s=JobServer.new
|
71
|
+
m = m = DRbObject.new_with_uri('druby://localhost:10001')
|
72
|
+
t1 = Thread.new{
|
73
|
+
m1 = DRbObject.new_with_uri('druby://localhost:10001')
|
74
|
+
q1 = m1.output
|
75
|
+
q1.push "hello world"
|
76
|
+
|
77
|
+
}
|
78
|
+
m2 = DRbObject.new_with_uri('druby://localhost:10001')
|
79
|
+
q2 = m2.output
|
80
|
+
ret = q2.pop
|
81
|
+
assert ret == "hello world"
|
82
|
+
s.stop
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
class TestJobWoker < Test::Unit::TestCase
|
3
|
+
|
4
|
+
|
5
|
+
def test_init_job_woker
|
6
|
+
worker = JobWorker.new
|
7
|
+
assert worker
|
8
|
+
end
|
9
|
+
#test task
|
10
|
+
class MyTask
|
11
|
+
def do_task(hash)
|
12
|
+
return "test_task_end"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
def test_start_stop
|
16
|
+
s =JobServer.new
|
17
|
+
w = JobWorker.new
|
18
|
+
t = Thread.new{
|
19
|
+
w.start
|
20
|
+
}
|
21
|
+
s.input.push MyTask.new
|
22
|
+
ret = s.output.pop
|
23
|
+
assert ret == "test_task_end"
|
24
|
+
s.stop
|
25
|
+
w.stop
|
26
|
+
assert w.status == false #�X���b�h�I���ł����H
|
27
|
+
end
|
28
|
+
def test_do_task
|
29
|
+
s=JobServer.new
|
30
|
+
worker = JobWorker.new
|
31
|
+
s.input.push MyTask.new
|
32
|
+
worker.handle_task
|
33
|
+
ret = s.output.pop
|
34
|
+
assert ret == "test_task_end"
|
35
|
+
s.stop
|
36
|
+
end
|
37
|
+
class MyTask2
|
38
|
+
def do_task(hash)
|
39
|
+
hash.put "MyTask", "foooo"
|
40
|
+
return "test_task_end"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
def test_task_write_hash_table
|
44
|
+
#�W���u�T�[�o�[�̋��L�̈�ɏ������߂邩�ǂ���
|
45
|
+
s=JobServer.new
|
46
|
+
worker = JobWorker.new
|
47
|
+
s.input.push MyTask2.new
|
48
|
+
worker.handle_task
|
49
|
+
ret = s.output.pop
|
50
|
+
assert ret == "test_task_end"
|
51
|
+
v = s.hash_table.get "MyTask"
|
52
|
+
assert v == "foooo"
|
53
|
+
s.stop
|
54
|
+
end
|
55
|
+
end
|
data/test/test_rqueue.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestRQueue < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@q = RQueue.new
|
6
|
+
end
|
7
|
+
def test_RQueue_init
|
8
|
+
q = RQueue.new
|
9
|
+
assert q.empty?
|
10
|
+
end
|
11
|
+
def test_RQueue_init_with_RQueue_max_size
|
12
|
+
max = 10
|
13
|
+
q = RQueue.new max
|
14
|
+
assert q.empty? && q.max_size==max
|
15
|
+
end
|
16
|
+
def test_RQueue_mutex_push
|
17
|
+
max = 100
|
18
|
+
q = RQueue.new max
|
19
|
+
th1 = Thread.new{
|
20
|
+
loop{
|
21
|
+
q.push 1
|
22
|
+
}
|
23
|
+
}
|
24
|
+
th2 = Thread.new{
|
25
|
+
loop{
|
26
|
+
q.push 1
|
27
|
+
}
|
28
|
+
}
|
29
|
+
sleep 0.1
|
30
|
+
assert th1.status == "sleep" && th2.status == "sleep" && q.full?
|
31
|
+
end
|
32
|
+
def test_RQueue_mutex_pop
|
33
|
+
max = 10
|
34
|
+
q = RQueue.new max
|
35
|
+
max.times{ q.push 1 }
|
36
|
+
th1 = Thread.new{
|
37
|
+
loop{
|
38
|
+
q.pop
|
39
|
+
}
|
40
|
+
}
|
41
|
+
th2 = Thread.new{
|
42
|
+
loop{
|
43
|
+
q.pop
|
44
|
+
}
|
45
|
+
}
|
46
|
+
while not q.empty? do
|
47
|
+
sleep 0.1
|
48
|
+
end
|
49
|
+
assert th1.status == "sleep" && th2.status == "sleep" && q.empty?
|
50
|
+
end
|
51
|
+
end
|
data/test/test_table.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestPageList < Test::Unit::TestCase
|
4
|
+
def test_table_put
|
5
|
+
list = Table.new
|
6
|
+
key,value = "test", "valuevalue"
|
7
|
+
list.put key,value
|
8
|
+
assert list.get(key) == value
|
9
|
+
end
|
10
|
+
def test_table_size
|
11
|
+
list = Table.new
|
12
|
+
assert list.size == 0
|
13
|
+
key,value = "test", "valuevalue"
|
14
|
+
list.put key,value
|
15
|
+
assert list.size == 1
|
16
|
+
end
|
17
|
+
def test_table_exists
|
18
|
+
list = Table.new
|
19
|
+
key,value = "test", "valuevalue"
|
20
|
+
list.put key,value
|
21
|
+
assert list.exists? key
|
22
|
+
end
|
23
|
+
def test_table_each
|
24
|
+
list = Table.new
|
25
|
+
data = { "a"=> "aa","b"=>"bv", "c"=> "cc", "d"=> "dd" }
|
26
|
+
data.each{|k,v| list.put k,v }
|
27
|
+
data.each{|k,v| assert list.get(k) == v }
|
28
|
+
list.each{|k,v| assert data[k] == v }
|
29
|
+
end
|
30
|
+
def test_save_table_data
|
31
|
+
list = Table.new
|
32
|
+
key,value = "test", "valuevalue"
|
33
|
+
list.put key,value
|
34
|
+
assert list.saved?(key) == false
|
35
|
+
list.update_saved_at(key)
|
36
|
+
assert list.saved?(key) == true
|
37
|
+
end
|
38
|
+
def test_table_each_unsaved_pair
|
39
|
+
list = Table.new
|
40
|
+
data = { "a"=> "aa","b"=>"bb", "c"=> "cc", "d"=> "dd" }
|
41
|
+
data.each{|k,v| list.put k,v }
|
42
|
+
list.put( "abc","123")
|
43
|
+
list.update_saved_at("abc")
|
44
|
+
assert list.saved?("abc")
|
45
|
+
a={}
|
46
|
+
list.each_unsaved_pair{|k,v| a[k]=v }
|
47
|
+
assert a.sort == data.sort
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
Thread.abort_on_exception=true
|
3
|
+
|
4
|
+
class TestTableSaverWorker < Test::Unit::TestCase
|
5
|
+
def test_table_saver_initialize
|
6
|
+
s = JobServer.new("localhost","10001")
|
7
|
+
saver = TableAutoSaver.new
|
8
|
+
saver.interval = 12
|
9
|
+
assert saver.interval == 12
|
10
|
+
end
|
11
|
+
def test_table_saver_save_dir
|
12
|
+
s = JobServer.new("localhost","10002")
|
13
|
+
saver = TableAutoSaver.new("localhost","10002")
|
14
|
+
begin
|
15
|
+
saver.save_dir = Dir.tmpdir + "a"
|
16
|
+
rescue => e
|
17
|
+
assert e.to_s =~ %r"is not direcotry."
|
18
|
+
end
|
19
|
+
d = Dir.mktmpdir("table_saver_")
|
20
|
+
saver.save_dir = d
|
21
|
+
assert saver.save_dir == d
|
22
|
+
Dir.rmdir d
|
23
|
+
assert FileTest.exists? d == false
|
24
|
+
end
|
25
|
+
def test_table_saver_save_dir
|
26
|
+
s = JobServer.new("localhost","10003")
|
27
|
+
saver = TableAutoSaver.new("localhost","10003")
|
28
|
+
t1 = saver.init_thread
|
29
|
+
t2 = Thread.new{
|
30
|
+
s.hash_table.put("aaaa",1234)
|
31
|
+
s.hash_table.put("baaa",1234)
|
32
|
+
s.hash_table.put("caaa",1234)
|
33
|
+
s.hash_table.put("daaa",1234)
|
34
|
+
s.hash_table.put("eaaa",1234)
|
35
|
+
while(s.hash_table.has_unsaved_key? )
|
36
|
+
sleep 0.001
|
37
|
+
end
|
38
|
+
}
|
39
|
+
|
40
|
+
t2.join
|
41
|
+
|
42
|
+
assert s.hash_table.has_unsaved_key? == false
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/test/test_task.rb
ADDED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: noda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 5
|
10
|
+
version: 0.0.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- takuya
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-28 00:00:00 +09:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -80,8 +80,9 @@ dependencies:
|
|
80
80
|
version_requirements: *id004
|
81
81
|
description: "noda is job queue system using druby "
|
82
82
|
email: takuya.1st@gmail
|
83
|
-
executables:
|
84
|
-
|
83
|
+
executables:
|
84
|
+
- noda_job_worker
|
85
|
+
- noda_job_server
|
85
86
|
extensions: []
|
86
87
|
|
87
88
|
extra_rdoc_files:
|
@@ -95,9 +96,26 @@ files:
|
|
95
96
|
- README.rdoc
|
96
97
|
- Rakefile
|
97
98
|
- VERSION
|
99
|
+
- bin/noda_job_server
|
100
|
+
- bin/noda_job_worker
|
98
101
|
- lib/noda.rb
|
102
|
+
- lib/noda/job_monitor.rb
|
103
|
+
- lib/noda/job_server.rb
|
104
|
+
- lib/noda/job_worker.rb
|
105
|
+
- lib/noda/rqueue.rb
|
106
|
+
- lib/noda/table.rb
|
107
|
+
- lib/noda/table_auto_saver.rb
|
108
|
+
- lib/noda/task.rb
|
99
109
|
- noda.gemspec
|
110
|
+
- test/test_helper.rb
|
111
|
+
- test/test_job_monitor.rb
|
112
|
+
- test/test_job_server.rb
|
113
|
+
- test/test_job_worker.rb
|
100
114
|
- test/test_noda.rb
|
115
|
+
- test/test_rqueue.rb
|
116
|
+
- test/test_table.rb
|
117
|
+
- test/test_table_saver_woker.rb
|
118
|
+
- test/test_task.rb
|
101
119
|
has_rdoc: true
|
102
120
|
homepage: http://github.com/takuya/noda
|
103
121
|
licenses:
|