Skip to content

Commit a99647b

Browse files
committed
PerfectQueue v0.8 initial commit
1 parent 863c27b commit a99647b

40 files changed

+2085
-1630
lines changed

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.bundle
2+
Gemfile.lock
3+
vendor/*
4+
coverage/*
5+
pkg/*
6+
spec/test.db

Gemfile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source :rubygems
2+
3+
gemspec

Rakefile

+12-41
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,19 @@
1-
require 'rake'
2-
require 'rake/testtask'
3-
require 'rake/clean'
1+
require 'bundler'
2+
Bundler::GemHelper.install_tasks
43

5-
begin
6-
require 'jeweler'
7-
Jeweler::Tasks.new do |gemspec|
8-
gemspec.name = "perfectqueue"
9-
gemspec.summary = "Highly available distributed queue built on RDBMS or SimpleDB"
10-
gemspec.author = "Sadayuki Furuhashi"
11-
gemspec.email = "[email protected]"
12-
gemspec.homepage = "https://github.com/treasure-data/perfectqueue"
13-
#gemspec.has_rdoc = false
14-
gemspec.require_paths = ["lib"]
15-
gemspec.add_dependency "sequel", "~> 3.26.0"
16-
gemspec.add_dependency "aws-sdk", "~> 1.1.1"
17-
gemspec.test_files = Dir["test/**/*.rb", "test/**/*.sh"]
18-
gemspec.files = Dir["bin/**/*", "lib/**/*"]
19-
gemspec.executables = ['perfectqueue']
20-
end
21-
Jeweler::GemcutterTasks.new
22-
rescue LoadError
23-
puts "Jeweler not available. Install it with: gem install jeweler"
24-
end
4+
require 'rspec/core'
5+
require 'rspec/core/rake_task'
256

26-
Rake::TestTask.new(:test) do |t|
27-
t.test_files = Dir['test/*_test.rb']
28-
t.ruby_opts = ['-rubygems'] if defined? Gem
29-
t.ruby_opts << '-I.'
7+
RSpec::Core::RakeTask.new(:spec) do |t|
8+
t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
9+
t.pattern = 'spec/**/*_spec.rb'
10+
t.verbose = true
3011
end
3112

32-
VERSION_FILE = "lib/perfectqueue/version.rb"
33-
34-
file VERSION_FILE => ["VERSION"] do |t|
35-
version = File.read("VERSION").strip
36-
File.open(VERSION_FILE, "w") {|f|
37-
f.write <<EOF
38-
module PerfectQueue
39-
40-
VERSION = '#{version}'
41-
42-
end
43-
EOF
44-
}
13+
task :coverage do |t|
14+
ENV['SIMPLE_COV'] = '1'
15+
Rake::Task["spec"].invoke
4516
end
4617

47-
task :default => [VERSION_FILE, :build]
18+
task :default => :build
4819

VERSION

-1
This file was deleted.

lib/perfectqueue.rb

+66-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,66 @@
1-
require 'perfectqueue/engine'
2-
require 'perfectqueue/worker'
3-
require 'perfectqueue/backend'
4-
require 'perfectqueue/version'
1+
#
2+
# PerfectQueue
3+
#
4+
# Copyright (C) 2012 FURUHASHI Sadayuki
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
19+
module PerfectQueue
20+
require 'json'
21+
require 'thread' # Mutex, CoditionVariable
22+
23+
{
24+
:Application => 'perfectqueue/application',
25+
:Backend => 'perfectqueue/backend',
26+
:BackendHelper => 'perfectqueue/backend',
27+
:BlockingFlag => 'perfectqueue/blocking_flag',
28+
:Client => 'perfectqueue/client',
29+
:DaemonsLogger => 'perfectqueue/daemons_logger',
30+
:Engine => 'perfectqueue/engine',
31+
:Model => 'perfectqueue/model',
32+
:Queue => 'perfectqueue/queue',
33+
:Runner => 'perfectqueue/runner',
34+
:Task => 'perfectqueue/task',
35+
:TaskWithMetadata => 'perfectqueue/task',
36+
:AcquiredTask => 'perfectqueue/task',
37+
:TaskMetadata => 'perfectqueue/task_metadata',
38+
:TaskMetadataAccessors => 'perfectqueue/task_metadata',
39+
:TaskStatus => 'perfectqueue/task_status',
40+
:Worker => 'perfectqueue/worker',
41+
}.each_pair {|k,v|
42+
autoload k, File.expand_path(v, File.dirname(__FILE__))
43+
}
44+
[
45+
'perfectqueue/multiprocess',
46+
'perfectqueue/error',
47+
].each {|v|
48+
require File.expand_path(v, File.dirname(__FILE__))
49+
}
50+
51+
def self.open(config, &block)
52+
c = Client.new(config)
53+
begin
54+
q = Queue.new(c)
55+
if block
56+
block.call(q)
57+
else
58+
c = nil
59+
return q
60+
end
61+
ensure
62+
c.close if c
63+
end
64+
end
65+
end
66+
+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#
2+
# PerfectQueue
3+
#
4+
# Copyright (C) 2012 FURUHASHI Sadayuki
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
19+
module PerfectQueue
20+
module Application
21+
22+
class Router
23+
def initialize
24+
@patterns = []
25+
@cache = {}
26+
end
27+
28+
def add(pattern, sym, options={})
29+
case pattern
30+
when Regexp
31+
# ok
32+
when String, Symbol
33+
pattern = /#{Regexp.escape(pattern)}/
34+
else
35+
raise ArguementError, "pattern should be String or Regexp but got #{pattern.class}: #{pattern.inspect}"
36+
end
37+
38+
@patterns << [pattern, sym]
39+
end
40+
41+
def route(type)
42+
if @cache.has_key?(type)
43+
return @cache[type]
44+
end
45+
46+
@patterns.each {|(pattern,sym)|
47+
if pattern.match(type)
48+
runner = resolve_application_base(sym)
49+
return @cache[type] = runner
50+
end
51+
}
52+
return @cache[type] = nil
53+
end
54+
55+
private
56+
def resolve_application_base(klass)
57+
case klass
58+
when Symbol
59+
self.class.const_get(klass)
60+
else
61+
klass
62+
end
63+
end
64+
end
65+
66+
class Dispatch
67+
# Runner interface
68+
def self.new(task)
69+
runner = router.route(task.type)
70+
unless runner
71+
task.release!
72+
raise "unknown task type #{task.type.inspect}" # TODO error class
73+
end
74+
b = runner.new(task)
75+
return b
76+
end
77+
78+
# DSL interface
79+
class << self
80+
def route(options)
81+
patterns = options.keys.select {|k| !k.is_a?(Symbol) }
82+
klasses = patterns.map {|k| options.delete(k) }
83+
patterns.zip(klasses).each {|pattern,sym|
84+
add_route(pattern, sym, options)
85+
}
86+
nil
87+
end
88+
89+
def add_route(pattern, klass, options)
90+
router.add(pattern, klass, options)
91+
end
92+
93+
private
94+
def router=(router)
95+
remove_method(:router) if method_defined?(:router)
96+
define_method(:router) { router }
97+
end
98+
99+
def router
100+
router = Router.new
101+
end
102+
end
103+
end
104+
end
105+
end
106+

lib/perfectqueue/application.rb

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#
2+
# PerfectQueue
3+
#
4+
# Copyright (C) 2012 FURUHASHI Sadayuki
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
19+
module PerfectQueue
20+
module Application
21+
{
22+
:Dispatch => 'application/dispatch',
23+
:Router => 'application/dispatch',
24+
}.each_pair {|k,v|
25+
autoload k, File.expand_path(v, File.dirname(__FILE__))
26+
}
27+
end
28+
end
29+

lib/perfectqueue/backend.rb

+44-47
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,49 @@
1+
#
2+
# PerfectQueue
3+
#
4+
# Copyright (C) 2012 FURUHASHI Sadayuki
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
118

219
module PerfectQueue
3-
4-
5-
class Task
6-
def initialize(id, created_at, data, resource=nil)
7-
@id = id
8-
@created_at = created_at
9-
@data = data
10-
@resource = resource
20+
module Backend
21+
def self.new_backend(client, config)
22+
case config[:type]
23+
when nil
24+
raise ConfigError, "'type' option is not set"
25+
when 'rdb_compat'
26+
require_backend('rdb_compat')
27+
RDBCompatBackend.new(client, config)
28+
end
29+
end
30+
31+
def self.require_backend(fname)
32+
require File.expand_path("backend/#{fname}", File.dirname(__FILE__))
33+
end
34+
end
35+
36+
module BackendHelper
37+
def initialize(client, config)
38+
@client = client
39+
@config = config
40+
end
41+
42+
attr_reader :client
43+
44+
def close
45+
# do nothing by default
46+
end
1147
end
12-
13-
attr_reader :id, :created_at, :data, :resource
14-
end
15-
16-
17-
class CanceledError < RuntimeError
18-
end
19-
20-
21-
class Backend
22-
# => list {|id,created_at,data,timeout| ... }
23-
def list(&block)
24-
end
25-
26-
# => token, task
27-
def acquire(timeout, now=Time.now.to_i)
28-
end
29-
30-
# => true (success) or false (canceled)
31-
def finish(token, delete_timeout=3600, now=Time.now.to_i)
32-
end
33-
34-
# => nil
35-
def update(token, timeout)
36-
end
37-
38-
# => true (success) or false (not found, canceled or finished)
39-
def cancel(id, delete_timeout=3600, now=Time.now.to_i)
40-
end
41-
42-
# => true (success) or nil (already exists)
43-
def submit(id, data, time=Time.now.to_i, resource=nil)
44-
end
45-
46-
def close
47-
end
48-
end
49-
50-
5148
end
5249

0 commit comments

Comments
 (0)