em-pg-client 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,125 @@
1
+ $:.unshift "lib"
2
+ gem 'eventmachine', '~> 1.0.0'
3
+ gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
4
+ require 'date'
5
+ require 'eventmachine'
6
+ require 'pg/em'
7
+
8
+ describe PG::EM::FeaturedDeferrable do
9
+ subject { PG::EM::FeaturedDeferrable }
10
+ let(:df) { subject.new }
11
+ let(:cb) { Proc.new {} }
12
+ let(:error) { RuntimeError.new }
13
+ let(:pg_error) {
14
+ PG::Error.new.tap do |err|
15
+ err.instance_variable_set :@connection, :connection
16
+ err.instance_variable_set :@result, :result
17
+ end
18
+ }
19
+
20
+ it "should set callback with a block " do
21
+ cb.should_receive(:call).with(:result)
22
+ df = subject.new(&cb)
23
+ df.succeed(:result)
24
+ end
25
+
26
+ it "should set errback with a block" do
27
+ cb.should_receive(:call).with(:err)
28
+ df = subject.new(&cb)
29
+ df.fail(:err)
30
+ end
31
+
32
+ it "should execute callbacks and errbacks in setup order" do
33
+ results = []
34
+ setup_callbacks = proc do |df|
35
+ df.callback { results << 1 }
36
+ df.callback { results << 2 }
37
+ df.callback { results << 3 }
38
+ df.errback { results << 4 }
39
+ df.errback { results << 5 }
40
+ df.errback { results << 6 }
41
+ end
42
+ df = subject.new
43
+ setup_callbacks.call df
44
+ df.succeed
45
+ df.fail
46
+ df = subject.new
47
+ setup_callbacks.call df
48
+ df.fail
49
+ df.succeed
50
+ results.should eq [1, 2, 3, 4, 5, 6]
51
+ end
52
+
53
+ it "should set completion with block" do
54
+ cb.should_receive(:call).with(:err)
55
+ df = subject.new
56
+ df.completion(&cb)
57
+ df.fail(:err)
58
+ df.succeed(:result)
59
+
60
+ cb.should_receive(:call).with(:result)
61
+ df = subject.new
62
+ df.completion(&cb)
63
+ df.succeed(:result)
64
+ df.fail(:err)
65
+ end
66
+
67
+ it "should bind status to another deferrable" do
68
+ cb.should_receive(:call).with(:result)
69
+ df = subject.new(&cb)
70
+ other_df = subject.new
71
+ df.bind_status(other_df)
72
+ other_df.succeed(:result)
73
+
74
+ cb.should_receive(:call).with(:err)
75
+ df = subject.new(&cb)
76
+ other_df = subject.new
77
+ df.bind_status(other_df)
78
+ other_df.fail(:err)
79
+ end
80
+
81
+ shared_context 'shared protect' do
82
+ it "should call df.fail and return nil" do
83
+ ::EM.stub(:next_tick) {|&cb| cb.call }
84
+ df.errback(&cb)
85
+ cb.should_receive(:call).with(error)
86
+ df.send(protect_method) do
87
+ raise error
88
+ end.should be_nil
89
+ end
90
+
91
+ it "should call df.fail and return custom fail value" do
92
+ ::EM.stub(:next_tick) {|&cb| cb.call }
93
+ df.errback(&cb)
94
+ cb.should_receive(:call).with(error)
95
+ df.send(protect_method, :fail) do
96
+ raise error
97
+ end.should eq :fail
98
+ end
99
+ end
100
+
101
+ context "#protect" do
102
+ let(:protect_method) { :protect }
103
+ it "should return value" do
104
+ df.protect do
105
+ :result
106
+ end.should eq :result
107
+ end
108
+
109
+ include_context 'shared protect'
110
+ end
111
+
112
+ context "#protect_and_succeed" do
113
+ let(:protect_method) { :protect_and_succeed }
114
+ it "should call deferrable.succeed and return value" do
115
+ ::EM.stub(:next_tick) {|&cb| cb.call }
116
+ df.callback(&cb)
117
+ cb.should_receive(:call).with(:result)
118
+ df.protect_and_succeed do
119
+ :result
120
+ end.should eq :result
121
+ end
122
+
123
+ include_context 'shared protect'
124
+ end
125
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: em-pg-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,33 +9,43 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-07 00:00:00.000000000 Z
12
+ date: 2013-12-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pg
16
- requirement: &244130120 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: 0.13.2
21
+ version: 0.17.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *244130120
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.17.0
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: eventmachine
27
- requirement: &244129580 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
- - - ! '>='
35
+ - - ~>
31
36
  - !ruby/object:Gem::Version
32
- version: 0.12.10
37
+ version: 1.0.0
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *244129580
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rspec
38
- requirement: &244128480 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ~>
@@ -43,21 +53,15 @@ dependencies:
43
53
  version: 2.8.0
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *244128480
47
- - !ruby/object:Gem::Dependency
48
- name: eventmachine
49
- requirement: &244127700 !ruby/object:Gem::Requirement
56
+ version_requirements: !ruby/object:Gem::Requirement
50
57
  none: false
51
58
  requirements:
52
- - - ! '>='
59
+ - - ~>
53
60
  - !ruby/object:Gem::Version
54
- version: 1.0.0.beta.1
55
- type: :development
56
- prerelease: false
57
- version_requirements: *244127700
61
+ version: 2.8.0
58
62
  - !ruby/object:Gem::Dependency
59
63
  name: em-synchrony
60
- requirement: &244126900 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
61
65
  none: false
62
66
  requirements:
63
67
  - - ~>
@@ -65,37 +69,58 @@ dependencies:
65
69
  version: 1.0.0
66
70
  type: :development
67
71
  prerelease: false
68
- version_requirements: *244126900
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 1.0.0
69
78
  description: PostgreSQL asynchronous EventMachine client, based on pg interface (PG::Connection)
70
79
  email: rafal@yeondir.com
71
80
  executables: []
72
81
  extensions: []
73
82
  extra_rdoc_files:
74
- - README.rdoc
75
- - BENCHMARKS.rdoc
83
+ - README.md
84
+ - BENCHMARKS.md
85
+ - LICENSE
86
+ - HISTORY.md
76
87
  files:
77
- - BENCHMARKS.rdoc
78
- - HISTORY.rdoc
79
- - README.rdoc
88
+ - .yardopts
89
+ - BENCHMARKS.md
90
+ - HISTORY.md
91
+ - LICENSE
92
+ - README.md
80
93
  - Rakefile
81
94
  - benchmarks/em_pg.rb
82
95
  - em-pg-client.gemspec
96
+ - lib/em-pg-client.rb
83
97
  - lib/em-synchrony/pg.rb
98
+ - lib/pg/em-version.rb
84
99
  - lib/pg/em.rb
100
+ - lib/pg/em/client/connect_watcher.rb
101
+ - lib/pg/em/client/watcher.rb
102
+ - lib/pg/em/connection_pool.rb
103
+ - lib/pg/em/featured_deferrable.rb
104
+ - spec/connection_pool_helpers.rb
105
+ - spec/em_client.rb
85
106
  - spec/em_client_autoreconnect.rb
86
107
  - spec/em_client_common.rb
87
- - spec/em_devel_client.rb
88
- - spec/em_release_client.rb
89
108
  - spec/em_synchrony_client.rb
90
109
  - spec/em_synchrony_client_autoreconnect.rb
110
+ - spec/pg_em_client_connect_finish.rb
111
+ - spec/pg_em_client_connect_timeout.rb
112
+ - spec/pg_em_client_options.rb
113
+ - spec/pg_em_connection_pool.rb
114
+ - spec/pg_em_featured_deferrable.rb
91
115
  homepage: http://github.com/royaltm/ruby-em-pg-client
92
- licenses: []
116
+ licenses:
117
+ - MIT
93
118
  post_install_message:
94
119
  rdoc_options:
95
120
  - --title
96
121
  - em-pg-client
97
122
  - --main
98
- - README.rdoc
123
+ - README.md
99
124
  require_paths:
100
125
  - lib
101
126
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -103,7 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
128
  requirements:
104
129
  - - ! '>='
105
130
  - !ruby/object:Gem::Version
106
- version: 1.9.1
131
+ version: 1.9.2
107
132
  required_rubygems_version: !ruby/object:Gem::Requirement
108
133
  none: false
109
134
  requirements:
@@ -113,14 +138,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
138
  requirements:
114
139
  - PostgreSQL server
115
140
  rubyforge_project:
116
- rubygems_version: 1.8.17
141
+ rubygems_version: 1.8.25
117
142
  signing_key:
118
143
  specification_version: 3
119
144
  summary: EventMachine PostgreSQL client
120
145
  test_files:
146
+ - spec/pg_em_client_connect_timeout.rb
147
+ - spec/em_client.rb
148
+ - spec/connection_pool_helpers.rb
149
+ - spec/pg_em_client_options.rb
121
150
  - spec/em_synchrony_client.rb
122
- - spec/em_devel_client.rb
123
151
  - spec/em_client_common.rb
124
- - spec/em_release_client.rb
125
152
  - spec/em_synchrony_client_autoreconnect.rb
153
+ - spec/pg_em_client_connect_finish.rb
154
+ - spec/pg_em_connection_pool.rb
126
155
  - spec/em_client_autoreconnect.rb
156
+ - spec/pg_em_featured_deferrable.rb
@@ -1,431 +0,0 @@
1
- = em-pg-client
2
-
3
- Author:: Rafał Michalski (mailto:rafal@yeondir.com)
4
-
5
- * http://github.com/royaltm/ruby-em-pg-client
6
-
7
- == DESCRIPTION
8
-
9
- *em-pg-client* is the Ruby and EventMachine driver interface to the PostgreSQL
10
- RDBMS. It is based on ruby-pg[https://bitbucket.org/ged/ruby-pg].
11
-
12
- == FEATURES
13
-
14
- * Non-blocking / asynchronous processing with EventMachine,
15
- * fully async auto re-connects on connection losses (e.g.: RDBMS restarts),
16
- * minimal changes to PG::Connection[http://deveiate.org/code/pg/PG/Connection.html] API,
17
- * configurable timeouts (connect or execute) of asynchronous processing,
18
- * additional Fiber-aware version supporting EM-Synchrony[https://github.com/igrigorik/em-synchrony].
19
-
20
- == BUGS/LIMITATIONS
21
-
22
- * no async support for: COPY commands (+get_copy_data+, +put_copy_data+),
23
- +wait_for_notify+ and +transaction+
24
- * actually no ActiveRecord nor Sequel support (you are welcome to contribute).
25
- * doesn't work on Windows (issue #7)
26
-
27
- == API Changes between versions
28
-
29
- === 0.1.x -> 0.2.x
30
- * +on_reconnect+ renamed to more accurate +on_autoreconnect+
31
- (well, it's not used by PG::EM::Client#reset call).
32
- * +async_autoreconnect+ is +false+ by default if +on_autoreconnect+
33
- is *not* specified as initialization option.
34
-
35
- == TODO:
36
-
37
- * implement EM adapted version of +get_copy_data+, +put_copy_data+,
38
- +wait_for_notify+ and +transaction+
39
- * add some fd/socket hackery to get it working on Windows (issue #7)
40
- * em-synchrony ORM (ActiveRecord, Sequel and maybe Datamapper) support
41
- as separate projects
42
- * present more benchmarks
43
-
44
- == REQUIREMENTS
45
-
46
- * ruby >= 1.9 (tested: 1.9.3-p194, 1.9.2-p320, 1.9.1-p378)
47
- * https://bitbucket.org/ged/ruby-pg >= 0.13.2 (>= 0.14 recommended)
48
- * PostgreSQL[http://www.postgresql.org/ftp/source/] RDBMS >= 8.3
49
- * http://rubyeventmachine.com >= 0.12.10
50
- * (optional) EM-Synchrony[https://github.com/igrigorik/em-synchrony]
51
-
52
- == INSTALL
53
-
54
- $ [sudo] gem install em-pg-client
55
-
56
- ==== Gemfile
57
-
58
- # eventmachine
59
- gem "em-pg-client", "~> 0.2.1", :require => 'pg/em'
60
- # em-synchrony
61
- gem "em-pg-client", "~> 0.2.1", :require => ['pg/em', 'em-synchrony/pg']
62
-
63
- ==== Github
64
-
65
- git clone git://github.com/royaltm/ruby-em-pg-client.git
66
-
67
- == WHY?
68
-
69
- Because I didn't find any ruby-pg's EM implementation to fit my needs.
70
- I've found at least 3 other implementations of EM postgres client:
71
-
72
- * https://github.com/jzimmek/em-postgresql-sequel
73
- * https://github.com/leftbee/em-postgresql-adapter
74
- * https://github.com/jtoy/em-postgres
75
-
76
- and (except the EM-bundled one which uses no longer maintained postgres-pr library)
77
- all of them have similiar flaws:
78
-
79
- * 2 of them are designed to support some ORM (ActiveRecord or Sequel),
80
- so they are EM-Synchrony only,
81
- * non-standard API method names,
82
- * no (nonexistent or non-working) autoreconnect implementation,
83
- * poor error handling,
84
- * not fully supporting asynchronous PG::Connection API.
85
-
86
- The last one is worth some comment:
87
-
88
- They all use blocking methods to retrieve whole result from server
89
- (PGConn#block[http://deveiate.org/code/pg/PG/Connection.html#method-i-block] or
90
- PGConn#get_result[http://deveiate.org/code/pg/PG/Connection.html#method-i-get_result] which also
91
- blocks when there is not enough buffered data on socket).
92
-
93
- This implementation makes use of non-blocking:
94
- PGConn#is_busy[http://deveiate.org/code/pg/PG/Connection.html#method-i-is_busy] and
95
- PGConn#consume_input[http://deveiate.org/code/pg/PG/Connection.html#method-i-consume_input] methods.
96
- Depending on the size of queries results and the level of concurrency, the gain in overall speed and
97
- responsiveness of your application might be actually quite huge. I've done some
98
- tests[link:BENCHMARKS.rdoc] already.
99
-
100
- == Thanks
101
-
102
- The greetz go to:
103
- - Authors[https://bitbucket.org/ged/ruby-pg/wiki/Home#!copying] of +pg+ driver (especially for its async-api)
104
- - Francis Cianfrocca for great reactor framework (EventMachine[https://github.com/eventmachine/eventmachine])
105
- - Ilya Grigorik (igrigorik[https://github.com/igrigorik]) for (untangling[http://www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers/]) EM with Fibers
106
-
107
- == USAGE
108
- +em-pg-client+ provides PG::EM::Client class which inherits
109
- PG::Connection[http://deveiate.org/code/pg/PG/Connection.html].
110
- You can work with PG::EM::Client almost the same way you would with
111
- PG::Connection.
112
-
113
- The real difference begins when you turn EventMachine reactor on.
114
-
115
- === BASIC
116
-
117
- require 'pg/em'
118
-
119
- # no async
120
- pg = PG::EM::Client.new dbname: 'test'
121
- pg.query('select * from foo') do |result|
122
- puts Array(result).inspect
123
- end
124
-
125
- # asynchronous
126
- EM.run do
127
- df = pg.query('select * from foo')
128
- df.callback { |result|
129
- puts Array(result).inspect
130
- EM.stop
131
- }
132
- df.errback {|ex|
133
- raise ex
134
- }
135
- puts "sent"
136
- end
137
-
138
- # alternatively
139
- EM.run do
140
- pg.query('select * from foo') do |result|
141
- raise result if result.is_a? ::Exception
142
- puts Array(result).inspect
143
- EM.stop
144
- end
145
- puts "sent"
146
- end
147
-
148
- === PG::Connection methods adapted to EventMachine
149
- The list of PG::EM::Client async methods for processing with EventMachine.
150
-
151
- ==== 1. Async methods (always returning +Deferrable+ object):
152
-
153
- * +Client.async_connect+ (singleton)
154
- * +async_reset+
155
- * +async_exec+ (alias: +async_query+)
156
- * +async_prepare+
157
- * +async_exec_prepared+
158
- * +async_describe_prepared+
159
- * +async_describe_portal+
160
-
161
- For arguments of theese methods consult their original blocking (without +async_+ prefix)
162
- counterparts in PG::Connection[http://deveiate.org/code/pg/PG/Connection.html] manual.
163
-
164
- Use +callback+ on the returned +Deferrable+ to receive result.
165
- The result you receive is PG::EM::Client for PG::EM::Client.async_connect
166
- and +async_reset+, and PG::Result[http://deveiate.org/code/pg/PG/Result.html] for the rest
167
- of the methods. The received PG::EM::Client is in a connected state and ready for queries.
168
- You need to +clear+ obtained PG::Result object yourself or leave it to +gc+.
169
-
170
- To detect a failure in an executed method use +errback+ on returned +Deferrable+.
171
- You should expect an instance of +Exception+ (usually PG::Error) as +errback+
172
- argument. You may check its +backtrace+ to find origin of the error.
173
-
174
- ==== 2. Async / blocking methods (returning +Deferrable+ only when EM is running):
175
-
176
- * +exec+ (alias: +query+)
177
- * +prepare+
178
- * +exec_prepared+
179
- * +describe_prepared+
180
- * +describe_portal+
181
-
182
- Outside EventMachine's event loop these methods are regular, blocking PG::Connection
183
- methods.
184
-
185
- All the methods (1 & 2) accept block argument which they attach to +callback+ and +errback+
186
- hooks of returned +Deferrable+.
187
-
188
- You may also mix async and blocking methods without closing the connection.
189
- You only need to start/stop EventMachine in between async calls.
190
-
191
- ==== Special options
192
- There are 3 additional connection options and 1 standard +pg+ option used by
193
- async methods. You may add them as one of the *hash* options to
194
- PG::EM::Client.new or PG::EM::Client.async_connect or simply use accessor
195
- methods to change them on the fly. The additional options are not passed to
196
- +libpq+.
197
-
198
- The options are:
199
-
200
- - +async_autoreconnect+ (+true+ / +false+ with default +false+ unless
201
- +on_autoreconnect+ is specified)
202
- allows automatic re-connection when there was a problem with connection
203
- to the server,
204
- - +on_autoreconnect+ (+nil+ / +Proc+ with default +nil+)
205
- a hook which is called after auto-reconnecting,
206
- - +query_timeout+ (+Float+ / +Fixnum+ with default +0+)
207
- allows to set timeout for query execution,
208
- - +connect_timeout+ (+Float+ / +Fixnum+ with default +0+)
209
- connection establishing and resetting timeout.
210
-
211
- Only +connect_timeout+ is a standard +libpq+ option, although changing it by
212
- accessor method only affects asynchronous functions.
213
-
214
- === AUTORECONNECTING IN ASYNC MODE
215
- Autoreconnecting is done in non-blocking manner using +async_reset+ internally.
216
-
217
- EM.run do
218
- pg = PG::EM::Client.new dbname: 'test',
219
- connect_timeout: 5, query_timeout: 50,
220
- async_autoreconnect: true
221
- try_query = lambda do |&blk|
222
- pg.query('select * from foo') do |result|
223
- raise result if result.is_a? ::Exception
224
- puts Array(result).inspect
225
- blk.call
226
- end
227
- end
228
- try_query.call {
229
- system 'pg_ctl stop -m fast'
230
- system 'pg_ctl start -w'
231
- try_query.call { EM.stop }
232
- }
233
- end
234
-
235
- to enable this feature call:
236
-
237
- pg.async_autoreconnect = true
238
-
239
- or
240
-
241
- pg = PG::EM::Client.new dbname: 'test',
242
- async_autoreconnect: true
243
-
244
- It's also possible to define +on_autoreconnect+ callback to be invoked
245
- while the connection has been reset. It's called just before the send query
246
- command is executed:
247
-
248
- EM.run do
249
- pg = PG::EM::Client.new dbname: 'test',
250
- async_autoreconnect: true
251
- pg.prepare('bar', 'select * from foo order by cdate desc') do
252
- pg.on_autoreconnect = proc { |c, e|
253
- c.prepare('bar', 'select * from foo order by cdate desc')
254
- }
255
- try_query = lambda do |&blk|
256
- pg.exec_prepared('bar') do |result|
257
- raise result if result.is_a? ::Exception
258
- puts Array(result).inspect
259
- blk.call
260
- end
261
- end
262
- try_query.call {
263
- system 'pg_ctl stop -m fast'
264
- system 'pg_ctl start -w'
265
- try_query.call { EM.stop }
266
- }
267
- end
268
- end
269
-
270
- As you can see it's possible to send async query from inside +on_autoreconnect+
271
- proc. However you have to pass +Deferrable+ from the async callback to the
272
- caller. See PG::EM::Client#on_autoreconnect docs for details.
273
-
274
- === TRUE ASYNC
275
- For non-blocking connect use PG::EM::Client.async_connect and
276
- PG::EM::Client#async_reset for asynchronous re-connect. Like other async
277
- methods they return +Deferrable+ object.
278
- Use Deferrable's #callback to obtain already connected PG::EM::Client.
279
-
280
- EM.run do
281
- pool = (1..10).map {
282
- PG::EM::Client.async_connect dbname: 'test',
283
- connect_timeout: 5, query_timeout: 50 }
284
-
285
- togo = pool.length
286
-
287
- pool.each_with_index do |df, i|
288
- df.callback do |pg|
289
- pg.query("select * from foo") do |result|
290
- puts "recv: #{i}"
291
- EM.stop if (togo-=1).zero?
292
- end
293
- puts "sent: #{i}"
294
- end
295
- df.errback { |ex| raise ex }
296
- end
297
- end
298
-
299
- === Fibers / EM-Synchrony
300
- There is a special version of PG::EM::Client library with fiber aware methods
301
- for EM-Synchrony or other implementations of Fiber untangled EventMachine.
302
-
303
- The +require+ string is "em-synchrony/pg" instead of "pg/em".
304
-
305
- +em-synchrony/pg+ version of PG::EM::Client.new is fully asynchronous and
306
- blocks only current fiber. This also applies to PG::EM::Client#reset.
307
-
308
- require 'em-synchrony'
309
- require 'em-synchrony/pg'
310
-
311
- EM.synchrony do
312
- pg = PG::EM::Client.new dbname: 'test'
313
- pg.query('select * from foo') do |result|
314
- puts Array(result).inspect
315
- end
316
- EM.stop
317
- end
318
-
319
- Although em-synchrony[https://github.com/igrigorik/em-synchrony/] provides
320
- very nice set of tools for untangled EventMachine, you don't really require
321
- it to fully benefit from this version of PG::EM::Client.
322
-
323
- ==== PG::Connection methods adapted to EM-Synchrony
324
- The list of PG::EM::Client fiber aware methods for processing with
325
- EM-Synchrony / EventMachine.
326
-
327
- All +async_*+ methods are exactly the same as in pure EventMachine version
328
- of PG::EM::Client.
329
-
330
- The fiber aware methods are:
331
-
332
- * +Client.connect+ (singleton, alias: +new+, +open+, +setdb+, +setdblogin+)
333
- * +reset+
334
- * +exec+ (alias: +query+)
335
- * +prepare+
336
- * +exec_prepared+
337
- * +describe_prepared+
338
- * +describe_portal+
339
-
340
- Under the hood, these methods call async counterparts of themselves and +yield+ from current
341
- fiber awaiting for the result. The PG::Result (or PG::EM::Client for +connect+
342
- and +reset+) is then returned to the caller. If code block was given, it is
343
- executed with result as the argument. In that case the value of the block is
344
- returned instead and PG::Result is cleared (or in case of +connect+ or +reset+
345
- PG::EM::Client is being closed) after executing block. From single fiber point
346
- of view, they behave like regular blocking PG::Connection methods.
347
-
348
- Each of them is also automatic, detecting if EventMachine is running.
349
- If called outside EM event loop they are exactly the original methods of
350
- PG::Connection.
351
-
352
- Like in pure EventMachine version you can mix async, fiber aware and
353
- blocking methods without finishing the connection. You only need to
354
- start/stop EventMachine in between async calls.
355
-
356
- ==== Handling errors
357
-
358
- EM.synchrony do
359
- begin
360
- pg.query('select * from foo') do |result|
361
- puts result
362
- end
363
- rescue PG::Error => e
364
- puts "PSQL error: #{e.inspect}"
365
- end
366
- EM.stop
367
- end
368
-
369
- ==== Parallel async queries
370
-
371
- EM.synchrony do
372
- pg = EM::Synchrony::ConnectionPool.new(size: 2) do
373
- PG::EM::Client.new :dbname => 'test'
374
- end
375
- multi = EventMachine::Synchrony::Multi.new
376
- multi.add :foo, pg.aquery('select * from foo') # or #async_query()
377
- multi.add :bar, pg.aquery('select * from bar') # #aquery() is just an alias
378
- res = multi.perform
379
- p res
380
- EM.stop
381
- end
382
-
383
- ==== Fiber Concurrency
384
-
385
- EM.synchrony do
386
- # use ConnectionPool when more Fibers will be querying at the same time!
387
- pg = EM::Synchrony::ConnectionPool.new(size: 5) do
388
- PG::EM::Client.new :dbname => 'test'
389
- end
390
- counter = 0
391
- EM::Synchrony::FiberIterator.new(['select * from foo']*10, 5) do |query|
392
- i = counter
393
- pg.query(query) do |result|
394
- puts "recv: #{i}"
395
- end
396
- puts "sent: #{i}"
397
- counter += 1
398
- end
399
- EM.stop
400
- end
401
-
402
- ==== Async reconnect with on_autoreconnect callback
403
-
404
- EM.synchrony do
405
- on_autoreconnect = proc do |c, e|
406
- c.prepare('bar', 'select * from foo order by cdate desc')
407
- end
408
- pg = EM::Synchrony::ConnectionPool.new(size: 5) do
409
- p = PG::EM::Client.new dbname: 'test', on_autoreconnect: on_autoreconnect
410
- on_autoreconnect.call p
411
- p
412
- end
413
- try_query = lambda do
414
- pg.exec_prepared('bar') do |result|
415
- raise result if result.is_a? ::Exception
416
- puts Array(result).inspect
417
- end
418
- end
419
- try_query.call
420
- system 'pg_ctl stop -m fast'
421
- system 'pg_ctl start -w'
422
- try_query.call
423
- EM.stop
424
- end
425
-
426
- Specifying +on_autoreconnect+ as PG::EM::Client.new initialization option,
427
- implicitly enables +async_autoreconnect+.
428
-
429
- == LICENCE
430
-
431
- The MIT License - Copyright (c) 2012 Rafał Michalski