em-pg-client 0.2.1 → 0.3.0

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