ap4r 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt 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