google-cloud-pubsub 0.20.0 → 2.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +18 -0
  3. data/AUTHENTICATION.md +178 -0
  4. data/CHANGELOG.md +659 -0
  5. data/CODE_OF_CONDUCT.md +40 -0
  6. data/CONTRIBUTING.md +187 -0
  7. data/EMULATOR.md +37 -0
  8. data/LICENSE +201 -0
  9. data/LOGGING.md +32 -0
  10. data/OVERVIEW.md +528 -0
  11. data/TROUBLESHOOTING.md +31 -0
  12. data/lib/google/cloud/pubsub/async_publisher/batch.rb +310 -0
  13. data/lib/google/cloud/pubsub/async_publisher.rb +402 -0
  14. data/lib/google/cloud/pubsub/batch_publisher.rb +100 -0
  15. data/lib/google/cloud/pubsub/convert.rb +91 -0
  16. data/lib/google/cloud/pubsub/credentials.rb +26 -10
  17. data/lib/google/cloud/pubsub/errors.rb +85 -0
  18. data/lib/google/cloud/pubsub/message.rb +82 -20
  19. data/lib/google/cloud/pubsub/policy.rb +40 -61
  20. data/lib/google/cloud/pubsub/project.rb +405 -265
  21. data/lib/google/cloud/pubsub/publish_result.rb +103 -0
  22. data/lib/google/cloud/pubsub/received_message.rb +165 -30
  23. data/lib/google/cloud/pubsub/retry_policy.rb +88 -0
  24. data/lib/google/cloud/pubsub/schema/list.rb +180 -0
  25. data/lib/google/cloud/pubsub/schema.rb +310 -0
  26. data/lib/google/cloud/pubsub/service.rb +304 -162
  27. data/lib/google/cloud/pubsub/snapshot/list.rb +178 -0
  28. data/lib/google/cloud/pubsub/snapshot.rb +205 -0
  29. data/lib/google/cloud/pubsub/subscriber/enumerator_queue.rb +54 -0
  30. data/lib/google/cloud/pubsub/subscriber/inventory.rb +173 -0
  31. data/lib/google/cloud/pubsub/subscriber/sequencer.rb +115 -0
  32. data/lib/google/cloud/pubsub/subscriber/stream.rb +400 -0
  33. data/lib/google/cloud/pubsub/subscriber/timed_unary_buffer.rb +230 -0
  34. data/lib/google/cloud/pubsub/subscriber.rb +417 -0
  35. data/lib/google/cloud/pubsub/subscription/list.rb +38 -43
  36. data/lib/google/cloud/pubsub/subscription/push_config.rb +268 -0
  37. data/lib/google/cloud/pubsub/subscription.rb +1040 -210
  38. data/lib/google/cloud/pubsub/topic/list.rb +32 -37
  39. data/lib/google/cloud/pubsub/topic.rb +726 -177
  40. data/lib/google/cloud/pubsub/version.rb +6 -4
  41. data/lib/google/cloud/pubsub.rb +138 -413
  42. data/lib/google-cloud-pubsub.rb +60 -42
  43. metadata +88 -39
  44. data/lib/google/cloud/pubsub/topic/publisher.rb +0 -87
  45. data/lib/google/iam/v1/iam_policy.rb +0 -33
  46. data/lib/google/iam/v1/iam_policy_services.rb +0 -30
  47. data/lib/google/iam/v1/policy.rb +0 -25
  48. data/lib/google/pubsub/v1/pubsub_pb.rb +0 -129
  49. data/lib/google/pubsub/v1/pubsub_services_pb.rb +0 -117
@@ -0,0 +1,178 @@
1
+ # Copyright 2017 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require "delegate"
17
+
18
+ module Google
19
+ module Cloud
20
+ module PubSub
21
+ class Snapshot
22
+ ##
23
+ # Snapshot::List is a special case Array with additional values.
24
+ class List < DelegateClass(::Array)
25
+ ##
26
+ # If not empty, indicates that there are more snapshots
27
+ # that match the request and this value should be passed to
28
+ # the next {Google::Cloud::PubSub::Project#snapshots} to continue.
29
+ attr_accessor :token
30
+
31
+ ##
32
+ # @private Create a new Snapshot::List with an array of values.
33
+ def initialize arr = []
34
+ @prefix = nil
35
+ @token = nil
36
+ @max = nil
37
+ super arr
38
+ end
39
+
40
+ ##
41
+ # Whether there a next page of snapshots.
42
+ #
43
+ # @return [Boolean]
44
+ #
45
+ # @example
46
+ # require "google/cloud/pubsub"
47
+ #
48
+ # pubsub = Google::Cloud::PubSub.new
49
+ #
50
+ # snapshots = pubsub.snapshots
51
+ # if snapshots.next?
52
+ # next_snapshots = snapshots.next
53
+ # end
54
+ #
55
+ def next?
56
+ !token.nil?
57
+ end
58
+
59
+ ##
60
+ # Retrieve the next page of snapshots.
61
+ #
62
+ # @return [Snapshot::List]
63
+ #
64
+ # @example
65
+ # require "google/cloud/pubsub"
66
+ #
67
+ # pubsub = Google::Cloud::PubSub.new
68
+ #
69
+ # snapshots = pubsub.snapshots
70
+ # if snapshots.next?
71
+ # next_snapshots = snapshots.next
72
+ # end
73
+ #
74
+ def next
75
+ return nil unless next?
76
+ ensure_service!
77
+ next_snapshots
78
+ end
79
+
80
+ ##
81
+ # Retrieves remaining results by repeatedly invoking {#next} until
82
+ # {#next?} returns `false`. Calls the given block once for each
83
+ # result, which is passed as the argument to the block.
84
+ #
85
+ # An Enumerator is returned if no block is given.
86
+ #
87
+ # This method will make repeated API calls until all remaining results
88
+ # are retrieved. (Unlike `#each`, for example, which merely iterates
89
+ # over the results returned by a single API call.) Use with caution.
90
+ #
91
+ # @param [Integer] request_limit The upper limit of API requests to
92
+ # make to load all snapshots. Default is no limit.
93
+ # @yield [snapshot] The block for accessing each snapshot.
94
+ # @yieldparam [Snapshot] snapshot The snapshot object.
95
+ #
96
+ # @return [Enumerator]
97
+ #
98
+ # @example Iterating each snapshot by passing a block:
99
+ # require "google/cloud/pubsub"
100
+ #
101
+ # pubsub = Google::Cloud::PubSub.new
102
+ #
103
+ # snapshots = pubsub.snapshots
104
+ # snapshots.all do |snapshot|
105
+ # puts snapshot.name
106
+ # end
107
+ #
108
+ # @example Using the enumerator by not passing a block:
109
+ # require "google/cloud/pubsub"
110
+ #
111
+ # pubsub = Google::Cloud::PubSub.new
112
+ #
113
+ # snapshots = pubsub.snapshots
114
+ # all_names = snapshots.all.map do |snapshot|
115
+ # snapshot.name
116
+ # end
117
+ #
118
+ # @example Limit the number of API calls made:
119
+ # require "google/cloud/pubsub"
120
+ #
121
+ # pubsub = Google::Cloud::PubSub.new
122
+ #
123
+ # snapshots = pubsub.snapshots
124
+ # snapshots.all(request_limit: 10) do |snapshot|
125
+ # puts snapshot.name
126
+ # end
127
+ #
128
+ def all request_limit: nil, &block
129
+ request_limit = request_limit.to_i if request_limit
130
+ return enum_for :all, request_limit: request_limit unless block_given?
131
+ results = self
132
+ loop do
133
+ results.each(&block)
134
+ if request_limit
135
+ request_limit -= 1
136
+ break if request_limit.negative?
137
+ end
138
+ break unless results.next?
139
+ results = results.next
140
+ end
141
+ end
142
+
143
+ ##
144
+ # @private New Snapshots::List from a
145
+ # Google::Cloud::PubSub::V1::ListSnapshotsRequest object.
146
+ def self.from_grpc grpc_list, service, max = nil
147
+ subs = new(Array(grpc_list.snapshots).map do |grpc|
148
+ Snapshot.from_grpc grpc, service
149
+ end)
150
+ token = grpc_list.next_page_token
151
+ token = nil if token == "".freeze
152
+ subs.instance_variable_set :@token, token
153
+ subs.instance_variable_set :@service, service
154
+ subs.instance_variable_set :@max, max
155
+ subs
156
+ end
157
+
158
+ protected
159
+
160
+ ##
161
+ # @private Raise an error unless an active connection to the service
162
+ # is available.
163
+ def ensure_service!
164
+ raise "Must have active connection to service" unless @service
165
+ end
166
+
167
+ def next_snapshots
168
+ options = { prefix: @prefix, token: @token, max: @max }
169
+ grpc = @service.list_snapshots options
170
+ self.class.from_grpc grpc, @service, @max
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ Pubsub = PubSub unless const_defined? :Pubsub
177
+ end
178
+ end
@@ -0,0 +1,205 @@
1
+ # Copyright 2017 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require "google/cloud/errors"
17
+ require "google/cloud/pubsub/snapshot/list"
18
+ require "google/cloud/pubsub/v1"
19
+
20
+ module Google
21
+ module Cloud
22
+ module PubSub
23
+ ##
24
+ # # Snapshot
25
+ #
26
+ # A named resource created from a subscription to retain a stream of
27
+ # messages from a topic. A snapshot is guaranteed to retain:
28
+ #
29
+ # * The existing backlog on the subscription. More precisely, this is
30
+ # defined as the messages in the subscription's backlog that are
31
+ # unacknowledged upon the successful completion of the
32
+ # `create_snapshot` operation; as well as:
33
+ # * Any messages published to the subscription's topic following the
34
+ # successful completion of the `create_snapshot` operation.
35
+ #
36
+ # @example
37
+ # require "google/cloud/pubsub"
38
+ #
39
+ # pubsub = Google::Cloud::PubSub.new
40
+ # sub = pubsub.subscription "my-sub"
41
+ #
42
+ # snapshot = sub.create_snapshot "my-snapshot"
43
+ # snapshot.name #=> "projects/my-project/snapshots/my-snapshot"
44
+ #
45
+ class Snapshot
46
+ ##
47
+ # @private The Service object.
48
+ attr_accessor :service
49
+
50
+ ##
51
+ # @private The gRPC Google::Cloud::PubSub::V1::Snapshot object.
52
+ attr_accessor :grpc
53
+
54
+ ##
55
+ # @private Create an empty {Snapshot} object.
56
+ def initialize
57
+ @service = nil
58
+ @grpc = Google::Cloud::PubSub::V1::Snapshot.new
59
+ end
60
+
61
+ ##
62
+ # The name of the snapshot.
63
+ #
64
+ # @return [String] A fully-qualified snapshot name in the form
65
+ # `projects/{project_id}/snapshots/{snapshot_id}`.
66
+ def name
67
+ @grpc.name
68
+ end
69
+
70
+ ##
71
+ # The {Topic} from which this snapshot is retaining messages.
72
+ #
73
+ # @return [Topic]
74
+ #
75
+ # @example
76
+ # require "google/cloud/pubsub"
77
+ #
78
+ # pubsub = Google::Cloud::PubSub.new
79
+ # sub = pubsub.subscription "my-sub"
80
+ #
81
+ # snapshot = sub.create_snapshot "my-snapshot"
82
+ # snapshot.topic.name #=> "projects/my-project/topics/my-topic"
83
+ #
84
+ def topic
85
+ Topic.from_name @grpc.topic, service
86
+ end
87
+
88
+ ##
89
+ # The snapshot is guaranteed to exist up until this time.
90
+ # A newly-created snapshot expires no later than 7 days from the time of
91
+ # its creation. Its exact lifetime is determined at creation by the
92
+ # existing backlog in the source subscription. Specifically, the
93
+ # lifetime of the snapshot is 7 days - (age of oldest unacked message in
94
+ # the subscription). For example, consider a subscription whose oldest
95
+ # unacked message is 3 days old. If a snapshot is created from this
96
+ # subscription, the snapshot -- which will always capture this 3-day-old
97
+ # backlog as long as the snapshot exists -- will expire in 4 days.
98
+ #
99
+ # @return [Time] The time until which the snapshot is guaranteed to
100
+ # exist.
101
+ #
102
+ # @example
103
+ # require "google/cloud/pubsub"
104
+ #
105
+ # pubsub = Google::Cloud::PubSub.new
106
+ # sub = pubsub.subscription "my-sub"
107
+ #
108
+ # snapshot = sub.create_snapshot "my-snapshot"
109
+ # snapshot.topic.name #=> "projects/my-project/topics/my-topic"
110
+ # snapshot.expiration_time
111
+ #
112
+ def expiration_time
113
+ self.class.timestamp_from_grpc @grpc.expire_time
114
+ end
115
+
116
+ ##
117
+ # A hash of user-provided labels associated with this snapshot.
118
+ # Labels can be used to organize and group snapshots.See [Creating and
119
+ # Managing Labels](https://cloud.google.com/pubsub/docs/labels).
120
+ #
121
+ # The returned hash is frozen and changes are not allowed. Use
122
+ # {#labels=} to update the labels for this snapshot.
123
+ #
124
+ # @return [Hash] The frozen labels hash.
125
+ #
126
+ def labels
127
+ @grpc.labels.to_h.freeze
128
+ end
129
+
130
+ ##
131
+ # Sets the hash of user-provided labels associated with this
132
+ # snapshot. Labels can be used to organize and group snapshots.
133
+ # Label keys and values can be no longer than 63 characters, can only
134
+ # contain lowercase letters, numeric characters, underscores and dashes.
135
+ # International characters are allowed. Label values are optional. Label
136
+ # keys must start with a letter and each label in the list must have a
137
+ # different key. See [Creating and Managing
138
+ # Labels](https://cloud.google.com/pubsub/docs/labels).
139
+ #
140
+ # @param [Hash] new_labels The new labels hash.
141
+ #
142
+ def labels= new_labels
143
+ raise ArgumentError, "Value must be a Hash" if new_labels.nil?
144
+ labels_map = Google::Protobuf::Map.new :string, :string
145
+ Hash(new_labels).each { |k, v| labels_map[String(k)] = String(v) }
146
+ update_grpc = @grpc.dup
147
+ update_grpc.labels = labels_map
148
+ @grpc = service.update_snapshot update_grpc, :labels
149
+ end
150
+
151
+ ##
152
+ # Removes an existing snapshot. All messages retained in the snapshot
153
+ # are immediately dropped. After a snapshot is deleted, a new one may be
154
+ # created with the same name, but the new one has no association with
155
+ # the old snapshot or its subscription, unless the same subscription is
156
+ # specified.
157
+ #
158
+ # @return [Boolean] Returns `true` if the snapshot was deleted.
159
+ #
160
+ # @example
161
+ # require "google/cloud/pubsub"
162
+ #
163
+ # pubsub = Google::Cloud::PubSub.new
164
+ #
165
+ # pubsub.snapshots.each do |snapshot|
166
+ # snapshot.delete
167
+ # end
168
+ #
169
+ def delete
170
+ ensure_service!
171
+ service.delete_snapshot name
172
+ true
173
+ end
174
+
175
+ ##
176
+ # @private New Snapshot from a Google::Cloud::PubSub::V1::Snapshot
177
+ # object.
178
+ def self.from_grpc grpc, service
179
+ new.tap do |f|
180
+ f.grpc = grpc
181
+ f.service = service
182
+ end
183
+ end
184
+
185
+ ##
186
+ # @private Get a Time object from a Google::Protobuf::Timestamp object.
187
+ def self.timestamp_from_grpc grpc_timestamp
188
+ return nil if grpc_timestamp.nil?
189
+ Time.at grpc_timestamp.seconds, Rational(grpc_timestamp.nanos, 1000)
190
+ end
191
+
192
+ protected
193
+
194
+ ##
195
+ # @private Raise an error unless an active connection to the service is
196
+ # available.
197
+ def ensure_service!
198
+ raise "Must have active connection to service" unless service
199
+ end
200
+ end
201
+ end
202
+
203
+ Pubsub = PubSub unless const_defined? :Pubsub
204
+ end
205
+ end
@@ -0,0 +1,54 @@
1
+ # Copyright 2017 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ module Google
17
+ module Cloud
18
+ module PubSub
19
+ class Subscriber
20
+ # @private
21
+ class EnumeratorQueue
22
+ def initialize sentinel = nil
23
+ @queue = Queue.new
24
+ @sentinel = sentinel
25
+ end
26
+
27
+ def push obj
28
+ @queue.push obj
29
+ end
30
+
31
+ def quit_and_dump_queue
32
+ objs = []
33
+ objs << @queue.pop until @queue.empty?
34
+ # Signal that the enumerator is ready to end
35
+ @queue.push @sentinel
36
+ objs
37
+ end
38
+
39
+ def each
40
+ return enum_for :each unless block_given?
41
+
42
+ loop do
43
+ obj = @queue.pop
44
+ break if obj.equal? @sentinel
45
+ yield obj
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ Pubsub = PubSub unless const_defined? :Pubsub
53
+ end
54
+ end
@@ -0,0 +1,173 @@
1
+ # Copyright 2017 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require "monitor"
17
+
18
+ module Google
19
+ module Cloud
20
+ module PubSub
21
+ class Subscriber
22
+ ##
23
+ # @private
24
+ class Inventory
25
+ InventoryItem = Struct.new :bytesize, :pulled_at do
26
+ def self.from rec_msg
27
+ new rec_msg.to_proto.bytesize, Time.now
28
+ end
29
+ end
30
+
31
+ include MonitorMixin
32
+
33
+ attr_reader :stream
34
+ attr_reader :limit
35
+ attr_reader :bytesize
36
+ attr_reader :extension
37
+ attr_reader :max_duration_per_lease_extension
38
+ attr_reader :use_legacy_flow_control
39
+
40
+ def initialize stream, limit:, bytesize:, extension:, max_duration_per_lease_extension:,
41
+ use_legacy_flow_control:
42
+ super()
43
+ @stream = stream
44
+ @limit = limit
45
+ @bytesize = bytesize
46
+ @extension = extension
47
+ @max_duration_per_lease_extension = max_duration_per_lease_extension
48
+ @use_legacy_flow_control = use_legacy_flow_control
49
+ @inventory = {}
50
+ @wait_cond = new_cond
51
+ end
52
+
53
+ def ack_ids
54
+ @inventory.keys
55
+ end
56
+
57
+ def add *rec_msgs
58
+ rec_msgs.flatten!
59
+ rec_msgs.compact!
60
+ return if rec_msgs.empty?
61
+
62
+ synchronize do
63
+ rec_msgs.each do |rec_msg|
64
+ @inventory[rec_msg.ack_id] = InventoryItem.from rec_msg
65
+ end
66
+ @wait_cond.broadcast
67
+ end
68
+ end
69
+
70
+ def remove *ack_ids
71
+ ack_ids.flatten!
72
+ ack_ids.compact!
73
+ return if ack_ids.empty?
74
+
75
+ synchronize do
76
+ @inventory.delete_if { |ack_id, _| ack_ids.include? ack_id }
77
+ @wait_cond.broadcast
78
+ end
79
+ end
80
+
81
+ def remove_expired!
82
+ synchronize do
83
+ extension_time = Time.new - extension
84
+ @inventory.delete_if { |_ack_id, item| item.pulled_at < extension_time }
85
+ @wait_cond.broadcast
86
+ end
87
+ end
88
+
89
+ def count
90
+ synchronize do
91
+ @inventory.count
92
+ end
93
+ end
94
+
95
+ def total_bytesize
96
+ synchronize do
97
+ @inventory.values.sum(&:bytesize)
98
+ end
99
+ end
100
+
101
+ def empty?
102
+ synchronize do
103
+ @inventory.empty?
104
+ end
105
+ end
106
+
107
+ def start
108
+ @background_thread ||= Thread.new { background_run }
109
+
110
+ self
111
+ end
112
+
113
+ def stop
114
+ synchronize do
115
+ @stopped = true
116
+ @wait_cond.broadcast
117
+ end
118
+
119
+ self
120
+ end
121
+
122
+ def stopped?
123
+ synchronize { @stopped }
124
+ end
125
+
126
+ def full?
127
+ synchronize do
128
+ @inventory.count >= limit || @inventory.values.sum(&:bytesize) >= bytesize
129
+ end
130
+ end
131
+
132
+ protected
133
+
134
+ def background_run
135
+ delay_target = nil
136
+
137
+ until stopped?
138
+ if empty?
139
+ delay_target = nil
140
+
141
+ synchronize { @wait_cond.wait } # wait until broadcast
142
+ next
143
+ end
144
+
145
+ delay_target ||= calc_target
146
+ delay_gap = delay_target - Time.now
147
+
148
+ unless delay_gap.positive?
149
+ delay_target = calc_target
150
+ stream.renew_lease!
151
+ next
152
+ end
153
+
154
+ synchronize { @wait_cond.wait delay_gap }
155
+ end
156
+ end
157
+
158
+ def calc_target
159
+ Time.now + calc_delay
160
+ end
161
+
162
+ def calc_delay
163
+ delay = (stream.subscriber.deadline - 3) * rand(0.8..0.9)
164
+ delay = [delay, max_duration_per_lease_extension].min if max_duration_per_lease_extension.positive?
165
+ delay
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ Pubsub = PubSub unless const_defined? :Pubsub
172
+ end
173
+ end