ap4r 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|