ap4r 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,8 @@ require 'rubygems'
6
6
  require 'mongrel'
7
7
  require 'ap4r/mongrel'
8
8
 
9
+ Mongrel::Command::BANNER.gsub!("rails", "ap4r")
10
+
9
11
  module Ap4r::Mongrel
10
12
 
11
13
  module Command
@@ -17,6 +19,8 @@ module Ap4r::Mongrel
17
19
  klass.class_eval do |k|
18
20
  include(::Mongrel::Command::Base)
19
21
  end
22
+
23
+
20
24
  # TODO: Can subclass the return of RubyGems::GemPlugin ? 2007/04/16 by shino
21
25
  end
22
26
 
@@ -0,0 +1,13 @@
1
+ CREATE TABLE reliable_msg_queues (
2
+ id character varying(255) NOT NULL default '',
3
+ queue character varying(255) NOT NULL default '',
4
+ headers text NOT NULL,
5
+ object text NOT NULL,
6
+ PRIMARY KEY (id)
7
+ );
8
+ CREATE TABLE reliable_msg_topics (
9
+ topic character varying(255) NOT NULL default '',
10
+ headers text NOT NULL,
11
+ object text NOT NULL,
12
+ PRIMARY KEY (topic)
13
+ );
@@ -12,8 +12,8 @@ module ReliableMsg #:nodoc:
12
12
  class RetentionHistory
13
13
  include DRbUndumped
14
14
 
15
- LOOP_INTERVAL = 3.seconds
16
- SHELF_LIFE = 1.hour
15
+ LOOP_INTERVAL = 1.seconds
16
+ SHELF_LIFE = 10.minutes
17
17
  # SHELF_LIFE = 10.seconds
18
18
  attr_reader :data
19
19
 
@@ -9,7 +9,6 @@ begin
9
9
  require 'active_support'
10
10
  rescue LoadError
11
11
  require 'rubygems'
12
- gem 'active_support'
13
12
  require 'active_support'
14
13
  end
15
14
 
@@ -5,12 +5,12 @@
5
5
  begin
6
6
  require 'active_record'
7
7
  require 'uuid'
8
+ require 'reliable-msg'
8
9
  rescue LoadError
9
10
  require 'rubygems'
10
- gem 'activerecord'
11
11
  require 'activerecord'
12
- gem 'uuid'
13
12
  require 'uuid'
13
+ require 'reliable-msg'
14
14
  end
15
15
 
16
16
  module Ap4r
@@ -23,11 +23,30 @@ module Ap4r
23
23
 
24
24
  STATUS_STORED = 0
25
25
  STATUS_FORWARDED = 1
26
- STATUS_FAILED = -1
27
-
26
+ @@status_value_of = { :unforwarded => STATUS_STORED,
27
+ :forwarded => STATUS_FORWARDED }
28
+
28
29
  PHYSICAL = :physical
29
30
  LOGICAL = :logical
30
-
31
+
32
+ def dumped_headers
33
+ # The warning occurs when putting backslash into binaly type in PostgreSQL.
34
+ if "postgresql" == Ap4r::StoredMessage.establish_connection.config[:adapter]
35
+ self.headers
36
+ else
37
+ Marshal::dump(self.headers)
38
+ end
39
+ end
40
+
41
+ def dumped_object
42
+ # The warning occurs when putting backslash into binaly type in PostgreSQL.
43
+ if "postgresql" == Ap4r::StoredMessage.establish_connection.config[:adapter]
44
+ self.object
45
+ else
46
+ Marshal::dump(self.object)
47
+ end
48
+ end
49
+
31
50
  # Insert queue information, such as queue name and message, for next logic.
32
51
  #
33
52
  # duplication_check_id is generated from UUID and should be unique
@@ -42,8 +61,15 @@ module Ap4r
42
61
  s.duplication_check_id = UUID.new
43
62
  s.queue = queue_name
44
63
  s.status = STATUS_STORED
45
- s.object = Marshal::dump(queue_message)
46
- s.headers = Marshal::dump(rm_options)
64
+
65
+ # The warning occurs when putting backslash into binaly type in PostgreSQL.
66
+ if "postgresql" == Ap4r::StoredMessage.establish_connection.config[:adapter]
67
+ s.object = YAML.dump(queue_message)
68
+ s.headers = YAML.dump(rm_options)
69
+ else
70
+ s.object = Marshal::dump(queue_message)
71
+ s.headers = Marshal::dump(rm_options)
72
+ end
47
73
  end
48
74
 
49
75
  begin
@@ -86,5 +112,92 @@ module Ap4r
86
112
  self
87
113
  end
88
114
 
115
+ # List the records which have specified status.
116
+ # The statuses are :forwarded, :unforwarded and :all.
117
+ # :unforwarded means unprocessed or error during forward process.
118
+ def self.find_status_of(status = :unforwarded)
119
+ case status
120
+ when :all
121
+ StoredMessage.find(:all)
122
+ when :forwarded, :unforwarded
123
+ StoredMessage.find(:all, :conditions => { :status => @@status_value_of[status] })
124
+ else
125
+ puts "Undefined status: #{status.to_s}."
126
+ puts "Usage: Ap4r::StoredMessage.find_on [ :forwarded | :unforwarded | :all ]"
127
+ end
128
+ end
129
+
130
+ # Return id, queue_name and created date time.
131
+ def to_summary_string
132
+ return "#{self.id}, #{self.queue}, #{self.created_at}"
133
+ end
134
+
135
+ # Update status value.
136
+ def self.update_status(id, status)
137
+ return "undefined status: #{status}" unless @@status_value_of.keys.include? status
138
+ stored_message = StoredMessage.find(id)
139
+
140
+ before_status = stored_message.status
141
+ after_status = @@status_value_of[status]
142
+
143
+ stored_message.status = after_status
144
+ stored_message.save!
145
+ end
146
+
147
+ # Try to forward the ONE message which status is unforwarded.
148
+ # If the message is forwarded successfully, the status will be "1" that means forwarded.
149
+ def self.reforward(id)
150
+ stored_message = StoredMessage.find(id)
151
+ if stored_message.status == @@status_value_of[:forwarded]
152
+ raise "The message (id = #{id}) was already forwarded."
153
+ end
154
+ stored_message.forward_and_update_status
155
+ end
156
+
157
+ # Try to forward all messages which status are unforwarded.
158
+ # This method issue commit command to database every transaction_num.
159
+ def self.reforward_all(transaction_num = 10)
160
+
161
+ stored_messages = StoredMessage.find(:all,
162
+ :conditions => {:status => @@status_value_of[:unforwarded]})
163
+ total_num = stored_messages.size
164
+ failed_num = 0
165
+
166
+ 0.step(total_num, transaction_num) do |offset|
167
+ target_sms = stored_messages[offset..(offset + transaction_num - 1)]
168
+ next if target_sms.empty?
169
+ begin
170
+ StoredMessage.transaction do
171
+ target_sms.each do |target_sm|
172
+ target_sm.forward_and_update_status
173
+ end
174
+ end
175
+ rescue Exception => error
176
+ puts error.message
177
+ failed_num += target_sms.size
178
+ end
179
+ end
180
+ return [total_num - failed_num, failed_num]
181
+ end
182
+
183
+ def forward_and_update_status
184
+ queue_name = self.queue
185
+
186
+ # The warning occurs when putting backslash into binaly type in PostgreSQL.
187
+ if "postgresql" == Ap4r::StoredMessage.establish_connection.config[:adapter]
188
+ queue_headers = YAML.load(self.headers)
189
+ queue_messages = YAML.load(self.object)
190
+ else
191
+ queue_headers = Marshal::load(self.headers)
192
+ queue_messages = Marshal::load(self.object)
193
+ end
194
+
195
+ q = ::ReliableMsg::Queue.new(queue_name, :drb_uri => Ap4r::AsyncHelper::Base::DRUBY_URI)
196
+ q.put(queue_messages, queue_headers)
197
+
198
+ self.status = STATUS_FORWARDED
199
+ self.save!
200
+ end
201
+
89
202
  end
90
203
  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 = 2
11
+ TINY = 3
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY].join('.')
14
14
  end
@@ -0,0 +1,21 @@
1
+ # Author:: Kiwamu Kato
2
+ # Copyright:: Copyright (c) 2006 Future System Consulting Corp.
3
+ # Licence:: MIT Licence
4
+
5
+ class CreateTableForSaf < ActiveRecord::Migration
6
+ def self.up
7
+ create_table :stored_messages do |t|
8
+ t.column :duplication_check_id, :string, :null => false
9
+ t.column :queue, :string, :null => false
10
+ t.column :headers, :binary, :null => false
11
+ t.column :object, :binary, :null => false
12
+ t.column :status, :integer, :null => false
13
+ t.column :created_at, :datetime, :null => false
14
+ t.column :updated_at, :datetime, :null => false
15
+ end
16
+ end
17
+
18
+ def self.down
19
+ drop_table :stored_messages
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # Author:: Kiwamu Kato
2
+ # Copyright:: Copyright (c) 2006 Future System Consulting Corp.
3
+ # Licence:: MIT Licence
4
+
5
+ class CreateTableForSaf < ActiveRecord::Migration
6
+ def self.up
7
+ create_table :stored_messages do |t|
8
+ t.column :duplication_check_id, :string, :null => false
9
+ t.column :queue, :string, :null => false
10
+ t.column :headers, :text, :null => false
11
+ t.column :object, :text, :null => false
12
+ t.column :status, :integer, :null => false
13
+ t.column :created_at, :datetime, :null => false
14
+ t.column :updated_at, :datetime, :null => false
15
+ end
16
+ end
17
+
18
+ def self.down
19
+ drop_table :stored_messages
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ # Author:: Shunichi Shinohara
2
+ # Copyright:: Copyright (c) 2007 Future Architect Inc.
3
+ # Licence:: MIT Licence
4
+
5
+ require 'ap4r_client'
6
+
7
+ class ActionController::Base
8
+ def ap4r
9
+ @ap4r_client ||= ::Ap4r::Client.new(self)
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ # Author:: Shunichi Shinohara
2
+ # Copyright:: Copyright (c) 2007 Future Architect Inc.
3
+ # Licence:: MIT Licence
4
+
5
+ module Ap4r
6
+ module AsyncHelper
7
+ module Base
8
+ def queued_messages
9
+ return @queued_messages if @queued_messages
10
+ @queued_messages = Hash.new {|hash, key| hash[key] = []}
11
+ return @queued_messages
12
+ end
13
+
14
+ private
15
+ def __queue_put(queue_name, message, headers)
16
+ queued_messages[queue_name] << {:headers => headers, :body => message}
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,165 @@
1
+ # Author:: Shunichi Shinohara
2
+ # Copyright:: Copyright (c) 2007 Future Architect Inc.
3
+ # Licence:: MIT Licence
4
+
5
+ require 'rubygems'
6
+ require 'erb'
7
+ require 'yaml'
8
+ require 'reliable-msg'
9
+ require 'ap4r'
10
+ require 'timeout'
11
+
12
+ module Ap4r
13
+
14
+ class ServiceHandler
15
+
16
+ def initialize(config_file = RAILS_ROOT + "/config/test_async.yml")
17
+ raise "please create config/test_async.yml to configure ap4r service." unless File.exist?(config_file)
18
+
19
+ config = {}
20
+ File.open(config_file, "r") do |input|
21
+ YAML.load_documents(ERB.new(input.read).result) do |doc|
22
+ config.merge! doc
23
+ end
24
+ end
25
+ @test_config = config["ap4r"]
26
+ @root_dir = @test_config["root_dir"]
27
+ @config_file = @test_config["config_file"]
28
+ @test_server_config = ReliableMsg::Config.new(File.join(@root_dir, @config_file))
29
+ raise "config file #{@test_server_config.path} NOT exist!" unless @test_server_config.exist?
30
+
31
+ @test_server_config.load_no_create
32
+ @qm = nil
33
+ end
34
+
35
+ def qm
36
+ @qm ||= DRbObject.new_with_uri("druby://localhost:#{@test_server_config.drb["port"]}")
37
+ end
38
+
39
+ # Starts ap4r service.
40
+ def start_ap4r_service(wait_until_started = true)
41
+ command = "ruby #{@test_config["start_ruby_args"]} #{@root_dir}/script/mongrel_ap4r " +
42
+ "start -d -c #{@root_dir} -A #{@config_file} -p 13038"
43
+ message = "Starting Mongrel(AP4R)"
44
+ execute_command(command, message, false)
45
+ if wait_until_started
46
+ print "and waiting..."
47
+ wait_until_alive
48
+ end
49
+ puts "Done."
50
+ end
51
+
52
+ # Stops ap4r service.
53
+ def stop_ap4r_service
54
+ command = "ruby #{@test_config["stop_ruby_args"]} #{@root_dir}/script/mongrel_ap4r " +
55
+ "stop -c #{@root_dir}"
56
+ message = "Terminating Mongrel(AP4R)"
57
+ execute_command(command, message, false)
58
+ @qm = nil
59
+ end
60
+
61
+ # Starts rails service.
62
+ # Invokes mongrel_rails, so mongrel_rails should be installed.
63
+ def start_rails_service
64
+ # TODO: Can use script/server? It's more general. 2007/05/31 by shino
65
+ command = "mongrel_rails start -d --environment test"
66
+ message = "Starting Mongrel(Rails)"
67
+ execute_command(command, message)
68
+ end
69
+
70
+ # Stops rails service.
71
+ def stop_rails_service
72
+ # puts "read pid"
73
+ # pid = File.read('log/mongrel.pid').to_i
74
+ # puts "send signal to #{pid}"
75
+ # Process.kill(:TERM, `cat log/mongrel.pid`.to_i)
76
+ # puts "done"
77
+ # return
78
+ command = "mongrel_rails stop"
79
+ # command = "kill " + `cat log/mongrel.pid`
80
+ # command = "sh -c 'mongrel_rails stop'"
81
+ message = "Terminating Mongrel(Rails)"
82
+ execute_command(command, message, false)
83
+ end
84
+
85
+ # Starts rails service and ap4r service.
86
+ # After block execution, stops both.
87
+ def with_services
88
+ begin
89
+ start_rails_service
90
+ begin
91
+ start_ap4r_service
92
+ yield
93
+ ensure
94
+ stop_ap4r_service
95
+ end
96
+ ensure
97
+ stop_rails_service
98
+ end
99
+ end
100
+
101
+ def start_dispatchers
102
+ qm.dispatchers.start
103
+ end
104
+
105
+ def stop_dispatchers
106
+ qm.dispatchers.stop
107
+ end
108
+
109
+ def clear(*queues)
110
+ raise "not yet implemented"
111
+ queues.each do |queue|
112
+ q = ReliableMsg::Queue.new(queue)
113
+ loop do
114
+ break unless q.get
115
+ end
116
+ end
117
+ end
118
+
119
+ def wait_for_saf_forward
120
+ 50.times do
121
+ count = ::Ap4r::StoredMessage.count(:conditions => {:status => ::Ap4r::StoredMessage::STATUS_STORED})
122
+ break if count == 0
123
+ sleep 0.2
124
+ end
125
+ end
126
+
127
+ def wait_all_done
128
+ 50.times do
129
+ break if flag = qm.no_active_message?
130
+ sleep 0.2
131
+ end
132
+ end
133
+
134
+ def dlq
135
+ qm.list :queue => "$dlq"
136
+ end
137
+
138
+ private
139
+ def execute_command(command, message, with_done_message = true)
140
+ command += ";" # force to execute via shell
141
+ print "#{message} with command: #{command}..."
142
+ begin
143
+ timeout(10) do
144
+ result = system("#{command}")
145
+ # TODO: handle result 2007/08/29 by shino
146
+ puts "Done." if with_done_message
147
+ end
148
+ rescue TimeoutError
149
+ puts "!!! command timed out !!!"
150
+ end
151
+ end
152
+
153
+ def wait_until_alive(message = nil)
154
+ 50.times do
155
+ print message if message
156
+ begin
157
+ break if qm.alive?
158
+ rescue => e
159
+ # ignore
160
+ end
161
+ sleep 0.2
162
+ end
163
+ end
164
+ end
165
+ end