em-pg-client-helper 0.5.0 → 0.5.1
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.
- data/lib/em-pg-client-helper/deferrable_group.rb +26 -13
- data/lib/em-pg-client-helper/transaction.rb +35 -15
- data/spec/db_transaction_spec.rb +22 -18
- metadata +3 -3
@@ -10,10 +10,10 @@ class PG::EM::Client::Helper::DeferrableGroup
|
|
10
10
|
# Create a new deferrable group.
|
11
11
|
#
|
12
12
|
def initialize
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@first_failure = nil
|
13
|
+
@closed = false
|
14
|
+
@failure = nil
|
16
15
|
@outstanding = []
|
16
|
+
|
17
17
|
yield(self) if block_given?
|
18
18
|
end
|
19
19
|
|
@@ -24,19 +24,34 @@ class PG::EM::Client::Helper::DeferrableGroup
|
|
24
24
|
# @return [EM::Deferrable] the same deferrable.
|
25
25
|
#
|
26
26
|
# @raise [RuntimeError] if you attempt to add a deferrable after the
|
27
|
-
# group has
|
28
|
-
#
|
27
|
+
# group has been closed (that is, the `#close` method has been called),
|
28
|
+
# indicating that the deferrable group doesn't have any more deferrables
|
29
|
+
# to add.
|
29
30
|
#
|
30
31
|
def add(df)
|
31
|
-
if @
|
32
|
+
if @closed
|
32
33
|
raise RuntimeError,
|
33
|
-
"This deferrable group
|
34
|
+
"This deferrable group is closed."
|
34
35
|
end
|
35
36
|
|
36
37
|
@outstanding << df
|
37
38
|
df.callback { completed(df) }.errback { |ex| failed(df, ex) }
|
38
39
|
end
|
39
40
|
|
41
|
+
# Tell the group that no further deferrables are to be added
|
42
|
+
#
|
43
|
+
# If all the deferrables in a group are complete, the group can't be sure
|
44
|
+
# whether further deferrables may be added in the future. By requiring
|
45
|
+
# an explicit `#close` call before the group completes, this ambiguity is
|
46
|
+
# avoided. It does, however, mean that if you forget to close the
|
47
|
+
# deferrable group, your code is going to hang. Such is the risk of
|
48
|
+
# async programming.
|
49
|
+
#
|
50
|
+
def close
|
51
|
+
@closed = true
|
52
|
+
maybe_done
|
53
|
+
end
|
54
|
+
|
40
55
|
# Mark a deferrable as having been completed.
|
41
56
|
#
|
42
57
|
# If this is the last deferrable in the group, then the callback/errback
|
@@ -58,8 +73,7 @@ class PG::EM::Client::Helper::DeferrableGroup
|
|
58
73
|
# will unfortunately be eaten by a grue.
|
59
74
|
#
|
60
75
|
def failed(df, ex)
|
61
|
-
@
|
62
|
-
@failed = true
|
76
|
+
@failure ||= ex
|
63
77
|
completed(df)
|
64
78
|
end
|
65
79
|
|
@@ -67,10 +81,9 @@ class PG::EM::Client::Helper::DeferrableGroup
|
|
67
81
|
# Called every time a deferrable finishes, just in case we're ready to
|
68
82
|
# trigger our callbacks.
|
69
83
|
def maybe_done
|
70
|
-
if @outstanding.empty?
|
71
|
-
@
|
72
|
-
|
73
|
-
fail(@first_failure)
|
84
|
+
if @closed and @outstanding.empty?
|
85
|
+
if @failure
|
86
|
+
fail(@failure)
|
74
87
|
else
|
75
88
|
succeed
|
76
89
|
end
|
@@ -7,12 +7,15 @@ class PG::EM::Client::Helper::Transaction
|
|
7
7
|
def initialize(conn, opts, &blk)
|
8
8
|
@conn = conn
|
9
9
|
@opts = opts
|
10
|
-
|
10
|
+
# This can be `nil` if the txn is in progress, or it will be
|
11
|
+
# true or false to indicate success/failure of the txn
|
12
|
+
@committed = nil
|
11
13
|
|
12
14
|
DeferrableGroup.new do |dg|
|
13
15
|
@dg = dg
|
14
16
|
|
15
|
-
|
17
|
+
trace_query("BEGIN")
|
18
|
+
@conn.exec_defer("BEGIN").callback do
|
16
19
|
begin
|
17
20
|
blk.call(self)
|
18
21
|
rescue StandardError => ex
|
@@ -20,9 +23,10 @@ class PG::EM::Client::Helper::Transaction
|
|
20
23
|
end
|
21
24
|
end.errback { |ex| rollback(ex) }.tap { |df| @dg.add(df) }
|
22
25
|
end.callback do
|
23
|
-
rollback(RuntimeError.new("txn.commit was not called"))
|
26
|
+
rollback(RuntimeError.new("txn.commit was not called")) unless @committed
|
27
|
+
self.succeed
|
24
28
|
end.errback do |ex|
|
25
|
-
|
29
|
+
self.fail(ex)
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
@@ -33,11 +37,16 @@ class PG::EM::Client::Helper::Transaction
|
|
33
37
|
# exception will be raised.
|
34
38
|
#
|
35
39
|
def commit
|
36
|
-
if @
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end.
|
40
|
+
if @committed.nil?
|
41
|
+
trace_query("COMMIT")
|
42
|
+
@conn.exec_defer("COMMIT").tap do |df|
|
43
|
+
@dg.add(df)
|
44
|
+
end.callback do
|
45
|
+
@committed = true
|
46
|
+
@dg.close
|
47
|
+
end.errback do |ex|
|
48
|
+
rollback(ex)
|
49
|
+
end
|
41
50
|
end
|
42
51
|
end
|
43
52
|
|
@@ -47,11 +56,15 @@ class PG::EM::Client::Helper::Transaction
|
|
47
56
|
# event of a database error or other exception.
|
48
57
|
#
|
49
58
|
def rollback(ex)
|
50
|
-
if @
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end.
|
59
|
+
if @committed.nil?
|
60
|
+
trace_query("ROLLBACK")
|
61
|
+
@conn.exec_defer("ROLLBACK").tap do |df|
|
62
|
+
@dg.add(df)
|
63
|
+
end.callback do
|
64
|
+
@committed = false
|
65
|
+
@dg.fail(ex)
|
66
|
+
@dg.close
|
67
|
+
end
|
55
68
|
end
|
56
69
|
end
|
57
70
|
|
@@ -74,15 +87,22 @@ class PG::EM::Client::Helper::Transaction
|
|
74
87
|
# specific query finishes.
|
75
88
|
#
|
76
89
|
def exec(sql, values=[], &blk)
|
77
|
-
unless @
|
90
|
+
unless @committed.nil?
|
78
91
|
raise RuntimeError,
|
79
92
|
"Cannot execute a query in a transaction that has been closed"
|
80
93
|
end
|
81
94
|
|
95
|
+
trace_query(sql, values)
|
82
96
|
@conn.exec_defer(sql, values).tap do |df|
|
83
97
|
@dg.add(df)
|
84
98
|
df.callback(&blk) if blk
|
99
|
+
end.errback do |ex|
|
100
|
+
rollback(ex)
|
85
101
|
end
|
86
102
|
end
|
87
103
|
alias_method :exec_defer, :exec
|
104
|
+
|
105
|
+
def trace_query(q, v=nil)
|
106
|
+
$stderr.puts "#{@conn.inspect}: #{q} #{v.inspect}" if ENV['EM_PG_TXN_TRACE']
|
107
|
+
end
|
88
108
|
end
|
data/spec/db_transaction_spec.rb
CHANGED
@@ -16,11 +16,6 @@ describe "PG::EM::Client::Helper#db_transaction" do
|
|
16
16
|
and_return(df).
|
17
17
|
ordered
|
18
18
|
|
19
|
-
# Rollback expects a yield
|
20
|
-
if q == "ROLLBACK"
|
21
|
-
ex.and_yield()
|
22
|
-
end
|
23
|
-
|
24
19
|
EM.add_timer(exec_time) do
|
25
20
|
df.__send__(disposition)
|
26
21
|
end
|
@@ -32,7 +27,7 @@ describe "PG::EM::Client::Helper#db_transaction" do
|
|
32
27
|
|
33
28
|
def in_em
|
34
29
|
EM.run do
|
35
|
-
EM.add_timer(
|
30
|
+
EM.add_timer(0.5) { EM.stop; raise "test timeout" }
|
36
31
|
yield
|
37
32
|
end
|
38
33
|
end
|
@@ -41,8 +36,8 @@ describe "PG::EM::Client::Helper#db_transaction" do
|
|
41
36
|
in_em do
|
42
37
|
expect_query("BEGIN")
|
43
38
|
expect_query("COMMIT")
|
44
|
-
in_transaction do
|
45
|
-
|
39
|
+
in_transaction do |txn|
|
40
|
+
txn.commit
|
46
41
|
end
|
47
42
|
end
|
48
43
|
end
|
@@ -51,8 +46,8 @@ describe "PG::EM::Client::Helper#db_transaction" do
|
|
51
46
|
in_em do
|
52
47
|
expect_query_failure("BEGIN")
|
53
48
|
expect_query("ROLLBACK")
|
54
|
-
in_transaction do
|
55
|
-
|
49
|
+
in_transaction do |txn|
|
50
|
+
txn.commit
|
56
51
|
end
|
57
52
|
end
|
58
53
|
end
|
@@ -62,8 +57,8 @@ describe "PG::EM::Client::Helper#db_transaction" do
|
|
62
57
|
expect_query("BEGIN")
|
63
58
|
expect_query_failure("COMMIT")
|
64
59
|
expect_query("ROLLBACK")
|
65
|
-
in_transaction do
|
66
|
-
|
60
|
+
in_transaction do |txn|
|
61
|
+
txn.commit
|
67
62
|
end
|
68
63
|
end
|
69
64
|
end
|
@@ -74,7 +69,9 @@ describe "PG::EM::Client::Helper#db_transaction" do
|
|
74
69
|
expect_query('INSERT INTO "foo" ("bar") VALUES ($1)', ["baz"])
|
75
70
|
expect_query("COMMIT")
|
76
71
|
in_transaction do |txn|
|
77
|
-
txn.insert("foo", :bar => 'baz')
|
72
|
+
txn.insert("foo", :bar => 'baz') do
|
73
|
+
txn.commit
|
74
|
+
end
|
78
75
|
end
|
79
76
|
end
|
80
77
|
end
|
@@ -85,7 +82,9 @@ describe "PG::EM::Client::Helper#db_transaction" do
|
|
85
82
|
expect_query_failure('INSERT INTO "foo" ("bar") VALUES ($1)', ["baz"])
|
86
83
|
expect_query("ROLLBACK")
|
87
84
|
in_transaction do |txn|
|
88
|
-
txn.insert("foo", :bar => 'baz')
|
85
|
+
txn.insert("foo", :bar => 'baz') do
|
86
|
+
txn.commit
|
87
|
+
end
|
89
88
|
end
|
90
89
|
end
|
91
90
|
end
|
@@ -101,7 +100,9 @@ describe "PG::EM::Client::Helper#db_transaction" do
|
|
101
100
|
in_transaction do |txn|
|
102
101
|
txn.insert("foo", :bar => 'baz') do
|
103
102
|
txn.insert("foo", :bar => 'wombat') do
|
104
|
-
txn.insert("foo", :bar => 'quux')
|
103
|
+
txn.insert("foo", :bar => 'quux') do
|
104
|
+
txn.commit
|
105
|
+
end
|
105
106
|
end
|
106
107
|
end
|
107
108
|
end
|
@@ -124,7 +125,9 @@ describe "PG::EM::Client::Helper#db_transaction" do
|
|
124
125
|
in_transaction do |txn|
|
125
126
|
txn.insert("foo", :bar => 'baz') do
|
126
127
|
txn.insert("foo", :bar => 'wombat') do
|
127
|
-
txn.insert("foo", :bar => 'quux')
|
128
|
+
txn.insert("foo", :bar => 'quux') do
|
129
|
+
txn.commit
|
130
|
+
end
|
128
131
|
end
|
129
132
|
end
|
130
133
|
end
|
@@ -137,8 +140,9 @@ describe "PG::EM::Client::Helper#db_transaction" do
|
|
137
140
|
expect_query('INSERT INTO "foo" ("bar") VALUES ($1)', ["baz"])
|
138
141
|
expect_query("ROLLBACK")
|
139
142
|
in_transaction do |txn|
|
140
|
-
txn.insert("foo", :bar => 'baz')
|
141
|
-
|
143
|
+
txn.insert("foo", :bar => 'baz') do
|
144
|
+
txn.rollback("Because I can")
|
145
|
+
end
|
142
146
|
end
|
143
147
|
end
|
144
148
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-pg-client-helper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -261,7 +261,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
261
261
|
version: '0'
|
262
262
|
segments:
|
263
263
|
- 0
|
264
|
-
hash:
|
264
|
+
hash: -4325502789198036899
|
265
265
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
266
266
|
none: false
|
267
267
|
requirements:
|
@@ -270,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
270
270
|
version: '0'
|
271
271
|
segments:
|
272
272
|
- 0
|
273
|
-
hash:
|
273
|
+
hash: -4325502789198036899
|
274
274
|
requirements: []
|
275
275
|
rubyforge_project:
|
276
276
|
rubygems_version: 1.8.23
|