ap4r 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -1
- data/Manifest.txt +5 -0
- data/Rakefile +106 -72
- data/config/queues_ar.cfg +20 -0
- data/lib/ap4r/db/migrate/001_reliable_msg_queue_and_topic.rb +22 -0
- data/lib/ap4r/dispatcher.rb +23 -8
- data/lib/ap4r/message_store_ext.rb +249 -0
- data/lib/ap4r/recipes.rb +124 -0
- data/lib/ap4r/reliable_msg_queue.rb +4 -0
- data/lib/ap4r/reliable_msg_topic.rb +4 -0
- data/lib/ap4r/version.rb +1 -1
- data/rails_plugin/ap4r/lib/async_helper.rb +76 -20
- data/rails_plugin/ap4r/lib/message_builder.rb +1 -1
- metadata +7 -2
data/History.txt
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
== 0.3.x
|
2
2
|
|
3
|
-
=== 0.3.
|
3
|
+
=== 0.3.4 (October 31, 2007)
|
4
|
+
* Added: Support ActiveRecord as reliable RDBMS persistence.
|
5
|
+
* Added: Capistrano recipes.
|
6
|
+
* Added: A dispatcher via druby.
|
7
|
+
Based on a patch from Kouhei Sutou <kou at cozmixng.org>.
|
8
|
+
* Added: Support memory queue which is volatile.
|
9
|
+
|
10
|
+
=== 0.3.3 (September 19, 2007)
|
4
11
|
* Added: Support with hoe.
|
5
12
|
* Added: Support PostgreSQL as reliable RDBMS persistence.
|
6
13
|
* Added: Test supports, stub of queueing and service controls.
|
data/Manifest.txt
CHANGED
@@ -7,11 +7,13 @@ bin/ap4r_setup
|
|
7
7
|
config/ap4r_settings.rb
|
8
8
|
config/log4r.yaml
|
9
9
|
config/queues.cfg
|
10
|
+
config/queues_ar.cfg
|
10
11
|
config/queues_disk.cfg
|
11
12
|
config/queues_mysql.cfg
|
12
13
|
config/queues_pgsql.cfg
|
13
14
|
lib/ap4r.rb
|
14
15
|
lib/ap4r/carrier.rb
|
16
|
+
lib/ap4r/db/migrate/001_reliable_msg_queue_and_topic.rb
|
15
17
|
lib/ap4r/dispatcher.rb
|
16
18
|
lib/ap4r/message_store_ext.rb
|
17
19
|
lib/ap4r/mongrel.rb
|
@@ -20,6 +22,9 @@ lib/ap4r/multi_queue.rb
|
|
20
22
|
lib/ap4r/postgresql.sql
|
21
23
|
lib/ap4r/queue_manager_ext.rb
|
22
24
|
lib/ap4r/queue_manager_ext_debug.rb
|
25
|
+
lib/ap4r/recipes.rb
|
26
|
+
lib/ap4r/reliable_msg_queue.rb
|
27
|
+
lib/ap4r/reliable_msg_topic.rb
|
23
28
|
lib/ap4r/retention_history.rb
|
24
29
|
lib/ap4r/script/base.rb
|
25
30
|
lib/ap4r/script/queue_manager_control.rb
|
data/Rakefile
CHANGED
@@ -1,85 +1,98 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'hoe'
|
3
|
+
require 'erb'
|
4
|
+
require 'active_record'
|
3
5
|
require File.join(File.dirname(__FILE__), 'lib/ap4r', 'version')
|
4
6
|
|
5
|
-
|
7
|
+
namespace :hoe do
|
8
|
+
hoe = Hoe.new('ap4r', Ap4r::VERSION::STRING) do |p|
|
9
|
+
p.author = ["Shunichi Shinohara", "Kiwamu Kato"]
|
10
|
+
p.changes = p.paragraphs_of('History.txt', 1..2).join("\n\n")
|
11
|
+
#p.clean_globs =
|
12
|
+
p.description = <<-EOF
|
13
|
+
Asynchronous Processing for Ruby.
|
14
|
+
EOF
|
15
|
+
p.email = %q{shinohara.shunichi@future.co.jp, kato.kiwamu@future.co.jp}
|
16
|
+
|
17
|
+
p.extra_deps << ['reliable-msg', '=1.1.0']
|
18
|
+
p.extra_deps << ['activesupport']
|
19
|
+
p.extra_deps << ['mongrel']
|
20
|
+
p.extra_deps << ['rake']
|
21
|
+
p.extra_deps << ['hoe']
|
22
|
+
|
23
|
+
p.name = 'ap4r'
|
24
|
+
p.need_tar = false
|
25
|
+
p.need_zip = false
|
26
|
+
p.rdoc_pattern = /^(lib|bin|ext|rails_plugin)|txt$/
|
27
|
+
|
28
|
+
#p.remote_rdoc_dir =
|
29
|
+
#p.rsync =
|
30
|
+
p.rubyforge_name = 'ap4r'
|
31
|
+
#p.spec_extra =
|
32
|
+
p.summary = 'Asynchronous Processing for Ruby.'
|
33
|
+
p.test_globs = 'spec/**/*_spec.rb'
|
34
|
+
p.url = 'http://ap4r.rubyforge.org/wiki/wiki.pl?HomePage'
|
35
|
+
p.version = Ap4r::VERSION::STRING
|
36
|
+
end
|
37
|
+
hoe.spec.dependencies.delete_if {|dep| dep.name == "hoe"}
|
38
|
+
|
39
|
+
end
|
40
|
+
task :pkg => "release:copy_plugin"
|
6
41
|
|
7
42
|
# AP4R release tasks --------------------------------------------------------
|
8
43
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
p.extra_deps << ['reliable-msg', '=1.1.0']
|
24
|
-
p.extra_deps << ['activesupport']
|
25
|
-
p.extra_deps << ['mongrel']
|
26
|
-
p.extra_deps << ['rake']
|
27
|
-
p.extra_deps << ['hoe']
|
28
|
-
|
29
|
-
p.name = 'ap4r'
|
30
|
-
p.need_tar = false
|
31
|
-
p.need_zip = false
|
32
|
-
#p.rdoc_pattern =
|
33
|
-
#p.remote_rdoc_dir =
|
34
|
-
#p.rsync =
|
35
|
-
p.rubyforge_name = 'ap4r'
|
36
|
-
#p.spec_extra =
|
37
|
-
p.summary = 'Asynchronous Processing for Ruby.'
|
38
|
-
p.test_globs = 'spec/**/*_spec.rb'
|
39
|
-
p.url = 'http://ap4r.rubyforge.org/wiki/wiki.pl?HomePage'
|
40
|
-
p.version = Ap4r::VERSION::STRING
|
41
|
-
end.spec.dependencies.delete_if {|dep| dep.name == "hoe"}
|
42
|
-
|
43
|
-
|
44
|
-
desc 'Create Manifest.txt'
|
45
|
-
task :create_manifest do
|
46
|
-
|
47
|
-
path_list = []
|
48
|
-
Find.find('.') do |path|
|
49
|
-
next unless File.file? path
|
50
|
-
next if path =~ /\.svn|tmp$|CVS|.rb\~/
|
51
|
-
path_list << path
|
44
|
+
HelloWorld = '../samples/HelloWorld'
|
45
|
+
|
46
|
+
namespace :release do
|
47
|
+
desc "copy rails plugin from sample before gem build"
|
48
|
+
task :copy_plugin do
|
49
|
+
# TODO: Should use file task ? 2007/09/27 by shino
|
50
|
+
FileUtils.rm_rf('./rails_plugin/ap4r')
|
51
|
+
FileUtils.mkdir_p('./rails_plugin/ap4r/lib')
|
52
|
+
FileUtils.cp(HelloWorld + '/db/migrate/001_create_table_for_saf.rb',
|
53
|
+
'./lib/ap4r/xxx_create_table_for_saf.rb')
|
54
|
+
FileUtils.cp_r(Dir.glob(HelloWorld + '/vendor/plugins/ap4r/*').reject{|f| f =~ /tmp$|CVS|\.svn/},
|
55
|
+
'./rails_plugin/ap4r')
|
56
|
+
# TODO: dot files and tilde files are copied 2007/09/20 by shino
|
52
57
|
end
|
53
58
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
59
|
+
desc "Create Manifest.txt"
|
60
|
+
task :create_manifest => [:copy_plugin] do
|
61
|
+
path_list = []
|
62
|
+
Find.find('.') do |path|
|
63
|
+
next unless File.file?(path)
|
64
|
+
next if path =~ /^\.\/doc\//
|
65
|
+
next if path =~ /\.svn|tmp$|CVS|\~$/
|
66
|
+
path_list << path
|
58
67
|
end
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
68
|
|
69
|
+
File.open('Manifest.txt', 'w') do |manifest|
|
70
|
+
path_list.sort.each do |path|
|
71
|
+
/.\// =~ path
|
72
|
+
manifest.puts($~.post_match)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
63
76
|
|
77
|
+
# Sample release tasks ------------------------------------------------------
|
78
|
+
desc 'Make sample tarball (Now only one sample "HelloWorld").'
|
79
|
+
task :sample do
|
80
|
+
FileUtils.mkdir_p('./pkg/samples')
|
81
|
+
FileUtils.rm_rf('./pkg/samples/HelloWorld')
|
82
|
+
|
83
|
+
FileUtils.cp_r(HelloWorld, './pkg/samples/')
|
84
|
+
Find.find('./pkg/samples') do |path|
|
85
|
+
next unless File.file? path
|
86
|
+
FileUtils.rm_rf(path) if path =~ /\.svn|tmp$|CVS|.rb\~/
|
87
|
+
end
|
64
88
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
FileUtils.cp_r(HelloWorld, './pkg/samples/')
|
72
|
-
Find.find('./pkg/samples') do |path|
|
73
|
-
next unless File.file? path
|
74
|
-
FileUtils.rm_rf(path) if path =~ /\.svn|tmp$|CVS|.rb\~/
|
89
|
+
Dir.chdir('./pkg/samples/HelloWorld')
|
90
|
+
`rake db:migrate`
|
91
|
+
Dir.chdir('../../')
|
92
|
+
|
93
|
+
`tar czf HelloWorld-#{Ap4r::VERSION::STRING}.tar.gz ./samples/HelloWorld/`
|
94
|
+
Dir.chdir('../')
|
75
95
|
end
|
76
|
-
|
77
|
-
Dir.chdir('./pkg/samples/HelloWorld')
|
78
|
-
`rake db:migrate`
|
79
|
-
Dir.chdir('../../')
|
80
|
-
|
81
|
-
`tar czvf HelloWorld-#{Ap4r::VERSION::STRING}.tar.gz ./samples/HelloWorld/`
|
82
|
-
Dir.chdir('../')
|
83
96
|
end
|
84
97
|
|
85
98
|
|
@@ -112,11 +125,11 @@ end
|
|
112
125
|
|
113
126
|
# AP4R misc tools ----------------------------------------------------------------
|
114
127
|
|
128
|
+
require 'active_support'
|
129
|
+
require 'code_statistics'
|
130
|
+
|
115
131
|
desc "display code statistics"
|
116
|
-
task :stats do
|
117
|
-
require 'rubygems'
|
118
|
-
require 'active_support'
|
119
|
-
require 'code_statistics'
|
132
|
+
task :stats => "release:copy_plugin" do
|
120
133
|
CodeStatistics::TEST_TYPES.concat(["Local specs"])
|
121
134
|
CodeStatistics.new(
|
122
135
|
["Core Sources", "lib"],
|
@@ -125,3 +138,24 @@ task :stats do
|
|
125
138
|
["Local specs", "spec/local"]
|
126
139
|
).to_s
|
127
140
|
end
|
141
|
+
|
142
|
+
namespace :qdb do
|
143
|
+
desc "Make queue and topic tables through scripts in lib/ap4r/db/migrate."
|
144
|
+
task :migrate do
|
145
|
+
|
146
|
+
# Todo: configurable file name, 2007/10/01 kiwamu
|
147
|
+
ap4r_config_file = "config/queues_ar.cfg"
|
148
|
+
ap4r_config = YAML::load(ERB.new(IO.read(ap4r_config_file)).result)
|
149
|
+
database_config = ap4r_config["store"]
|
150
|
+
if "activerecord" == database_config["type"].downcase
|
151
|
+
database_config["adapter"] = database_config["adapter"].downcase
|
152
|
+
else
|
153
|
+
# Todo
|
154
|
+
end
|
155
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
156
|
+
ActiveRecord::Base.establish_connection(database_config)
|
157
|
+
|
158
|
+
ActiveRecord::Migrator.migrate("lib/ap4r/db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
store:
|
3
|
+
type: activerecord
|
4
|
+
adapter: sqlite3
|
5
|
+
host: localhost
|
6
|
+
database: reliable_msg.db
|
7
|
+
username: ap4r
|
8
|
+
password: ap4r
|
9
|
+
drb:
|
10
|
+
host:
|
11
|
+
port: 6438
|
12
|
+
acl: allow 127.0.0.1 allow ::1 allow 10.0.0.0/8
|
13
|
+
dispatchers:
|
14
|
+
-
|
15
|
+
targets: queue.*
|
16
|
+
threads: 1
|
17
|
+
#carriers:
|
18
|
+
# -
|
19
|
+
# source_uri: druby://another.host.local:6438
|
20
|
+
# threads: 1
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ReliableMsgQueueAndTopic < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :reliable_msg_queues do |t|
|
5
|
+
t.column "message_id", :string
|
6
|
+
t.column "queue", :string
|
7
|
+
t.column "headers", :binary
|
8
|
+
t.column "object", :binary
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table :reliable_msg_topics do |t|
|
12
|
+
t.column "topic", :string
|
13
|
+
t.column "headers", :binary
|
14
|
+
t.column "object", :binary
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.down
|
19
|
+
drop_table :reliable_msg_queues
|
20
|
+
drop_table :reliable_msg_topics
|
21
|
+
end
|
22
|
+
end
|
data/lib/ap4r/dispatcher.rb
CHANGED
@@ -54,7 +54,7 @@ module Ap4r
|
|
54
54
|
|
55
55
|
# Starts every dispatcher.
|
56
56
|
# If an exception is detected, this method raise it through with logging.
|
57
|
-
#
|
57
|
+
#
|
58
58
|
def start
|
59
59
|
begin
|
60
60
|
logger.info{ "about to start dispatchers with config\n#{@config.to_yaml}" }
|
@@ -98,7 +98,7 @@ module Ap4r
|
|
98
98
|
klass.new(message, conf_per_targets)
|
99
99
|
end
|
100
100
|
|
101
|
-
# Defines the general structure for each dispatcher thread
|
101
|
+
# Defines the general structure for each dispatcher thread
|
102
102
|
# from begging to end.
|
103
103
|
def dispatching_loop(group, conf, index)
|
104
104
|
group.add(Thread.current)
|
@@ -112,7 +112,7 @@ module Ap4r
|
|
112
112
|
begin
|
113
113
|
mq.get{|m|
|
114
114
|
unless m
|
115
|
-
logger.debug{"message is nul"}
|
115
|
+
logger.debug{"message is nul"}
|
116
116
|
break
|
117
117
|
end
|
118
118
|
logger.debug{"dispatcher get message\n#{m.to_yaml}"}
|
@@ -148,7 +148,7 @@ module Ap4r
|
|
148
148
|
::Ap4r::Dispatchers.register_dispatcher_class(mode_symbol, self)
|
149
149
|
end
|
150
150
|
|
151
|
-
# Takes
|
151
|
+
# Takes
|
152
152
|
# * +message+: from a queue
|
153
153
|
# * +conf+: configuration from dispatchers section
|
154
154
|
#--
|
@@ -217,7 +217,7 @@ module Ap4r
|
|
217
217
|
# <tt>options[:target_method]</tt>.
|
218
218
|
#
|
219
219
|
# Determination of "success" is two fold:
|
220
|
-
# * status code should be exactly 200, other codes (including 201-2xx) are
|
220
|
+
# * status code should be exactly 200, other codes (including 201-2xx) are
|
221
221
|
# treated as error, and
|
222
222
|
# * body should include a string "true"
|
223
223
|
#
|
@@ -231,12 +231,12 @@ module Ap4r
|
|
231
231
|
@response = nil
|
232
232
|
uri = URI.parse(@message[:target_url])
|
233
233
|
headers = make_header
|
234
|
-
|
234
|
+
|
235
235
|
Net::HTTP.start(uri.host, uri.port) do |http|
|
236
236
|
@response, = http.post(uri.path, @message.object, headers)
|
237
237
|
end
|
238
238
|
end
|
239
|
-
|
239
|
+
|
240
240
|
def make_header
|
241
241
|
headers = { }
|
242
242
|
@message.headers.map do |k,v|
|
@@ -246,7 +246,7 @@ module Ap4r
|
|
246
246
|
end
|
247
247
|
headers
|
248
248
|
end
|
249
|
-
|
249
|
+
|
250
250
|
def validate_response
|
251
251
|
logger.debug{"response status [#{@response.code} #{@response.message}]"}
|
252
252
|
validate_response_status(Net::HTTPOK)
|
@@ -322,5 +322,20 @@ module Ap4r
|
|
322
322
|
end
|
323
323
|
end
|
324
324
|
|
325
|
+
# Dispatches via druby protocol with the implementation DRb.
|
326
|
+
#
|
327
|
+
# The call result is judged as
|
328
|
+
# * "success" if finishes normally (without an exception)
|
329
|
+
# * "failuer" if finishes with an exception
|
330
|
+
#
|
331
|
+
class Druby < Base
|
332
|
+
dispatch_mode :druby
|
333
|
+
|
334
|
+
def invoke
|
335
|
+
object = DRbObject.new_with_uri(@message[:target_url])
|
336
|
+
object.method_missing(@message[:target_method].to_sym, @message.object)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
325
340
|
end
|
326
341
|
end
|
@@ -30,6 +30,23 @@ module ReliableMsg #:nodoc:
|
|
30
30
|
}
|
31
31
|
queue_and_created ? queue_and_created[0] : nil
|
32
32
|
end
|
33
|
+
|
34
|
+
# Returns a message store from the specified configuration (previously
|
35
|
+
# created with configure).
|
36
|
+
#
|
37
|
+
# :call-seq:
|
38
|
+
# Base::configure(config, logger) -> store
|
39
|
+
#
|
40
|
+
def self.configure config, logger
|
41
|
+
if config["type"].downcase.starts_with?("activerecord")
|
42
|
+
type = config["type"].downcase.split("_").first
|
43
|
+
else
|
44
|
+
type = config["type"].downcase
|
45
|
+
end
|
46
|
+
cls = @@stores[type]
|
47
|
+
raise RuntimeError, format(ERROR_INVALID_MESSAGE_STORE, type) unless cls
|
48
|
+
cls.new config, logger
|
49
|
+
end
|
33
50
|
|
34
51
|
end
|
35
52
|
|
@@ -200,11 +217,243 @@ module ReliableMsg #:nodoc:
|
|
200
217
|
end
|
201
218
|
|
202
219
|
end
|
220
|
+
|
221
|
+
rescue LoadError
|
222
|
+
# do nothing
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
begin
|
227
|
+
# ActiveRecord
|
228
|
+
# Make sure we have a ActiveRecord library before creating this class,
|
229
|
+
# worst case we end up with a disk-based message store.
|
230
|
+
begin
|
231
|
+
require 'active_record'
|
232
|
+
require 'ap4r/reliable_msg_queue'
|
233
|
+
require 'ap4r/reliable_msg_topic'
|
234
|
+
rescue LoadError
|
235
|
+
require 'rubygems'
|
236
|
+
require 'activerecord'
|
237
|
+
require 'ap4r/reliable_msg_queue'
|
238
|
+
require 'ap4r/reliable_msg_topic'
|
239
|
+
end
|
240
|
+
|
241
|
+
class ActiveRecordStore < Base #:nodoc:
|
242
|
+
|
243
|
+
TYPE = "activerecord"
|
244
|
+
|
245
|
+
@@stores[TYPE] = self
|
246
|
+
|
247
|
+
# Default prefix for tables in the database.
|
248
|
+
DEFAULT_PREFIX = 'reliable_msg_';
|
249
|
+
|
250
|
+
# Reference to an open ActiveRecord connection held in the current thread.
|
251
|
+
THREAD_CURRENT_ACTIVE_RECORD = :reliable_msg_active_record #:nodoc:
|
252
|
+
|
253
|
+
|
254
|
+
def initialize config, logger
|
255
|
+
super logger
|
256
|
+
@config = { :adapter=>config['adapter'],
|
257
|
+
:host=>config['host'], :username=>config['username'], :password=>config['password'],
|
258
|
+
:database=>config['database'], :port=>config['port'], :socket=>config['socket'] }
|
259
|
+
@prefix = config['prefix'] || DEFAULT_PREFIX
|
260
|
+
@queues_table = "#{@prefix}queues"
|
261
|
+
@topics_table = "#{@prefix}topics"
|
262
|
+
establish_connection
|
263
|
+
end
|
264
|
+
|
265
|
+
|
266
|
+
def type
|
267
|
+
"#{TYPE} (#{@config[:adapter]})"
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
# Todo: implement calling migration logic. 2007/10/01 kiwamu
|
272
|
+
def setup
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
def configuration
|
277
|
+
config = { "type"=>TYPE, "adapter"=>@config[:adapter], "host"=>@config[:host],
|
278
|
+
"username"=>@config[:username], "password"=>@config[:password], "database"=>@config[:database] }
|
279
|
+
config["port"] = @config[:port] if @config[:port]
|
280
|
+
config["socket"] = @config[:socket] if @config[:socket]
|
281
|
+
config["prefix"] = @config[:prefix] if @config[:prefix]
|
282
|
+
config
|
283
|
+
end
|
284
|
+
|
285
|
+
|
286
|
+
def activate
|
287
|
+
super
|
288
|
+
load_index
|
289
|
+
end
|
290
|
+
|
291
|
+
|
292
|
+
def deactivate
|
293
|
+
Thread.list.each do |thread|
|
294
|
+
if conn = thread[THREAD_CURRENT_ACTIVE_RECORD]
|
295
|
+
thread[THREAD_CURRENT_ACTIVE_RECORD] = nil
|
296
|
+
conn.close
|
297
|
+
end
|
298
|
+
end
|
299
|
+
super
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
protected
|
304
|
+
|
305
|
+
def update inserts, deletes, dlqs
|
306
|
+
begin
|
307
|
+
inserts.each do |insert|
|
308
|
+
if insert[:queue]
|
309
|
+
::Ap4r::ReliableMsgQueue.new(
|
310
|
+
:message_id => insert[:id],
|
311
|
+
:queue => insert[:queue],
|
312
|
+
:headers => Marshal::dump(insert[:headers]),
|
313
|
+
:object => insert[:message]).save!
|
314
|
+
else
|
315
|
+
::Ap4r::ReliableMsgTopic.new(
|
316
|
+
:topic => insert[:topic],
|
317
|
+
:headers => Marshal::dump(insert[:headers]),
|
318
|
+
:object => insert[:message]).save!
|
319
|
+
end
|
320
|
+
end
|
321
|
+
ids = deletes.inject([]) do |array, delete|
|
322
|
+
delete[:queue] ? array << "#{delete[:id]}" : array
|
323
|
+
end
|
324
|
+
if !ids.empty?
|
325
|
+
# TODO: Use IN clause 2007/10/01 kiwamu
|
326
|
+
ids.each do |id|
|
327
|
+
::Ap4r::ReliableMsgQueue.delete_all(:message_id => id)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
dlqs.each do |dlq|
|
331
|
+
dlq_message = ::Ap4r::ReliableMsgQueue.find(:first, :conditions => { :message_id => dlq[:id] })
|
332
|
+
dlq_message.queue = Queue::DLQ
|
333
|
+
dlq_message.save!
|
334
|
+
end
|
335
|
+
rescue Exception=>error
|
336
|
+
raise error
|
337
|
+
end
|
338
|
+
super
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
def load_index
|
344
|
+
::Ap4r::ReliableMsgQueue.find(:all).each do |message|
|
345
|
+
queue = @queues[message[:queue]] ||= []
|
346
|
+
headers = Marshal::load(message[:headers])
|
347
|
+
# Add element based on priority, higher priority comes first.
|
348
|
+
priority = headers[:priority]
|
349
|
+
added = false
|
350
|
+
queue.each_index do |idx|
|
351
|
+
if queue[idx][:priority] < priority
|
352
|
+
queue[idx, 0] = headers
|
353
|
+
added = true
|
354
|
+
break
|
355
|
+
end
|
356
|
+
end
|
357
|
+
queue << headers unless added
|
358
|
+
end
|
359
|
+
|
360
|
+
::Ap4r::ReliableMsgTopic.find(:all).each do |message|
|
361
|
+
@topocs[message[:topic]] = Marshal::load(message[:headers])
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
|
366
|
+
def load id, type, queue_or_topic
|
367
|
+
object = nil
|
368
|
+
if type == :queue
|
369
|
+
message = ::Ap4r::ReliableMsgQueue.find(:first, :conditions => { :message_id => id })
|
370
|
+
object = message.object
|
371
|
+
else
|
372
|
+
message = ::Ap4r::ReliableMsgTopic.find(:first, :conditions => { :topic => queue_or_topic })
|
373
|
+
object = message.object
|
374
|
+
end
|
375
|
+
object
|
376
|
+
end
|
377
|
+
|
378
|
+
|
379
|
+
def establish_connection
|
380
|
+
ActiveRecord::Base.establish_connection(
|
381
|
+
:adapter => @config[:adapter],
|
382
|
+
:host => @config[:host],
|
383
|
+
:username => @config[:username],
|
384
|
+
:password => @config[:password],
|
385
|
+
:database => @config[:database]
|
386
|
+
)
|
387
|
+
end
|
388
|
+
|
389
|
+
end
|
203
390
|
|
204
391
|
rescue LoadError
|
205
392
|
# do nothing
|
206
393
|
end
|
207
394
|
|
395
|
+
|
396
|
+
class Memory < Base #:nodoc:
|
397
|
+
|
398
|
+
TYPE = self.name.split('::').last.downcase
|
399
|
+
|
400
|
+
@@stores[TYPE] = self
|
401
|
+
|
402
|
+
DEFAULT_CONFIG = {
|
403
|
+
"type"=>TYPE,
|
404
|
+
}
|
405
|
+
|
406
|
+
def initialize config, logger
|
407
|
+
super logger
|
408
|
+
# memory_map maps messages (by ID) to memory. The value is messege object.
|
409
|
+
@memory_map = {}
|
410
|
+
end
|
411
|
+
|
412
|
+
|
413
|
+
def type
|
414
|
+
TYPE
|
415
|
+
end
|
416
|
+
|
417
|
+
|
418
|
+
def setup
|
419
|
+
# do nothing
|
420
|
+
end
|
421
|
+
|
422
|
+
|
423
|
+
def configuration
|
424
|
+
{ "type"=>TYPE }
|
425
|
+
end
|
426
|
+
|
427
|
+
|
428
|
+
def activate
|
429
|
+
super
|
430
|
+
end
|
431
|
+
|
432
|
+
|
433
|
+
def deactivate
|
434
|
+
@memory_map = nil
|
435
|
+
super
|
436
|
+
end
|
437
|
+
|
438
|
+
|
439
|
+
protected
|
440
|
+
|
441
|
+
def update inserts, deletes, dlqs
|
442
|
+
inserts.each do |insert|
|
443
|
+
@mutex.synchronize do
|
444
|
+
@memory_map[insert[:id]] = insert[:message]
|
445
|
+
end
|
446
|
+
end
|
447
|
+
super
|
448
|
+
@mutex.synchronize do
|
449
|
+
deletes.each do |delete|
|
450
|
+
@memory_map.delete(delete[:id])
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
end
|
456
|
+
|
208
457
|
end
|
209
458
|
end
|
210
459
|
|
data/lib/ap4r/recipes.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
config = Capistrano::Configuration.respond_to?(:instance) ?
|
2
|
+
Capistrano::Configuration.instance(:must_exist) :
|
3
|
+
Capistrano.configuration(:must_exist)
|
4
|
+
|
5
|
+
config.load do
|
6
|
+
namespace :ap4r do
|
7
|
+
desc <<-DESC
|
8
|
+
Deploys your project. This calls both 'deploy:update' and 'ap4r:restart'.
|
9
|
+
Note that this will generally only work for applications that have
|
10
|
+
already been deployed once. For a "cold" deploy, you will want to take
|
11
|
+
a look at the 'ap4r:cold' task, which handles the cold start
|
12
|
+
specifically.
|
13
|
+
DESC
|
14
|
+
task :default do
|
15
|
+
update
|
16
|
+
restart
|
17
|
+
end
|
18
|
+
|
19
|
+
desc <<-DESC
|
20
|
+
Setups your project space. This make some shared directories (by 'deploy.update')
|
21
|
+
and additionallly make uuid.state in the shared/ direcotory.
|
22
|
+
DESC
|
23
|
+
task :setup do
|
24
|
+
deploy.setup
|
25
|
+
run <<-CMD
|
26
|
+
ruby -e 'require "rubygems"; require "uuid"; Dir.chdir("#{shared_path}"){UUID.new}' > /dev/null
|
27
|
+
CMD
|
28
|
+
end
|
29
|
+
|
30
|
+
desc <<-DESC
|
31
|
+
Deploys and starts a "cold" application. This is useful if you have not
|
32
|
+
deployed your application before, or if your application is (for some
|
33
|
+
other reason) not currently running. It will deploy the code, and
|
34
|
+
invoke 'ap4r:start' to fire up the AP4R servers.
|
35
|
+
DESC
|
36
|
+
task :cold do
|
37
|
+
update
|
38
|
+
start
|
39
|
+
end
|
40
|
+
|
41
|
+
desc <<-DESC
|
42
|
+
Start AP4R process on the ap4r server. This uses the :use_sudo variable
|
43
|
+
to determine whether to use sudo or not. By default, :use_sudo is
|
44
|
+
set to true.
|
45
|
+
DESC
|
46
|
+
task :start, :roles => :ap4r do
|
47
|
+
run_mongrel_ap4r("start", "-d -A #{ap4r_conf}")
|
48
|
+
end
|
49
|
+
|
50
|
+
desc <<-DESC
|
51
|
+
Restart the AP4R process on the ap4r server by starting and stopping the
|
52
|
+
AP4R. This uses the :use_sudo variable to determine whether to use sudo
|
53
|
+
or not. By default, :use_sudo is set to true.
|
54
|
+
DESC
|
55
|
+
task :restart, :roles => :ap4r do
|
56
|
+
stop
|
57
|
+
start
|
58
|
+
end
|
59
|
+
|
60
|
+
desc <<-DESC
|
61
|
+
Stop the AP4R process on the ap4r server. This uses the :use_sudo
|
62
|
+
variable to determine whether to use sudo or not. By default, :use_sudo is
|
63
|
+
set to true.
|
64
|
+
DESC
|
65
|
+
task :stop, :roles => :ap4r do
|
66
|
+
run_mongrel_ap4r("stop")
|
67
|
+
end
|
68
|
+
|
69
|
+
desc <<-DESC
|
70
|
+
Rolls back to a previous version and restarts.
|
71
|
+
DESC
|
72
|
+
task :rollback do
|
73
|
+
deploy.rollback_code
|
74
|
+
restart
|
75
|
+
end
|
76
|
+
|
77
|
+
desc <<-DESC
|
78
|
+
Updates your code from repository and makes symlinks for shared resourses.
|
79
|
+
DESC
|
80
|
+
task :update do
|
81
|
+
transaction do
|
82
|
+
deploy.update_code
|
83
|
+
deploy.symlink
|
84
|
+
|
85
|
+
finalize_update
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Makes some symlinks.
|
90
|
+
# One for the queues dir of disk message store.
|
91
|
+
# And one for the uuid.state file.
|
92
|
+
task :finalize_update do
|
93
|
+
require 'ap4r'
|
94
|
+
set_ap4r_conf
|
95
|
+
|
96
|
+
# TODO: This logic needs the config file at local to be synchronized to svn 2007/10/12 by shino
|
97
|
+
config = ReliableMsg::Config.new(ap4r_conf)
|
98
|
+
config.load_no_create
|
99
|
+
if config.store["type"] == "disk"
|
100
|
+
queue_path = config.store["path"] || ReliableMsg::Config::DEFAULT_STORE["path"]
|
101
|
+
latest_queue_path = "#{latest_release}/#{queue_path}"
|
102
|
+
shared_queue_path = "#{shared_path}/#{queue_path}"
|
103
|
+
# mkdir -p is making sure that the directories are there for some SCM's that don't
|
104
|
+
# save empty folders
|
105
|
+
run "umask 02 && mkdir -p #{shared_queue_path}/"
|
106
|
+
run <<-CMD
|
107
|
+
rm -rf #{latest_queue_path} &&
|
108
|
+
ln -s #{shared_queue_path} #{latest_queue_path} &&
|
109
|
+
ln -s #{shared_path}/uuid.state #{latest_release}/uuid.state
|
110
|
+
CMD
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def run_mongrel_ap4r(command, options="")
|
115
|
+
set_ap4r_conf
|
116
|
+
send(run_method, "ruby #{current_path}/script/mongrel_ap4r #{command} -c #{current_path} #{options}")
|
117
|
+
end
|
118
|
+
|
119
|
+
def set_ap4r_conf
|
120
|
+
set :ap4r_conf, "#{application}/config/queues.cfg" unless ap4r_conf
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
data/lib/ap4r/version.rb
CHANGED
@@ -86,12 +86,6 @@ module Ap4r
|
|
86
86
|
logger.debug(rm_options.inspect)
|
87
87
|
end
|
88
88
|
|
89
|
-
# TODO: clone it, 2006/10/16 shino
|
90
|
-
url_options ||= {}
|
91
|
-
url_options[:controller] ||= @controller.controller_path.gsub("/", ".")
|
92
|
-
url_options[:url] ||= {:controller => url_options[:controller], :action => url_options[:action]}
|
93
|
-
url_options[:url][:controller] ||= url_options[:controller] if url_options[:url].kind_of?(Hash)
|
94
|
-
|
95
89
|
rm_options = @@default_rm_options.merge(rm_options || {})
|
96
90
|
|
97
91
|
# Only async_params is not cloned. options and rm_options are cloned before now.
|
@@ -99,7 +93,7 @@ module Ap4r
|
|
99
93
|
converter = Converters[rm_options[:dispatch_mode]].new(url_options, async_params, rm_options, self)
|
100
94
|
logger.debug{"druby uri for queue-manager : #{DRUBY_URI}"}
|
101
95
|
|
102
|
-
queue_name =
|
96
|
+
queue_name = converter.queue_name
|
103
97
|
queue_message = converter.make_params
|
104
98
|
queue_headers = converter.make_rm_options
|
105
99
|
|
@@ -141,17 +135,6 @@ module Ap4r
|
|
141
135
|
q.put(queue_message, queue_headers)
|
142
136
|
end
|
143
137
|
|
144
|
-
def __get_queue_name(options, rm_options)
|
145
|
-
if options[:url].kind_of?(Hash)
|
146
|
-
rm_options[:queue] ||=
|
147
|
-
@@default_queue_prefix.clone.concat(options[:url][:controller].to_s).concat('.').concat(options[:url][:action].to_s)
|
148
|
-
else
|
149
|
-
rm_options[:queue] ||=
|
150
|
-
@@default_queue_prefix.clone.chomp(".").concat(URI::parse(options[:url]).path.gsub("/", "."))
|
151
|
-
end
|
152
|
-
rm_options[:queue]
|
153
|
-
end
|
154
|
-
|
155
138
|
end
|
156
139
|
|
157
140
|
module Converters #:nodoc:
|
@@ -176,6 +159,12 @@ module Ap4r
|
|
176
159
|
@url_for_handler = url_for_handler
|
177
160
|
end
|
178
161
|
|
162
|
+
# Returns a queue name to which a message will be queued.
|
163
|
+
# Should be implemented by subclasses.
|
164
|
+
def queue_name
|
165
|
+
raise 'must be implemented in subclasses'
|
166
|
+
end
|
167
|
+
|
179
168
|
# Returns a object which passed to <tt>ReliableMsg::Queue.put(message, headers)</tt>'s
|
180
169
|
# first argument +message+.
|
181
170
|
# Should be implemented by subclasses.
|
@@ -199,7 +188,35 @@ module Ap4r
|
|
199
188
|
|
200
189
|
end
|
201
190
|
|
202
|
-
class
|
191
|
+
class ToRailsBase < Base
|
192
|
+
def initialize(url_options, async_params, rm_options, url_for_handler)
|
193
|
+
super
|
194
|
+
|
195
|
+
@url_options ||= {}
|
196
|
+
@url_options[:controller] ||= @controller.controller_path.gsub("/", ".")
|
197
|
+
@url_options[:url] ||= {:controller => url_options[:controller], :action => url_options[:action]}
|
198
|
+
@url_options[:url][:controller] ||= url_options[:controller] if url_options[:url].kind_of?(Hash)
|
199
|
+
end
|
200
|
+
|
201
|
+
def queue_name
|
202
|
+
queue_name = @rm_options[:queue]
|
203
|
+
return queue_name if queue_name
|
204
|
+
|
205
|
+
queue_prefix = ::Ap4r::AsyncHelper::Base.default_queue_prefix
|
206
|
+
queue_prefix = queue_prefix.chomp(".")
|
207
|
+
url = @url_options[:url]
|
208
|
+
if url.kind_of?(Hash)
|
209
|
+
@rm_options[:queue] ||=
|
210
|
+
[queue_prefix, url[:controller].to_s, url[:action].to_s].join(".")
|
211
|
+
else
|
212
|
+
@rm_options[:queue] ||=
|
213
|
+
"#{queue_prefix}.#{URI.parse(url).path.gsub("/", ".")}"
|
214
|
+
end
|
215
|
+
@rm_options[:queue]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class Http < ToRailsBase
|
203
220
|
dispatch_mode :HTTP
|
204
221
|
|
205
222
|
def make_params
|
@@ -214,7 +231,7 @@ module Ap4r
|
|
214
231
|
end
|
215
232
|
end
|
216
233
|
|
217
|
-
class WebService <
|
234
|
+
class WebService < ToRailsBase
|
218
235
|
def make_params
|
219
236
|
message_obj = {}
|
220
237
|
@async_params.each_pair{|k,v| message_obj[k.to_sym]=v}
|
@@ -264,6 +281,45 @@ module Ap4r
|
|
264
281
|
end
|
265
282
|
end
|
266
283
|
|
284
|
+
class Druby < Base
|
285
|
+
OPTION_KEY = :receiver
|
286
|
+
dispatch_mode :druby
|
287
|
+
|
288
|
+
@@default_url = "druby://localhost:9999"
|
289
|
+
cattr_accessor :default_url
|
290
|
+
|
291
|
+
def initialize(url_options, async_params, rm_options, url_for_handler)
|
292
|
+
super
|
293
|
+
@url_options[:url] ||= @@default_url
|
294
|
+
end
|
295
|
+
|
296
|
+
def queue_name
|
297
|
+
queue_name = @rm_options[:queue]
|
298
|
+
return queue_name if queue_name
|
299
|
+
|
300
|
+
@rm_options[:queue] =
|
301
|
+
[AsyncHelper::Base.default_queue_prefix.chomp("."),
|
302
|
+
@url_options[OPTION_KEY].to_s || "druby",
|
303
|
+
@url_options[:message].to_s].join(".")
|
304
|
+
@rm_options[:queue]
|
305
|
+
end
|
306
|
+
|
307
|
+
def make_params
|
308
|
+
@async_params
|
309
|
+
end
|
310
|
+
|
311
|
+
def make_rm_options
|
312
|
+
@rm_options[:target_url] ||=
|
313
|
+
if @url_options[OPTION_KEY]
|
314
|
+
"#{@url_options[:url]}?#{@url_options[OPTION_KEY]}"
|
315
|
+
else
|
316
|
+
@url_options[:url]
|
317
|
+
end
|
318
|
+
@rm_options[:target_method] = @url_options[:message]
|
319
|
+
@rm_options
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
267
323
|
end
|
268
324
|
end
|
269
325
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ap4r
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.3.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.3.4
|
7
|
+
date: 2007-10-31 00:00:00 +09:00
|
8
8
|
summary: Asynchronous Processing for Ruby.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -39,11 +39,13 @@ files:
|
|
39
39
|
- config/ap4r_settings.rb
|
40
40
|
- config/log4r.yaml
|
41
41
|
- config/queues.cfg
|
42
|
+
- config/queues_ar.cfg
|
42
43
|
- config/queues_disk.cfg
|
43
44
|
- config/queues_mysql.cfg
|
44
45
|
- config/queues_pgsql.cfg
|
45
46
|
- lib/ap4r.rb
|
46
47
|
- lib/ap4r/carrier.rb
|
48
|
+
- lib/ap4r/db/migrate/001_reliable_msg_queue_and_topic.rb
|
47
49
|
- lib/ap4r/dispatcher.rb
|
48
50
|
- lib/ap4r/message_store_ext.rb
|
49
51
|
- lib/ap4r/mongrel.rb
|
@@ -52,6 +54,9 @@ files:
|
|
52
54
|
- lib/ap4r/postgresql.sql
|
53
55
|
- lib/ap4r/queue_manager_ext.rb
|
54
56
|
- lib/ap4r/queue_manager_ext_debug.rb
|
57
|
+
- lib/ap4r/recipes.rb
|
58
|
+
- lib/ap4r/reliable_msg_queue.rb
|
59
|
+
- lib/ap4r/reliable_msg_topic.rb
|
55
60
|
- lib/ap4r/retention_history.rb
|
56
61
|
- lib/ap4r/script/base.rb
|
57
62
|
- lib/ap4r/script/queue_manager_control.rb
|