google-cloud-firestore 2.2.0 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2c1c6b4bcea222f6ed81150700b9d6c969fc70eeb8492db0ed69db1bb43f62cb
4
- data.tar.gz: 50bbd220cf388af656606d99948477d47f9a1fa3d41ab479f6fcaa32f32e909d
3
+ metadata.gz: 12a9c7f721487eef84a1d703f77f0b2f56aea624fc9c6e1052be059c49437a6f
4
+ data.tar.gz: 76d354bb9933a7a83ef6163fef5bd37da82808786f05d06a83f54dc605ca1154
5
5
  SHA512:
6
- metadata.gz: d1a810ae1cd779858ad8762dacd08765b2daf06b1de8ce13dc675b79ef7c6696c3bbda34d7593a6087e2189aebd2e23090bd89d11da8753f1751726270a61391
7
- data.tar.gz: af77949c47636ca6e65ca14224fa5270a9f3daa4c00fd236e19780273e35593c0986ba5e5a0d601a6f107cbdc5482db51ca002841ee8cbf21acbd9ac752a93ee
6
+ metadata.gz: b8e403df8684221a0521432017c511f8b0c4d174c97c95129f7952e6751914093fe692585127d2f0a267f9776b9a464062bd10e3f3a7d9aa7c772edcddde8d2e
7
+ data.tar.gz: bd858f3f1c199b835ce22f567068af585f9ce41d2cd9da6811f5d06bbcc45ab1aadaa40575d1684bb2245d691c90589df420343a0233039f860030513037de75
@@ -1,5 +1,15 @@
1
1
  # Release History
2
2
 
3
+ ### 2.3.0 / 2020-09-30
4
+
5
+ #### Features
6
+
7
+ * Add error callbacks for listener threads
8
+ * Add DocumentListener#last_error
9
+ * Add DocumentListener#on_error
10
+ * Add QueryListener#last_error
11
+ * Add QueryListener#on_error
12
+
3
13
  ### 2.2.0 / 2020-09-17
4
14
 
5
15
  #### Features
@@ -14,11 +14,14 @@
14
14
 
15
15
 
16
16
  require "google/cloud/firestore/watch/listener"
17
+ require "monitor"
17
18
 
18
19
  module Google
19
20
  module Cloud
20
21
  module Firestore
21
22
  ##
23
+ # # DocumentListener
24
+ #
22
25
  # An ongoing listen operation on a document reference. This is returned by
23
26
  # calling {DocumentReference#listen}.
24
27
  #
@@ -31,25 +34,28 @@ module Google
31
34
  # nyc_ref = firestore.doc "cities/NYC"
32
35
  #
33
36
  # listener = nyc_ref.listen do |snapshot|
34
- # puts "The population of #{snapshot[:name]} "
35
- # puts "is #{snapshot[:population]}."
37
+ # puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
36
38
  # end
37
39
  #
38
40
  # # When ready, stop the listen operation and close the stream.
39
41
  # listener.stop
40
42
  #
41
43
  class DocumentListener
44
+ include MonitorMixin
42
45
  ##
43
46
  # @private
44
47
  # Creates the watch stream and listener object.
45
48
  def initialize doc_ref, &callback
49
+ super() # to init MonitorMixin
50
+
46
51
  @doc_ref = doc_ref
47
52
  raise ArgumentError if @doc_ref.nil?
48
53
 
49
54
  @callback = callback
50
55
  raise ArgumentError if @callback.nil?
56
+ @error_callbacks = []
51
57
 
52
- @listener = Watch::Listener.for_doc_ref doc_ref do |query_snp|
58
+ @listener = Watch::Listener.for_doc_ref self, doc_ref do |query_snp|
53
59
  doc_snp = query_snp.docs.find { |doc| doc.path == @doc_ref.path }
54
60
 
55
61
  if doc_snp.nil?
@@ -80,8 +86,7 @@ module Google
80
86
  # nyc_ref = firestore.doc "cities/NYC"
81
87
  #
82
88
  # listener = nyc_ref.listen do |snapshot|
83
- # puts "The population of #{snapshot[:name]} "
84
- # puts "is #{snapshot[:population]}."
89
+ # puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
85
90
  # end
86
91
  #
87
92
  # # When ready, stop the listen operation and close the stream.
@@ -103,8 +108,7 @@ module Google
103
108
  # nyc_ref = firestore.doc "cities/NYC"
104
109
  #
105
110
  # listener = nyc_ref.listen do |snapshot|
106
- # puts "The population of #{snapshot[:name]} "
107
- # puts "is #{snapshot[:population]}."
111
+ # puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
108
112
  # end
109
113
  #
110
114
  # # Checks if the listener is stopped.
@@ -119,6 +123,81 @@ module Google
119
123
  def stopped?
120
124
  @listener.stopped?
121
125
  end
126
+
127
+ ##
128
+ # Register to be notified of errors when raised.
129
+ #
130
+ # If an unhandled error has occurred the listener will attempt to
131
+ # recover from the error and resume listening.
132
+ #
133
+ # Multiple error handlers can be added.
134
+ #
135
+ # @yield [callback] The block to be called when an error is raised.
136
+ # @yieldparam [Exception] error The error raised.
137
+ #
138
+ # @example
139
+ # require "google/cloud/firestore"
140
+ #
141
+ # firestore = Google::Cloud::Firestore.new
142
+ #
143
+ # # Get a document reference
144
+ # nyc_ref = firestore.doc "cities/NYC"
145
+ #
146
+ # listener = nyc_ref.listen do |snapshot|
147
+ # puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
148
+ # end
149
+ #
150
+ # # Register to be notified when unhandled errors occur.
151
+ # listener.on_error do |error|
152
+ # puts error
153
+ # end
154
+ #
155
+ # # When ready, stop the listen operation and close the stream.
156
+ # listener.stop
157
+ #
158
+ def on_error &block
159
+ raise ArgumentError, "on_error must be called with a block" unless block_given?
160
+ synchronize { @error_callbacks << block }
161
+ end
162
+
163
+ ##
164
+ # The most recent unhandled error to occur while listening for changes.
165
+ #
166
+ # If an unhandled error has occurred the listener will attempt to
167
+ # recover from the error and resume listening.
168
+ #
169
+ # @return [Exception, nil] error The most recent error raised.
170
+ #
171
+ # @example
172
+ # require "google/cloud/firestore"
173
+ #
174
+ # firestore = Google::Cloud::Firestore.new
175
+ #
176
+ # # Get a document reference
177
+ # nyc_ref = firestore.doc "cities/NYC"
178
+ #
179
+ # listener = nyc_ref.listen do |snapshot|
180
+ # puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
181
+ # end
182
+ #
183
+ # # If an error was raised, it can be retrieved here:
184
+ # listener.last_error #=> nil
185
+ #
186
+ # # When ready, stop the listen operation and close the stream.
187
+ # listener.stop
188
+ #
189
+ def last_error
190
+ synchronize { @last_error }
191
+ end
192
+
193
+ # @private Pass the error to user-provided error callbacks.
194
+ def error! error
195
+ error_callbacks = synchronize do
196
+ @last_error = error
197
+ @error_callbacks.dup
198
+ end
199
+ error_callbacks.each { |error_callback| error_callback.call error }
200
+ end
122
201
  end
123
202
  end
124
203
  end
@@ -168,8 +168,7 @@ module Google
168
168
  # nyc_ref = firestore.doc "cities/NYC"
169
169
  #
170
170
  # listener = nyc_ref.listen do |snapshot|
171
- # puts "The population of #{snapshot[:name]} "
172
- # puts "is #{snapshot[:population]}."
171
+ # puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
173
172
  # end
174
173
  #
175
174
  # # When ready, stop the listen operation and close the stream.
@@ -53,8 +53,7 @@ module Google
53
53
  # nyc_ref = firestore.doc "cities/NYC"
54
54
  #
55
55
  # listener = nyc_ref.listen do |snapshot|
56
- # puts "The population of #{snapshot[:name]} "
57
- # puts "is #{snapshot[:population]}."
56
+ # puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
58
57
  # end
59
58
  #
60
59
  # # When ready, stop the listen operation and close the stream.
@@ -41,17 +41,21 @@ module Google
41
41
  # listener.stop
42
42
  #
43
43
  class QueryListener
44
+ include MonitorMixin
44
45
  ##
45
46
  # @private
46
47
  # Creates the watch stream and listener object.
47
48
  def initialize query, &callback
49
+ super() # to init MonitorMixin
50
+
48
51
  @query = query
49
52
  raise ArgumentError if @query.nil?
50
53
 
51
54
  @callback = callback
52
55
  raise ArgumentError if @callback.nil?
56
+ @error_callbacks = []
53
57
 
54
- @listener = Watch::Listener.for_query query, &callback
58
+ @listener = Watch::Listener.for_query self, query, &callback
55
59
  end
56
60
 
57
61
  ##
@@ -112,6 +116,83 @@ module Google
112
116
  def stopped?
113
117
  @listener.stopped?
114
118
  end
119
+
120
+ ##
121
+ # Register to be notified of errors when raised.
122
+ #
123
+ # If an unhandled error has occurred the listener will attempt to
124
+ # recover from the error and resume listening.
125
+ #
126
+ # Multiple error handlers can be added.
127
+ #
128
+ # @yield [callback] The block to be called when an error is raised.
129
+ # @yieldparam [Exception] error The error raised.
130
+ #
131
+ # @example
132
+ # require "google/cloud/firestore"
133
+ #
134
+ # firestore = Google::Cloud::Firestore.new
135
+ #
136
+ # # Create a query
137
+ # query = firestore.col(:cities).order(:population, :desc)
138
+ #
139
+ # listener = query.listen do |snapshot|
140
+ # puts "The query snapshot has #{snapshot.docs.count} documents "
141
+ # puts "and has #{snapshot.changes.count} changes."
142
+ # end
143
+ #
144
+ # # Register to be notified when unhandled errors occur.
145
+ # listener.on_error do |error|
146
+ # puts error
147
+ # end
148
+ #
149
+ # # When ready, stop the listen operation and close the stream.
150
+ # listener.stop
151
+ #
152
+ def on_error &block
153
+ raise ArgumentError, "on_error must be called with a block" unless block_given?
154
+ synchronize { @error_callbacks << block }
155
+ end
156
+
157
+ ##
158
+ # The most recent unhandled error to occur while listening for changes.
159
+ #
160
+ # If an unhandled error has occurred the listener will attempt to
161
+ # recover from the error and resume listening.
162
+ #
163
+ # @return [Exception, nil] error The most recent error raised.
164
+ #
165
+ # @example
166
+ # require "google/cloud/firestore"
167
+ #
168
+ # firestore = Google::Cloud::Firestore.new
169
+ #
170
+ # # Create a query
171
+ # query = firestore.col(:cities).order(:population, :desc)
172
+ #
173
+ # listener = query.listen do |snapshot|
174
+ # puts "The query snapshot has #{snapshot.docs.count} documents "
175
+ # puts "and has #{snapshot.changes.count} changes."
176
+ # end
177
+ #
178
+ # # If an error was raised, it can be retrieved here:
179
+ # listener.last_error #=> nil
180
+ #
181
+ # # When ready, stop the listen operation and close the stream.
182
+ # listener.stop
183
+ #
184
+ def last_error
185
+ synchronize { @last_error }
186
+ end
187
+
188
+ # @private Pass the error to user-provided error callbacks.
189
+ def error! error
190
+ error_callbacks = synchronize do
191
+ @last_error = error
192
+ @error_callbacks.dup
193
+ end
194
+ error_callbacks.each { |error_callback| error_callback.call error }
195
+ end
115
196
  end
116
197
  end
117
198
  end
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Firestore
19
- VERSION = "2.2.0".freeze
19
+ VERSION = "2.3.0".freeze
20
20
  end
21
21
  end
22
22
  end
@@ -30,7 +30,7 @@ module Google
30
30
  class Listener
31
31
  include MonitorMixin
32
32
 
33
- def self.for_doc_ref doc_ref, &callback
33
+ def self.for_doc_ref parent, doc_ref, &callback
34
34
  raise ArgumentError if doc_ref.nil?
35
35
  raise ArgumentError if callback.nil?
36
36
 
@@ -44,10 +44,10 @@ module Google
44
44
  )
45
45
  )
46
46
 
47
- new nil, doc_ref, doc_ref.client, init_listen_req, &callback
47
+ new parent, nil, doc_ref, doc_ref.client, init_listen_req, &callback
48
48
  end
49
49
 
50
- def self.for_query query, &callback
50
+ def self.for_query parent, query, &callback
51
51
  raise ArgumentError if query.nil?
52
52
  raise ArgumentError if callback.nil?
53
53
 
@@ -61,12 +61,13 @@ module Google
61
61
  )
62
62
  )
63
63
 
64
- new query, nil, query.client, init_listen_req, &callback
64
+ new parent, query, nil, query.client, init_listen_req, &callback
65
65
  end
66
66
 
67
- def initialize query, doc_ref, client, init_listen_req, &callback
67
+ def initialize parent, query, doc_ref, client, init_listen_req, &callback
68
68
  super() # to init MonitorMixin
69
69
 
70
+ @parent = parent
70
71
  @query = query
71
72
  @doc_ref = doc_ref
72
73
  @client = client
@@ -119,6 +120,8 @@ module Google
119
120
 
120
121
  def send_callback query_snp
121
122
  @callback.call query_snp
123
+ rescue StandardError => e
124
+ @parent.error! e
122
125
  end
123
126
 
124
127
  def start_listening!
@@ -270,25 +273,29 @@ module Google
270
273
  @request_queue.push self
271
274
  rescue GRPC::Cancelled, GRPC::DeadlineExceeded, GRPC::Internal,
272
275
  GRPC::ResourceExhausted, GRPC::Unauthenticated,
273
- GRPC::Unavailable, GRPC::Core::CallError
276
+ GRPC::Unavailable, GRPC::Core::CallError => e
274
277
  # Restart the stream with an incremental back for a retriable error.
275
278
  # Also when GRPC raises the internal CallError.
276
279
 
277
- # Re-raise if retried more than the max
278
- raise err if @backoff[:current] > @backoff[:max]
279
-
280
- # Sleep with incremental backoff before restarting
281
- sleep @backoff[:delay]
280
+ # Raise if retried more than the max
281
+ if @backoff[:current] > @backoff[:max]
282
+ @parent.error! e
283
+ raise e
284
+ else
285
+ # Sleep with incremental backoff before restarting
286
+ sleep @backoff[:delay]
282
287
 
283
- # Update increment backoff delay and retry counter
284
- @backoff[:delay] *= @backoff[:mod]
285
- @backoff[:current] += 1
288
+ # Update increment backoff delay and retry counter
289
+ @backoff[:delay] *= @backoff[:mod]
290
+ @backoff[:current] += 1
286
291
 
287
- retry
292
+ retry
293
+ end
288
294
  rescue RestartStream
289
295
  retry
290
296
  rescue StandardError => e
291
- raise Google::Cloud::Error.from_error(e)
297
+ @parent.error! e
298
+ raise e
292
299
  end
293
300
  end
294
301
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-firestore
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Google Inc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-17 00:00:00.000000000 Z
11
+ date: 2020-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-cloud-core