em-pg-client-helper 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|