ap4r 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -2
- data/Manifest.txt +4 -1
- data/Rakefile +88 -36
- data/lib/ap4r/carrier.rb +3 -2
- data/lib/ap4r/dispatcher.rb +8 -2
- data/{rails_plugin/ap4r/lib → lib/ap4r}/message_builder.rb +3 -2
- data/lib/ap4r/message_store_ext.rb +19 -19
- data/lib/ap4r/mongrel.rb +192 -1
- data/lib/ap4r/mongrel_ap4r.rb +2 -0
- data/lib/ap4r/queue_manager_ext.rb +11 -11
- data/lib/ap4r/retention_history.rb +6 -4
- data/lib/ap4r/stored_message.rb +2 -2
- data/lib/ap4r/util/queue_client.rb +4 -5
- data/lib/ap4r/version.rb +1 -1
- data/rails_plugin/ap4r/lib/async_helper.rb +1 -1
- data/rails_plugin/ap4r/tasks/ap4r.rake +9 -4
- data/spec/local/message_builder_spec.rb +200 -0
- data/spec/local/send_message_handler_spec.rb +109 -0
- data/spec/local/subscribe_message_handler_spec.rb +51 -0
- metadata +85 -72
data/lib/ap4r/mongrel_ap4r.rb
CHANGED
@@ -116,6 +116,8 @@ module Ap4r::Mongrel
|
|
116
116
|
listener do
|
117
117
|
log "Starting AP4R Handler with #{defaults[:ap4r_config_file]}"
|
118
118
|
uri "/", :handler => ::Ap4r::Mongrel::Ap4rHandler.new(defaults)
|
119
|
+
uri "/queues", :handler => ::Ap4r::Mongrel::Ap4rSendMessageHandler.new(defaults)
|
120
|
+
uri "/subscribes", :handler => ::Ap4r::Mongrel::Ap4rSubscribeMessageHandler.new(defaults)
|
119
121
|
end
|
120
122
|
setup_signals(settings)
|
121
123
|
end
|
@@ -6,7 +6,7 @@ require 'active_support'
|
|
6
6
|
require 'yaml'
|
7
7
|
require 'thread'
|
8
8
|
require 'pp'
|
9
|
-
|
9
|
+
require 'erb'
|
10
10
|
require 'uuid'
|
11
11
|
require 'reliable-msg'
|
12
12
|
|
@@ -19,21 +19,21 @@ require 'ap4r/carrier'
|
|
19
19
|
module ReliableMsg #:nodoc:
|
20
20
|
|
21
21
|
# = Dynamic configuration with ERb
|
22
|
-
#
|
23
|
-
# Some times you would like to inject dynamic values into your configuration file.
|
22
|
+
#
|
23
|
+
# Some times you would like to inject dynamic values into your configuration file.
|
24
24
|
# In these cases, you can mix ERb in with your YAML to code some logic, like:
|
25
|
-
#
|
25
|
+
#
|
26
26
|
# <% acl = [] %>
|
27
27
|
# <% for i in 1..100 %>
|
28
28
|
# <% acl << "192.168.0.#{i}" %>
|
29
|
-
# <% end %>
|
29
|
+
# <% end %>
|
30
30
|
# acl: <%= acl.map{|ip| "allow #{ip}"}.join(' ')
|
31
31
|
#
|
32
32
|
class Config
|
33
|
-
|
33
|
+
|
34
34
|
alias :load_no_create_original :load_no_create
|
35
35
|
alias :load_or_create_original :load_or_create
|
36
|
-
|
36
|
+
|
37
37
|
#--
|
38
38
|
# TODO: should enhance YAML.load_documents instead of this method?, 2007/5/7 kato-k
|
39
39
|
def load_no_create
|
@@ -47,7 +47,7 @@ module ReliableMsg #:nodoc:
|
|
47
47
|
true
|
48
48
|
end
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
#--
|
52
52
|
# TODO: should enhance YAML.load_documents instead of this method?, 2007/5/7 kato-k
|
53
53
|
def load_or_create
|
@@ -68,13 +68,13 @@ module ReliableMsg #:nodoc:
|
|
68
68
|
@logger.info format(INFO_CREATED_CONFIG, @file)
|
69
69
|
end
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
private
|
73
73
|
def erb_render(configuration_content)
|
74
|
-
ERB.new(configuration_content).result
|
74
|
+
::ERB.new(configuration_content).result
|
75
75
|
end
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
class QueueManager
|
79
79
|
|
80
80
|
# Gets a queue name which has the most stale message.
|
@@ -7,14 +7,16 @@ require 'active_support'
|
|
7
7
|
module ReliableMsg #:nodoc:
|
8
8
|
|
9
9
|
# This class is too much experimental.
|
10
|
-
# The aim: for performance monitoring, records unprocessed message count
|
10
|
+
# The aim: for performance monitoring, records unprocessed message count
|
11
11
|
# in every queues at some interval.
|
12
12
|
class RetentionHistory
|
13
13
|
include DRbUndumped
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
# to_i method is required for ActiveSupport 2.0 where return value of seconds method
|
16
|
+
# is not Fixnum.
|
17
|
+
LOOP_INTERVAL = 1.seconds.to_i
|
18
|
+
SHELF_LIFE = 10.minutes.to_i
|
19
|
+
# SHELF_LIFE = 10.seconds.to_i
|
18
20
|
attr_reader :data
|
19
21
|
|
20
22
|
def initialize(qm, logger, config)
|
data/lib/ap4r/stored_message.rb
CHANGED
@@ -31,7 +31,7 @@ module Ap4r
|
|
31
31
|
|
32
32
|
def dumped_headers
|
33
33
|
# The warning occurs when putting backslash into binaly type in PostgreSQL.
|
34
|
-
if postgresql?
|
34
|
+
if self.class.postgresql?
|
35
35
|
self.headers
|
36
36
|
else
|
37
37
|
Marshal::dump(self.headers)
|
@@ -40,7 +40,7 @@ module Ap4r
|
|
40
40
|
|
41
41
|
def dumped_object
|
42
42
|
# The warning occurs when putting backslash into binaly type in PostgreSQL.
|
43
|
-
if postgresql?
|
43
|
+
if self.class.postgresql?
|
44
44
|
self.object
|
45
45
|
else
|
46
46
|
Marshal::dump(self.object)
|
@@ -7,15 +7,14 @@ module Ap4r::Util #:nodoc:
|
|
7
7
|
#
|
8
8
|
# Client class for +QueueManager+.
|
9
9
|
# This class wraps DRb client and provides some helper methods.
|
10
|
-
# TODO: many drb calls are executed in a method call such as +list_queues+.
|
11
|
-
# ParseTree is perhaps needed.
|
12
|
-
# TODO: +Proc+ object cannnot be passed via DRb. ParseTree also?
|
10
|
+
# TODO: many drb calls are executed in a method call such as +list_queues+. 2006/09/22 by shino
|
11
|
+
# ParseTree is perhaps needed. Now ruby-parser is also available?
|
13
12
|
class QueueClient
|
14
13
|
CONFIG_DIR_DEFAULT = 'config'
|
15
14
|
CONFIG_FILE_DEFAULT = 'queues.cfg'
|
16
15
|
|
17
16
|
HOST_DEFAULT = 'localhost'
|
18
|
-
|
17
|
+
|
19
18
|
DEFAULT_QUEUE_PREFIX = 'queue.test.'
|
20
19
|
DEFAULT_QUEUE_SUFFIX = 'default'
|
21
20
|
DEFAULT_MULTI_QUEUE = DEFAULT_QUEUE_PREFIX + '*'
|
@@ -57,7 +56,7 @@ module Ap4r::Util #:nodoc:
|
|
57
56
|
def list_queues
|
58
57
|
qm.store.queues.keys
|
59
58
|
end
|
60
|
-
|
59
|
+
|
61
60
|
def list_messages(suffix = DEFAULT_QUEUE_SUFFIX,
|
62
61
|
prefix = DEFAULT_QUEUE_PREFIX)
|
63
62
|
qm.store.queues[prefix.to_s + suffix.to_s]
|
data/lib/ap4r/version.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + "/../lib/ap4r/service_handler.rb")
|
2
|
-
|
3
1
|
namespace :test do
|
4
2
|
|
5
3
|
# task :asyncs do
|
@@ -10,14 +8,14 @@ namespace :test do
|
|
10
8
|
namespace :asyncs do
|
11
9
|
|
12
10
|
desc "Start Rails and AP4R servers to test:asyncs:exec"
|
13
|
-
task :arrange do |t|
|
11
|
+
task :arrange => :require_dependencies do |t|
|
14
12
|
ap4r_handler = Ap4r::ServiceHandler.new
|
15
13
|
ap4r_handler.start_rails_service
|
16
14
|
ap4r_handler.start_ap4r_service
|
17
15
|
end
|
18
16
|
|
19
17
|
desc "Start Rails and AP4R servers to test:asyncs:exec"
|
20
|
-
task :cleanup do |t|
|
18
|
+
task :cleanup => :require_dependencies do |t|
|
21
19
|
ap4r_handler = Ap4r::ServiceHandler.new
|
22
20
|
ap4r_handler.stop_ap4r_service
|
23
21
|
ap4r_handler.stop_rails_service
|
@@ -30,6 +28,13 @@ namespace :test do
|
|
30
28
|
end
|
31
29
|
Rake::Task['test:asyncs:run'].comment = "Run the unit tests in test/async"
|
32
30
|
|
31
|
+
# service_handler.rb needs to require the following libraries.
|
32
|
+
# If reliable-msg's rails adapter is loaded before rails initialization,
|
33
|
+
# it may cause to uninitialization error because the adapter requires ActionController.
|
34
|
+
# So, the load of the following libraries is delayed with rake task.
|
35
|
+
task :require_dependencies do
|
36
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/ap4r/service_handler.rb")
|
37
|
+
end
|
33
38
|
end
|
34
39
|
|
35
40
|
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "../spec_helper")
|
2
|
+
require 'ap4r/message_builder'
|
3
|
+
# TODO: move message_builder.rb to lib directory below. 2008/01/18 kiwamu
|
4
|
+
# require File.join(File.dirname(__FILE__), "../../rails_plugin/ap4r/lib/message_builder")
|
5
|
+
|
6
|
+
describe "When simple API is used," do
|
7
|
+
|
8
|
+
describe Ap4r::MessageBuilder, " with an empty message" do
|
9
|
+
before(:all) do
|
10
|
+
empty_message = {}
|
11
|
+
@message_builder = Ap4r::MessageBuilder.new("queue_name", empty_message, {})
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have the right MIME header." do
|
15
|
+
pending("TODO: should modify implementation? 2008/01/18 kiwamu")
|
16
|
+
mime_type = @message_builder.message_headers["http_header_Content-type".to_sym]
|
17
|
+
mime_type.should == "application/x-www-form-urlencoded"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have the given message." do
|
21
|
+
@message_builder.message_body.should == {}
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return also a empty string body after format." do
|
25
|
+
@message_builder.format_message_body.should == ""
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe Ap4r::MessageBuilder, " with a simple message" do
|
31
|
+
before(:all) do
|
32
|
+
message = {:foo => "bar"}
|
33
|
+
@message_builder = Ap4r::MessageBuilder.new("queue_name", message, {})
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should have the right MIME header." do
|
37
|
+
pending("TODO: should modify implementation? 2008/01/18 kiwamu")
|
38
|
+
mime_type = @message_builder.message_headers["http_header_Content-type".to_sym]
|
39
|
+
mime_type.should == "application/x-www-form-urlencoded"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should have the given message." do
|
43
|
+
@message_builder.message_body.should == {:foo => "bar"}
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return the urlencoded body." do
|
47
|
+
@message_builder.format_message_body.should == "foo=bar"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
describe Ap4r::MessageBuilder, " with a nested complicated message" do
|
53
|
+
before(:all) do
|
54
|
+
@message = {:a => {:b => "c", :d => { :e => "f", :g => "h"}}, :i => "j"}
|
55
|
+
@message_builder = Ap4r::MessageBuilder.new("queue_name", @message, {})
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should have the given message." do
|
59
|
+
@message_builder.message_body.should == @message
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return the urlencoded body." do
|
63
|
+
query = @message_builder.format_message_body
|
64
|
+
query.split("&").sort.should == %w(a[b]=c a[d][e]=f a[d][g]=h i=j).sort
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
describe "When block style API is used, " do
|
73
|
+
|
74
|
+
describe Ap4r::MessageBuilder, " assigned unknown format" do
|
75
|
+
|
76
|
+
before(:all) do
|
77
|
+
|
78
|
+
block = Proc.new do
|
79
|
+
body :key1, "value"
|
80
|
+
body :key2, 1
|
81
|
+
format :unknown_format
|
82
|
+
end
|
83
|
+
|
84
|
+
@message_builder = Ap4r::MessageBuilder.new("", {}, {})
|
85
|
+
@message_builder.instance_eval(&block)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should have the right MIME header." do
|
89
|
+
pending("TODO: should modify implementation? 2008/01/24 kiwamu")
|
90
|
+
mime_type = @message_builder.message_headers["http_header_Content-type".to_sym]
|
91
|
+
mime_type.should == "application/x-www-form-urlencoded"
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should have the given message." do
|
95
|
+
@message_builder.message_body.should == {:key1 => "value", :key2 => 1}
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should return the urlencoded body." do
|
99
|
+
@message_builder.format_message_body.should == "key1=value&key2=1"
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
describe Ap4r::MessageBuilder, " assigned text format" do
|
105
|
+
|
106
|
+
before(:all) do
|
107
|
+
|
108
|
+
block = Proc.new do
|
109
|
+
body :key1, "value"
|
110
|
+
body :key2, 1
|
111
|
+
format :text
|
112
|
+
end
|
113
|
+
|
114
|
+
@message_builder = Ap4r::MessageBuilder.new("", {}, {})
|
115
|
+
@message_builder.instance_eval(&block)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should have the right MIME header." do
|
119
|
+
mime_type = @message_builder.message_headers["http_header_Content-type".to_sym]
|
120
|
+
mime_type.should == "text/plain"
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should return the to_s formatted body." do
|
124
|
+
@message_builder.format_message_body.should == {:key1 => "value", :key2 => 1}.to_s
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe Ap4r::MessageBuilder, " assigned xml format" do
|
129
|
+
|
130
|
+
before(:all) do
|
131
|
+
|
132
|
+
block = Proc.new do
|
133
|
+
body :key1, "value"
|
134
|
+
body :key2, 1
|
135
|
+
format :xml
|
136
|
+
end
|
137
|
+
|
138
|
+
@message_builder = Ap4r::MessageBuilder.new("", {}, {})
|
139
|
+
@message_builder.instance_eval(&block)
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should have the right MIME header." do
|
143
|
+
mime_type = @message_builder.message_headers["http_header_Content-type".to_sym]
|
144
|
+
mime_type.should == "application/xml"
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should return the xml formatted body." do
|
148
|
+
@message_builder.format_message_body.should == {:key1 => "value", :key2 => 1}.to_xml(:root => "root")
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe Ap4r::MessageBuilder, " assigned json format" do
|
153
|
+
|
154
|
+
before(:all) do
|
155
|
+
|
156
|
+
block = Proc.new do
|
157
|
+
body :key1, "value"
|
158
|
+
body :key2, 1
|
159
|
+
format :json
|
160
|
+
end
|
161
|
+
|
162
|
+
@message_builder = Ap4r::MessageBuilder.new("", {}, {})
|
163
|
+
@message_builder.instance_eval(&block)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should have the right MIME header." do
|
167
|
+
mime_type = @message_builder.message_headers["http_header_Content-type".to_sym]
|
168
|
+
mime_type.should == "application/json"
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should return the json formatted body." do
|
172
|
+
@message_builder.format_message_body.should == {:key1 => "value", :key2 => 1}.to_json
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe Ap4r::MessageBuilder, " assigned yaml format" do
|
177
|
+
|
178
|
+
before(:all) do
|
179
|
+
|
180
|
+
block = Proc.new do
|
181
|
+
body :key1, "value"
|
182
|
+
body :key2, 1
|
183
|
+
format :yaml
|
184
|
+
end
|
185
|
+
|
186
|
+
@message_builder = Ap4r::MessageBuilder.new("", {}, {})
|
187
|
+
@message_builder.instance_eval(&block)
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should have the right MIME header." do
|
191
|
+
mime_type = @message_builder.message_headers["http_header_Content-type".to_sym]
|
192
|
+
mime_type.should == "text/yaml"
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should return the yaml formatted body." do
|
196
|
+
@message_builder.format_message_body.should == {:key1 => "value", :key2 => 1}.to_yaml
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "../spec_helper")
|
2
|
+
|
3
|
+
require "reliable-msg"
|
4
|
+
require "ap4r/mongrel"
|
5
|
+
|
6
|
+
describe Ap4r::Mongrel::Ap4rSendMessageHandler, " on accepting a simple message" do
|
7
|
+
|
8
|
+
def start_queue_manager
|
9
|
+
@manager = ::ReliableMsg::QueueManager.new(:config => "config/queues_disk.cfg")
|
10
|
+
@manager.start_original
|
11
|
+
end
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
start_queue_manager
|
15
|
+
q = ::ReliableMsg::Queue.new "queue.test"
|
16
|
+
while q.get; end
|
17
|
+
|
18
|
+
params = {
|
19
|
+
Mongrel::Const::PATH_INFO => "/queue.test",
|
20
|
+
Mongrel::Const::REQUEST_METHOD => "POST",
|
21
|
+
}
|
22
|
+
class << params
|
23
|
+
def http_body
|
24
|
+
"hoge"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class MockSocket
|
29
|
+
def initialize;end
|
30
|
+
def closed?;false;end
|
31
|
+
end
|
32
|
+
|
33
|
+
@handler = Ap4r::Mongrel::Ap4rSendMessageHandler.new(nil)
|
34
|
+
@request = Mongrel::HttpRequest.new(params, nil, nil)
|
35
|
+
@response = Mongrel::HttpResponse.new(MockSocket.new)
|
36
|
+
@handler.process(@request, @response)
|
37
|
+
end
|
38
|
+
|
39
|
+
after(:each)do
|
40
|
+
@manager.stop_original
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should have one message in the queue" do
|
44
|
+
q = ReliableMsg::Queue.new "queue.test"
|
45
|
+
q.get.should_not be_nil
|
46
|
+
q.get.should be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should have the same message body as http body" do
|
50
|
+
q = ReliableMsg::Queue.new "queue.test"
|
51
|
+
q.get.object.should == "hoge"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe Ap4r::Mongrel::Ap4rSendMessageHandler, " on accepting a message with options" do
|
56
|
+
|
57
|
+
before(:each) do
|
58
|
+
@manager = ::ReliableMsg::QueueManager.new(:config => "config/queues_disk.cfg")
|
59
|
+
@manager.start_original
|
60
|
+
|
61
|
+
params = {
|
62
|
+
Mongrel::Const::PATH_INFO => "/queue.test",
|
63
|
+
Mongrel::Const::REQUEST_METHOD => "POST",
|
64
|
+
"HTTP_X_AP4R" => "priority=1, delivery=once, dispatch_mode=HTTP, target_method=POST, " +
|
65
|
+
"target_url=http://sample.com:3000"
|
66
|
+
}
|
67
|
+
class << params
|
68
|
+
def http_body
|
69
|
+
"hoge"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class MockSocket
|
74
|
+
def initialize;end
|
75
|
+
def closed?;false;end
|
76
|
+
end
|
77
|
+
|
78
|
+
@handler = Ap4r::Mongrel::Ap4rSendMessageHandler.new(nil)
|
79
|
+
@request = Mongrel::HttpRequest.new(params, nil, nil)
|
80
|
+
@response = Mongrel::HttpResponse.new(MockSocket.new)
|
81
|
+
@handler.process(@request, @response)
|
82
|
+
end
|
83
|
+
|
84
|
+
after(:each)do
|
85
|
+
@manager.stop_original
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should have one message in the queue" do
|
89
|
+
q = ReliableMsg::Queue.new "queue.test"
|
90
|
+
q.get.should_not be_nil
|
91
|
+
q.get.should be_nil
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should have the same message body as http body" do
|
95
|
+
q = ReliableMsg::Queue.new "queue.test"
|
96
|
+
q.get.object.should == "hoge"
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should have the same message header as http header" do
|
100
|
+
q = ReliableMsg::Queue.new "queue.test"
|
101
|
+
m = q.get
|
102
|
+
m.headers[:priority].should == 1
|
103
|
+
m.headers[:delivery].should == :once
|
104
|
+
m.headers[:dispatch_mode].should == :HTTP
|
105
|
+
m.headers[:target_method].should == :POST
|
106
|
+
m.headers[:target_url].should == "http://sample.com:3000"
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|