ap4r 0.3.5 → 0.3.6
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 -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
|