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 CHANGED
@@ -1,6 +1,13 @@
1
1
  == 0.3.x
2
2
 
3
- === 0.3.3 (June ?, 2007)
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
- HelloWorld = '../samples/HelloWorld'
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
- # copy rails plugin from sample before gem build
10
- FileUtils.mkdir_p('./rails_plugin/ap4r/lib')
11
- FileUtils.cp(HelloWorld + '/db/migrate/001_create_table_for_saf.rb', './lib/ap4r/xxx_create_table_for_saf.rb')
12
- FileUtils.cp_r(Dir.glob(HelloWorld + '/vendor/plugins/ap4r/*').reject{|f| f =~ /tmp$|CVS|\.svn/}, './rails_plugin/ap4r')
13
-
14
- Hoe.new('ap4r', Ap4r::VERSION::STRING) do |p|
15
- p.author = ["Shunichi Shinohara", "Kiwamu Kato"]
16
- p.changes = p.paragraphs_of('History.txt', 1..2).join("\n\n")
17
- #p.clean_globs =
18
- p.description = <<-EOF
19
- Asynchronous Processing for Ruby.
20
- EOF
21
- p.email = %q{shinohara.shunichi@future.co.jp, kato.kiwamu@future.co.jp}
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
- File.open('Manifest.txt', 'w') do |manifest|
55
- path_list.sort.each do |path|
56
- /.\// =~ path
57
- manifest.puts($~.post_match)
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
- # Sample release tasks ------------------------------------------------------
66
- desc 'Make samle tarball (Now only HelloWorld sample).'
67
- task :sample do
68
- FileUtils.mkdir_p('./pkg/samples')
69
- FileUtils.rm_rf('./pkg/samples/HelloWorld')
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
@@ -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
 
@@ -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
@@ -0,0 +1,4 @@
1
+ module Ap4r
2
+ class ReliableMsgQueue < ActiveRecord::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Ap4r
2
+ class ReliableMsgTopic < ActiveRecord::Base
3
+ end
4
+ end
data/lib/ap4r/version.rb CHANGED
@@ -8,7 +8,7 @@ module Ap4r
8
8
  module VERSION #:nodoc:
9
9
  MAJOR = 0
10
10
  MINOR = 3
11
- TINY = 3
11
+ TINY = 4
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY].join('.')
14
14
  end
@@ -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 = __get_queue_name(url_options, rm_options)
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 Http < Base
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 < Base
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
@@ -77,7 +77,7 @@ module Ap4r #:nodoc:
77
77
  when :text
78
78
  set_content_type("text/plain")
79
79
  when :xml
80
- set_content_type("text/xml application/x-xml")
80
+ set_content_type("application/xml")
81
81
  when :json
82
82
  set_content_type("application/json")
83
83
  when :yaml
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.3
7
- date: 2007-09-19 00:00:00 +09:00
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