ap4r 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,10 @@
1
1
  == 0.3.x
2
2
 
3
+ === 0.3.3 (June ?, 2007)
4
+ * Added: Support with hoe.
5
+ * Added: Support PostgreSQL as reliable RDBMS persistence.
6
+ * Added: Test supports, stub of queueing and service controls.
7
+
3
8
  === 0.3.2 (June 7th, 2007)
4
9
  * Fixed: util/loc.rb doesn't work.
5
10
  * Changed: Argument order of async_dispatch has changed, backward INCOMPATIBLE.
data/Manifest.txt ADDED
@@ -0,0 +1,48 @@
1
+ History.txt
2
+ MIT-LICENSE
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/ap4r_setup
7
+ config/ap4r_settings.rb
8
+ config/log4r.yaml
9
+ config/queues.cfg
10
+ config/queues_disk.cfg
11
+ config/queues_mysql.cfg
12
+ config/queues_pgsql.cfg
13
+ lib/ap4r.rb
14
+ lib/ap4r/carrier.rb
15
+ lib/ap4r/dispatcher.rb
16
+ lib/ap4r/message_store_ext.rb
17
+ lib/ap4r/mongrel.rb
18
+ lib/ap4r/mongrel_ap4r.rb
19
+ lib/ap4r/multi_queue.rb
20
+ lib/ap4r/postgresql.sql
21
+ lib/ap4r/queue_manager_ext.rb
22
+ lib/ap4r/queue_manager_ext_debug.rb
23
+ lib/ap4r/retention_history.rb
24
+ lib/ap4r/script/base.rb
25
+ lib/ap4r/script/queue_manager_control.rb
26
+ lib/ap4r/script/setup.rb
27
+ lib/ap4r/script/workspace_generator.rb
28
+ lib/ap4r/start_with_log4r.rb
29
+ lib/ap4r/store_and_forward.rb
30
+ lib/ap4r/stored_message.rb
31
+ lib/ap4r/util/irm.rb
32
+ lib/ap4r/util/queue_client.rb
33
+ lib/ap4r/version.rb
34
+ lib/ap4r/xxx_create_table_for_saf.rb
35
+ lib/ap4r/xxx_create_table_for_saf_to_postgresql.rb
36
+ rails_plugin/ap4r/init.rb
37
+ rails_plugin/ap4r/lib/ap4r/queue_put_stub.rb
38
+ rails_plugin/ap4r/lib/ap4r/service_handler.rb
39
+ rails_plugin/ap4r/lib/ap4r_client.rb
40
+ rails_plugin/ap4r/lib/async_helper.rb
41
+ rails_plugin/ap4r/lib/message_builder.rb
42
+ rails_plugin/ap4r/tasks/ap4r.rake
43
+ script/irm
44
+ script/mongrel_ap4r
45
+ script/start
46
+ script/stop
47
+ spec/local/dispatcher_base_spec.rb
48
+ spec/spec_helper.rb
data/README.txt ADDED
@@ -0,0 +1,82 @@
1
+ Ap4r
2
+ * by Kiwamu Kato, Shun'ichi Shinohara
3
+ * http://ap4r.rubyforge.org/wiki/wiki.pl?HomePage
4
+ * ap4r-user@rubyforge.org
5
+
6
+ == DESCRIPTION:
7
+
8
+ AP4R, Asynchronous Processing for Ruby, is the implementation of reliable asynchronous message processing. It provides message queuing, and message dispatching.
9
+ Using asynchronous processing, we can cut down turn-around-time of web applications by queuing, or can utilize more machine power by load-balancing.
10
+ Also AP4R nicely ties with your Ruby on Rails applications. See Hello World sample application from rubyforge.
11
+
12
+ For more information, please step in AP4R homepage!
13
+
14
+
15
+ == FEATURES / PROBLEMS TO SOLVE:
16
+
17
+ * Business logics can be implemented as simple Web applications, or ruby code, whether it's called asynchronously or synchronously.
18
+ * Asynchronous messaging is reliable by RDBMS persistence (now MySQL only) or file persistence, under the favor of reliable-msg.
19
+ * Load balancing over multiple AP4R processes on single/multiple servers is supported.
20
+ * Asynchronous logics are called via various protocols, such as XML-RPC, SOAP, HTTP POST, and more.
21
+ * Using store and forward function, at-least-once QoS level is provided.
22
+
23
+ == TYPICAL PROCESS FLOW:
24
+
25
+ 1. A client (e.g. a web browser) makes a request to a web server (Apache, Lighttpd, etc...).
26
+ 1. A rails application (a synchronous logic) is executed on mongrel via mod_proxy or something.
27
+ 1. At the last of the synchronous logic, message(s) are put to AP4R (AP4R provides a helper).
28
+ 1. Once the synchronous logic is done, the clients receives a response immediately.
29
+ 1. AP4R queues the message, and requests it to the web server asynchronously.
30
+ 1. An asynchronous logic, implemented as usual rails action, is executed.
31
+
32
+
33
+ == SYNOPSIS:
34
+
35
+ * FIX (code sample of usage)
36
+
37
+ == REQUIREMENTS:
38
+
39
+ * FIX (list of requirements)
40
+
41
+ == INSTALL:
42
+
43
+ Use RubyGems command.
44
+
45
+ $ sudo gem install ap4r --include-dependencies
46
+
47
+
48
+ == REFERENCES:
49
+
50
+ * Ruby Homepage
51
+ * http://www.ruby-lang.org/
52
+ * Ruby on Rails tutorial
53
+ * http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html
54
+ * MySQL tutorial
55
+ * http://dev.mysql.com/doc/refman/5.0/en/index.html
56
+ * reliable-msg
57
+ * http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/Ruby/ReliableMessaging
58
+
59
+
60
+ == LICENSE:
61
+
62
+ * This software is licensed under the MIT license.
63
+ * Copyright(c) 2007 Future Architect Inc.
64
+
65
+ Permission is hereby granted, free of charge, to any person obtaining
66
+ a copy of this software and associated documentation files (the
67
+ 'Software'), to deal in the Software without restriction, including
68
+ without limitation the rights to use, copy, modify, merge, publish,
69
+ distribute, sublicense, and/or sell copies of the Software, and to
70
+ permit persons to whom the Software is furnished to do so, subject to
71
+ the following conditions:
72
+
73
+ The above copyright notice and this permission notice shall be
74
+ included in all copies or substantial portions of the Software.
75
+
76
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
77
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
78
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
79
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
80
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
81
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
82
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,101 +1,87 @@
1
- # Author:: Kiwamu Kato
2
- # Copyright:: Copyright (c) 2007 Future Architect Inc.
3
- # Licence:: MIT Licence
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ require File.join(File.dirname(__FILE__), 'lib/ap4r', 'version')
4
4
 
5
- require 'rake'
6
- require 'rake/testtask'
7
- require 'rake/rdoctask'
8
- require 'rake/gempackagetask'
9
- require 'rake/contrib/rubyforgepublisher'
5
+ HelloWorld = '../samples/HelloWorld'
10
6
 
11
- require 'date'
12
- require 'find'
13
- require 'rbconfig'
7
+ # AP4R release tasks --------------------------------------------------------
14
8
 
15
- require File.join(File.dirname(__FILE__), 'lib/ap4r', 'version')
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')
16
13
 
17
- PKG_VERSION = Ap4r::VERSION::STRING
18
-
19
- TEMP_DIR = './temp'
20
- PKG_DIR = './pkg'
21
- RELEASE_DIR = './release'
22
- HELLO_WORLD_DIR = '../samples/HelloWorld'
23
-
24
- # Generate GEM ----------------------------------------------------------------------------
25
-
26
-
27
- PKG_FILES = FileList[
28
- '[a-zA-Z]*',
29
- 'bin/**/*',
30
- 'config/**/*',
31
- 'rails_plugin/**/*',
32
- 'script/**/*',
33
- 'lib/**/*'
34
- ]
35
-
36
- HELLO_WORLD_SAMPLE_FILES = FileList[
37
- '[a-zA-Z]*',
38
- 'app/**/*',
39
- 'components/**/*',
40
- 'config/**/*',
41
- 'db/**/*',
42
- 'doc/**/*',
43
- 'lib/**/*',
44
- 'log/**/*',
45
- 'public/**/*',
46
- 'script/**/*',
47
- 'test/**/*',
48
- 'tmp/**/*',
49
- 'vendor/**/*',
50
- ]
51
-
52
-
53
- spec = Gem::Specification.new do |s|
54
- s.name = 'ap4r'
55
- s.version = PKG_VERSION
56
- s.summary = "Asynchronous Processing for Ruby."
57
- s.description = <<-EOF
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
58
19
  Asynchronous Processing for Ruby.
59
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
52
+ end
60
53
 
61
- s.add_dependency(%q<reliable-msg>, ["= 1.1.0"])
62
- s.add_dependency(%q<rake>)
63
- s.add_dependency(%q<activesupport>)
64
- s.add_dependency(%q<mongrel>)
65
-
66
- s.has_rdoc = true
67
- s.extra_rdoc_files = ["README", "CHANGELOG", 'rails_plugin']
68
- s.rdoc_options << "--main" << "README"
69
- s.rdoc_options << "--title" << "Asynchronous Processing for Ruby"
70
- s.rdoc_options << "--line-numbers"
71
-
54
+ File.open('Manifest.txt', 'w') do |manifest|
55
+ path_list.sort.each do |path|
56
+ /.\// =~ path
57
+ manifest.puts($~.post_match)
58
+ end
59
+ end
60
+
61
+ end
72
62
 
73
- s.files = PKG_FILES.to_a.delete_if {|f| f.include?('.svn')}
74
- s.require_path = 'lib'
75
- s.autorequire = %q{ap4r.rb}
76
63
 
77
- s.bindir = "bin" # Use these for applications.
78
- s.executables = ["ap4r_setup"]
79
- s.default_executable = "ap4r_setup"
80
64
 
81
- s.authors = ["Shunichi Shinohara", "Kiwamu Kato"]
82
- s.email = %q{shinohara.shunichi@future.co.jp, kato.kiwamu@future.co.jp}
83
- s.homepage = %q{http://rubyforge.org/projects/ap4r/}
84
- s.rubyforge_project = "ap4r"
85
- end
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\~/
75
+ end
86
76
 
87
- Rake::GemPackageTask.new(spec) do |pkg|
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('../')
88
83
  end
89
84
 
90
- # Generate documentation ------------------------------------------------------------------
91
-
92
- Rake::RDocTask.new { |rdoc|
93
- rdoc.rdoc_dir = 'doc'
94
- rdoc.options << '--line-numbers' << '--inline-source' << '--accessor' << 'cattr_accessor=rw'
95
- rdoc.rdoc_files.include('README', 'CHANGELOG')
96
- rdoc.rdoc_files.include('lib/**/*.rb')
97
- rdoc.rdoc_files.include('rails_plugin/**/*.rb')
98
- }
99
85
 
100
86
  # Spec tasks ----------------------------------------------------------------
101
87
  require 'spec/rake/spectask'
@@ -123,70 +109,6 @@ namespace :spec do
123
109
  end
124
110
  end
125
111
 
126
- # AP4R release ----------------------------------------------------------------
127
-
128
- desc "Make gem"
129
- task :gem_release => [ :make_release_dir, :copy_to_ap4r_from_sample, :gem]
130
-
131
- task :copy_to_ap4r_from_sample do
132
- FileUtils.cp(HELLO_WORLD_DIR + '/db/migrate/001_create_table_for_saf.rb', './lib/ap4r/xxx_create_table_for_saf.rb')
133
-
134
- FileUtils.cp(HELLO_WORLD_DIR + '/vendor/plugins/ap4r/init.rb', './rails_plugin/ap4r/init.rb')
135
- FileUtils.cp(HELLO_WORLD_DIR + '/vendor/plugins/ap4r/lib/async_helper.rb', './rails_plugin/ap4r/lib/async_helper.rb')
136
- FileUtils.cp(HELLO_WORLD_DIR + '/vendor/plugins/ap4r/lib/ap4r_client.rb', './rails_plugin/ap4r/lib/ap4r_client.rb')
137
- FileUtils.cp(HELLO_WORLD_DIR + '/vendor/plugins/ap4r/lib/message_builder.rb', './rails_plugin/ap4r/lib/message_builder.rb')
138
- end
139
-
140
- desc "Make sample tgz"
141
- task :sample_release => [ :make_release_dir, :make_sample_tgz, :copy_to_release_dir ]
142
-
143
- task :make_sample_tgz => [ :make_temp_dir, :copy_sample, :execute_migration, :make_tgz ]
144
-
145
- task :make_release_dir do
146
- make_dir RELEASE_DIR
147
- end
148
-
149
- task :make_temp_dir do
150
- make_dir TEMP_DIR
151
- end
152
-
153
- def make_dir(path)
154
- if(File.exist?(path))
155
- FileUtils.remove_entry(path, true)
156
- end
157
- FileUtils.mkdir_p(path)
158
- end
159
-
160
-
161
- task :copy_sample do
162
- FileUtils.cp_r(HELLO_WORLD_DIR, TEMP_DIR)
163
- Find.find(TEMP_DIR) {|f|
164
- if f.include?('.svn')
165
- FileUtils.rm_rf(f)
166
- end
167
- }
168
- end
169
-
170
- task :execute_migration do
171
- Dir.chdir('temp/HelloWorld')
172
- `rake db:migrate`
173
- Dir.chdir('../../')
174
- end
175
-
176
- task :make_tgz do
177
- Dir.chdir('temp/')
178
- `tar czvf HelloWorld.tar.gz HelloWorld/`
179
- Dir.chdir('../')
180
- end
181
-
182
- task :copy_to_release_dir do
183
- Dir.foreach(PKG_DIR) {|f|
184
- FileUtils.cp(PKG_DIR + '/' + f, RELEASE_DIR) if File.fnmatch("*.gem", f)
185
- }
186
- Dir.foreach(TEMP_DIR) {|f|
187
- FileUtils.cp(TEMP_DIR + '/' + f, RELEASE_DIR) if File.fnmatch("*.tar.gz", f)
188
- }
189
- end
190
112
 
191
113
  # AP4R misc tools ----------------------------------------------------------------
192
114
 
@@ -8,7 +8,7 @@ store:
8
8
  drb:
9
9
  host:
10
10
  port: 6438
11
- acl: allow 127.0.0.1 allow 10.0.0.0/8
11
+ acl: allow 127.0.0.1 allow ::1 allow 10.0.0.0/8
12
12
  dispatchers:
13
13
  -
14
14
  targets: queue.*
@@ -16,4 +16,4 @@ dispatchers:
16
16
  #carriers:
17
17
  # -
18
18
  # source_uri: druby://another.host.local:6438
19
- # threads: 1
19
+ # threads: 1
@@ -0,0 +1,19 @@
1
+ ---
2
+ store:
3
+ type: postgresql
4
+ uri: # default is tcp://localhost:5432
5
+ database: ap4r
6
+ username: ap4r
7
+ password: ap4r
8
+ drb:
9
+ host:
10
+ port: 6438
11
+ acl: allow 127.0.0.1 allow ::1 allow 10.0.0.0/8
12
+ dispatchers:
13
+ -
14
+ targets: queue.*
15
+ threads: 1
16
+ #carriers:
17
+ # -
18
+ # source_uri: druby://another.host.local:6438
19
+ # threads: 1
data/lib/ap4r.rb CHANGED
@@ -3,7 +3,6 @@
3
3
  # Licence:: MIT Licence
4
4
 
5
5
  require 'rubygems'
6
- gem 'reliable-msg'
7
6
  require 'reliable-msg'
8
7
 
9
8
  hack = true
@@ -33,6 +33,236 @@ module ReliableMsg #:nodoc:
33
33
 
34
34
  end
35
35
 
36
+ begin
37
+
38
+ # Make sure we have a PostgreSQL library before creating this class,
39
+ # worst case we end up with a disk-based message store. Try the
40
+ # native PostgreSQL library, followed by the pure Ruby PostgreSQL library.
41
+ begin
42
+ require 'postgres'
43
+ rescue LoadError
44
+ require 'postgres-pr/connection'
45
+ end
46
+
47
+ require 'base64'
48
+
49
+ class PostgreSQL < Base #:nodoc:
50
+
51
+ TYPE = self.name.split('::').last.downcase
52
+
53
+ @@stores[TYPE] = self
54
+
55
+ # Default prefix for tables in the database.
56
+ DEFAULT_PREFIX = 'reliable_msg_';
57
+
58
+ # Reference to an open PostgreSQL connection held in the current thread.
59
+ THREAD_CURRENT_PGSQL = :reliable_msg_pgsql #:nodoc:
60
+
61
+ def initialize config, logger
62
+ super logger
63
+ @config = { :host=>config['host'], :username=>config['username'], :password=>config['password'],
64
+ :database=>config['database'], :port=>config['port'], :socket=>config['socket'] }
65
+ @prefix = config['prefix'] || DEFAULT_PREFIX
66
+ @queues_table = "#{@prefix}queues"
67
+ @topics_table = "#{@prefix}topics"
68
+ end
69
+
70
+ def type
71
+ TYPE
72
+ end
73
+
74
+ def setup
75
+ pgsql = connection
76
+ requires = 2 # Number of tables used by reliable-msg.
77
+ pgsql.query "\dt" do |result|
78
+ while row = result.fetch_row
79
+ requires -= 1 if row[0] == @queues_table || row[0] == @topics_table
80
+ end
81
+ end
82
+ if requires > 0
83
+ sql = File.open File.join(File.dirname(__FILE__), "postgresql.sql"), "r" do |input|
84
+ input.readlines.join
85
+ end
86
+ sql.gsub! DEFAULT_PREFIX, @prefix
87
+ pgsql.query sql
88
+ true
89
+ end
90
+ end
91
+
92
+
93
+ def configuration
94
+ config = { "type"=>TYPE, "host"=>@config[:host], "username"=>@config[:username],
95
+ "password"=>@config[:password], "database"=>@config[:database] }
96
+ config["port"] = @config[:port] if @config[:port]
97
+ config["socket"] = @config[:socket] if @config[:socket]
98
+ config["prefix"] = @config[:prefix] if @config[:prefix]
99
+ config
100
+ end
101
+
102
+
103
+ def activate
104
+ super
105
+ load_index
106
+ end
107
+
108
+
109
+ def deactivate
110
+ Thread.list.each do |thread|
111
+ if conn = thread[THREAD_CURRENT_PGSQL]
112
+ thread[THREAD_CURRENT_PGSQL] = nil
113
+ conn.close
114
+ end
115
+ end
116
+ super
117
+ end
118
+
119
+
120
+ protected
121
+
122
+ def update inserts, deletes, dlqs
123
+ pgsql = connection
124
+ pgsql.query "BEGIN"
125
+ begin
126
+ inserts.each do |insert|
127
+ if insert[:queue]
128
+ pgsql.query "INSERT INTO #{@queues_table} (id,queue,headers,object) VALUES('#{connection.quote insert[:id]}', '#{connection.quote insert[:queue]}', '#{connection.quote YAML.dump(insert[:headers])}', '#{connection.quote Base64.encode64(insert[:message])}')"
129
+ else
130
+ pgsql.query "REPLACE #{@topics_table} (topic,headers,object) VALUES('#{connection.quote insert[:topic]}','#{connection.quote YAML.dump(insert[:headers])}','#{connection.quote insert[:message]}')"
131
+ end
132
+ end
133
+ ids = deletes.inject([]) do |array, delete|
134
+ delete[:queue] ? array << "'#{delete[:id]}'" : array
135
+ end
136
+ if !ids.empty?
137
+ pgsql.query "DELETE FROM #{@queues_table} WHERE id IN (#{ids.join ','})"
138
+ end
139
+ dlqs.each do |dlq|
140
+ pgsql.query "UPDATE #{@queues_table} SET queue='#{Queue::DLQ}' WHERE id='#{connection.quote dlq[:id]}'"
141
+ end
142
+ pgsql.query "COMMIT"
143
+ rescue Exception=>error
144
+ pgsql.query "ROLLBACK"
145
+ raise error
146
+ end
147
+ super
148
+ end
149
+
150
+
151
+ def load_index
152
+ connection.query "SELECT id,queue,headers FROM #{@queues_table}" do |result|
153
+ result.each do |tuple|
154
+ queue = @queues[tuple[1]] ||= []
155
+ headers = YAML.load tuple[2]
156
+ # Add element based on priority, higher priority comes first.
157
+ priority = headers[:priority]
158
+ added = false
159
+ queue.each_index do |idx|
160
+ if queue[idx][:priority] < priority
161
+ queue[idx, 0] = headers
162
+ added = true
163
+ break
164
+ end
165
+ end
166
+ queue << headers unless added
167
+ end
168
+ end
169
+ connection.query "SELECT topic,headers FROM #{@topics_table}" do |result|
170
+ result.each do |tuple|
171
+ @topics[tuple[0]] = YAML.load tuple[1]
172
+ end
173
+ end
174
+ end
175
+
176
+
177
+ def load id, type, queue_or_topic
178
+ message = nil
179
+ if type == :queue
180
+ connection.query "SELECT object FROM #{@queues_table} WHERE id='#{id}'" do |result|
181
+ message = Base64.decode64(result[0][0]) if result[0]
182
+ end
183
+ else
184
+ connection.query "SELECT object FROM #{@topics_table} WHERE topic='#{queue_or_topic}'" do |result|
185
+ message = Base64.decode64(result[0][0]) if result[0]
186
+ end
187
+ end
188
+ message
189
+ end
190
+
191
+ def connection
192
+ Thread.current[THREAD_CURRENT_PGSQL] ||=
193
+ # PGconn is overriding in this file, so is defined regardless of 'postgres' LoadError.
194
+ if Object.const_defined? :PGError
195
+ ::PGconn.connect @config[:host], @config[:port], @config[:options], @config[:tty], @config[:database], @config[:username], @config[:password]
196
+ elsif Object.const_defined? :PostgresPR
197
+ ::PostgresPR::Connection.new @config[:database], @config[:username], @config[:password], @config[:uri]
198
+ end
199
+
200
+ end
201
+
202
+ end
203
+
204
+ rescue LoadError
205
+ # do nothing
206
+ end
207
+
208
+ end
209
+ end
210
+
211
+ if Object.const_defined? :PGError
212
+ class PGconn
213
+ alias original_query query
214
+
215
+ def query(q, *bind_values, &block)
216
+ # In PGconn, +query+ method does NOT care about a given block.
217
+ # To deal with a given block, this method adds iteration
218
+ # over query results.
219
+ maybe_result = exec(q, *bind_values)
220
+ puts "PGconn: query called by #{q}" if $DEBUG
221
+ puts "PGconn#query returns #{maybe_result}(class: #{maybe_result.class})." if $DEBUG
222
+ return maybe_result unless block && maybe_result.kind_of?(PGresult)
223
+ begin
224
+ puts "PGconn extention: about to yield result." if $DEBUG
225
+ block.call(maybe_result)
226
+ ensure
227
+ maybe_result.clear
228
+ end
229
+ end
230
+
231
+ def quote str
232
+ # do nothing
233
+ str
234
+ end
235
+
236
+ end
237
+ end
238
+
239
+ if Object.const_defined? :PostgresPR
240
+ module PostgresPR
241
+ class Connection
242
+ alias original_query query
243
+
244
+ def query(q, &block)
245
+ # In PostgresPR, +query+ method does NOT care about a given block.
246
+ # To deal with a given block, this method adds iteration
247
+ # over query results.
248
+ maybe_result = original_query(q, &block)
249
+ puts "PostgresPR: query called by #{q}" if $DEBUG
250
+ puts "PostgresPR::Connenction#query returns #{maybe_result}(class: #{maybe_result.class})." if $DEBUG
251
+ return maybe_result.rows unless block && maybe_result.kind_of?(PostgresPR::Connection::Result)
252
+ begin
253
+ puts "PostgresPR extention: about to yield result." if $DEBUG
254
+ block.call(maybe_result.rows)
255
+ ensure
256
+ maybe_result = nil
257
+ end
258
+ end
259
+
260
+ def quote(str)
261
+ # do nothing
262
+ str
263
+ end
264
+
265
+ end
36
266
  end
37
267
  end
38
268