ap4r 0.3.2 → 0.3.3

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.
@@ -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