noda 0.0.1 → 0.0.5
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/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:
|