google-cloud-pubsub 0.24.0 → 0.25.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,165 @@
1
+ # Copyright 2017 Google Inc. All rights reserved.
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
+ # http://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
+
19
+ module Google
20
+ module Cloud
21
+ module Pubsub
22
+ ##
23
+ # # Snapshot
24
+ #
25
+ # A named resource created from a subscription to retain a stream of
26
+ # messages from a topic. A snapshot is guaranteed to retain:
27
+ #
28
+ # * The existing backlog on the subscription. More precisely, this is
29
+ # defined as the messages in the subscription's backlog that are
30
+ # unacknowledged upon the successful completion of the
31
+ # `create_snapshot` operation; as well as:
32
+ # * Any messages published to the subscription's topic following the
33
+ # successful completion of the `create_snapshot` operation.
34
+ #
35
+ # @example
36
+ # require "google/cloud/pubsub"
37
+ #
38
+ # pubsub = Google::Cloud::Pubsub.new
39
+ # sub = pubsub.subscription "my-sub"
40
+ #
41
+ # snapshot = sub.create_snapshot "my-snapshot"
42
+ # snapshot.name #=> "projects/my-project/snapshots/my-snapshot"
43
+ #
44
+ class Snapshot
45
+ ##
46
+ # @private The Service object.
47
+ attr_accessor :service
48
+
49
+ ##
50
+ # @private The gRPC Google::Pubsub::V1::Snapshot object.
51
+ attr_accessor :grpc
52
+
53
+ ##
54
+ # @private Create an empty {Snapshot} object.
55
+ def initialize
56
+ @service = nil
57
+ @grpc = Google::Pubsub::V1::Snapshot.new
58
+ end
59
+
60
+ ##
61
+ # The name of the snapshot. Format is
62
+ # `projects/{project}/snapshots/{snap}`.
63
+ def name
64
+ @grpc.name
65
+ end
66
+
67
+ ##
68
+ # The {Topic} from which this snapshot is retaining messages.
69
+ #
70
+ # @return [Topic]
71
+ #
72
+ # @example
73
+ # require "google/cloud/pubsub"
74
+ #
75
+ # pubsub = Google::Cloud::Pubsub.new
76
+ # sub = pubsub.subscription "my-sub"
77
+ #
78
+ # snapshot = sub.create_snapshot "my-snapshot"
79
+ # snapshot.topic.name #=> "projects/my-project/topics/my-topic"
80
+ #
81
+ def topic
82
+ Topic.new_lazy @grpc.topic, service
83
+ end
84
+
85
+ ##
86
+ # The snapshot is guaranteed to exist up until this time.
87
+ # A newly-created snapshot expires no later than 7 days from the time of
88
+ # its creation. Its exact lifetime is determined at creation by the
89
+ # existing backlog in the source subscription. Specifically, the
90
+ # lifetime of the snapshot is 7 days - (age of oldest unacked message in
91
+ # the subscription). For example, consider a subscription whose oldest
92
+ # unacked message is 3 days old. If a snapshot is created from this
93
+ # subscription, the snapshot -- which will always capture this 3-day-old
94
+ # backlog as long as the snapshot exists -- will expire in 4 days.
95
+ #
96
+ # @return [Time] The time until which the snapshot is guaranteed to
97
+ # exist.
98
+ #
99
+ # @example
100
+ # require "google/cloud/pubsub"
101
+ #
102
+ # pubsub = Google::Cloud::Pubsub.new
103
+ # sub = pubsub.subscription "my-sub"
104
+ #
105
+ # snapshot = sub.create_snapshot "my-snapshot"
106
+ # snapshot.topic.name #=> "projects/my-project/topics/my-topic"
107
+ # snapshot.expiration_time
108
+ #
109
+ def expiration_time
110
+ self.class.timestamp_from_grpc @grpc.expiration_time
111
+ end
112
+
113
+ ##
114
+ # Removes an existing snapshot. All messages retained in the snapshot
115
+ # are immediately dropped. After a snapshot is deleted, a new one may be
116
+ # created with the same name, but the new one has no association with
117
+ # the old snapshot or its subscription, unless the same subscription is
118
+ # specified.
119
+ #
120
+ # @return [Boolean] Returns `true` if the snapshot was deleted.
121
+ #
122
+ # @example
123
+ # require "google/cloud/pubsub"
124
+ #
125
+ # pubsub = Google::Cloud::Pubsub.new
126
+ #
127
+ # pubsub.snapshots.each do |snapshot|
128
+ # snapshot.delete
129
+ # end
130
+ #
131
+ def delete
132
+ ensure_service!
133
+ service.delete_snapshot name
134
+ true
135
+ end
136
+
137
+ ##
138
+ # @private New Snapshot from a Google::Pubsub::V1::Snapshot
139
+ # object.
140
+ def self.from_grpc grpc, service
141
+ new.tap do |f|
142
+ f.grpc = grpc
143
+ f.service = service
144
+ end
145
+ end
146
+
147
+ ##
148
+ # @private Get a Time object from a Google::Protobuf::Timestamp object.
149
+ def self.timestamp_from_grpc grpc_timestamp
150
+ return nil if grpc_timestamp.nil?
151
+ Time.at grpc_timestamp.seconds, Rational(grpc_timestamp.nanos, 1000)
152
+ end
153
+
154
+ protected
155
+
156
+ ##
157
+ # @private Raise an error unless an active connection to the service is
158
+ # available.
159
+ def ensure_service!
160
+ fail "Must have active connection to service" unless service
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,178 @@
1
+ # Copyright 2017 Google Inc. All rights reserved.
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
+ # http://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
129
+ request_limit = request_limit.to_i if request_limit
130
+ unless block_given?
131
+ return enum_for(:all, request_limit: request_limit)
132
+ end
133
+ results = self
134
+ loop do
135
+ results.each { |r| yield r }
136
+ if request_limit
137
+ request_limit -= 1
138
+ break if request_limit < 0
139
+ end
140
+ break unless results.next?
141
+ results = results.next
142
+ end
143
+ end
144
+
145
+ ##
146
+ # @private New Snapshots::List from a
147
+ # Google::Pubsub::V1::ListSnapshotsRequest object.
148
+ def self.from_grpc grpc_list, service, max = nil
149
+ subs = new(Array(grpc_list.snapshots).map do |grpc|
150
+ Snapshot.from_grpc grpc, service
151
+ end)
152
+ token = grpc_list.next_page_token
153
+ token = nil if token == ""
154
+ subs.instance_variable_set "@token", token
155
+ subs.instance_variable_set "@service", service
156
+ subs.instance_variable_set "@max", max
157
+ subs
158
+ end
159
+
160
+ protected
161
+
162
+ ##
163
+ # @private Raise an error unless an active connection to the service
164
+ # is available.
165
+ def ensure_service!
166
+ fail "Must have active connection to service" unless @service
167
+ end
168
+
169
+ def next_snapshots
170
+ options = { prefix: @prefix, token: @token, max: @max }
171
+ grpc = @service.list_snapshots options
172
+ self.class.from_grpc grpc, @service, @max
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
@@ -16,6 +16,7 @@
16
16
  require "google/cloud/errors"
17
17
  require "google/cloud/pubsub/subscription/list"
18
18
  require "google/cloud/pubsub/received_message"
19
+ require "google/cloud/pubsub/snapshot"
19
20
 
20
21
  module Google
21
22
  module Cloud
@@ -97,6 +98,36 @@ module Google
97
98
  @grpc.ack_deadline_seconds
98
99
  end
99
100
 
101
+ ##
102
+ # Indicates whether to retain acknowledged messages. If `true`, then
103
+ # messages are not expunged from the subscription's backlog, even if
104
+ # they are acknowledged, until they fall out of the
105
+ # {#retention_duration} window. Default is `false`.
106
+ #
107
+ # @return [Boolean] Returns `true` if acknowledged messages are
108
+ # retained.
109
+ #
110
+ def retain_acked
111
+ ensure_grpc!
112
+ @grpc.retain_acked_messages
113
+ end
114
+
115
+ ##
116
+ # How long to retain unacknowledged messages in the subscription's
117
+ # backlog, from the moment a message is published. If
118
+ # {#retain_acked} is `true`, then this also configures the retention of
119
+ # acknowledged messages, and thus configures how far back in time a
120
+ # {#seek} can be done. Cannot be more than 604,800 seconds (7 days) or
121
+ # less than 600 seconds (10 minutes). Default is 604,800 seconds (7
122
+ # days).
123
+ #
124
+ # @return [Numeric] The message retention duration in seconds.
125
+ #
126
+ def retention
127
+ ensure_grpc!
128
+ duration_to_number @grpc.message_retention_duration
129
+ end
130
+
100
131
  ##
101
132
  # Returns the URL locating the endpoint to which messages should be
102
133
  # pushed.
@@ -207,8 +238,8 @@ module Google
207
238
  #
208
239
  # pubsub = Google::Cloud::Pubsub.new
209
240
  #
210
- # sub = pubsub.subscription "my-topic-sub", max: 10
211
- # sub.pull.each { |msg| msg.acknowledge! }
241
+ # sub = pubsub.subscription "my-topic-sub"
242
+ # sub.pull(max: 10).each { |msg| msg.acknowledge! }
212
243
  #
213
244
  # @example The call can block until messages are available:
214
245
  # require "google/cloud/pubsub"
@@ -376,6 +407,105 @@ module Google
376
407
  true
377
408
  end
378
409
 
410
+ ##
411
+ # Creates a new {Snapshot} from the subscription. The created snapshot
412
+ # is guaranteed to retain:
413
+ #
414
+ # * The existing backlog on the subscription. More precisely, this is
415
+ # defined as the messages in the subscription's backlog that are
416
+ # unacknowledged upon the successful completion of the
417
+ # `create_snapshot` operation; as well as:
418
+ # * Any messages published to the subscription's topic following the
419
+ # successful completion of the `create_snapshot` operation.
420
+ #
421
+ # @param [String, nil] snapshot_name Name of the new snapshot. If the
422
+ # name is not provided, the server will assign a random name
423
+ # for this snapshot on the same project as the subscription. The
424
+ # format is `projects/{project}/snapshots/{snap}`. The name must start
425
+ # with a letter, and contain only letters ([A-Za-z]), numbers
426
+ # ([0-9], dashes (-), underscores (_), periods (.), tildes (~), plus
427
+ # (+) or percent signs (%). It must be between 3 and 255 characters in
428
+ # length, and it must not start with "goog". Optional.
429
+ #
430
+ # @return [Google::Cloud::Pubsub::Snapshot]
431
+ #
432
+ # @example
433
+ # require "google/cloud/pubsub"
434
+ #
435
+ # pubsub = Google::Cloud::Pubsub.new
436
+ # sub = pubsub.subscription "my-sub"
437
+ #
438
+ # snapshot = sub.create_snapshot "my-snapshot"
439
+ # snapshot.name #=> "projects/my-project/snapshots/my-snapshot"
440
+ #
441
+ # @example Without providing a name:
442
+ # require "google/cloud/pubsub"
443
+ #
444
+ # pubsub = Google::Cloud::Pubsub.new
445
+ # sub = pubsub.subscription "my-sub"
446
+ #
447
+ # snapshot = sub.create_snapshot
448
+ # snapshot.name #=> "projects/my-project/snapshots/gcr-analysis-..."
449
+ #
450
+ def create_snapshot snapshot_name = nil
451
+ ensure_service!
452
+ grpc = service.create_snapshot name, snapshot_name
453
+ Snapshot.from_grpc grpc, service
454
+ end
455
+ alias_method :new_snapshot, :create_snapshot
456
+
457
+ ##
458
+ # Resets the subscription's backlog to a given {Snapshot} or to a point
459
+ # in time, whichever is provided in the request.
460
+ #
461
+ # @param [Snapshot, String, Time] snapshot The `Snapshot` instance,
462
+ # snapshot name, or time to which to perform the seek.
463
+ # If the argument is a snapshot, the snapshot's topic must be the
464
+ # same as that of the subscription. If it is a time, messages retained
465
+ # in the subscription that were published before this time are marked
466
+ # as acknowledged, and messages retained in the subscription that were
467
+ # published after this time are marked as unacknowledged. Note that
468
+ # this operation affects only those messages retained in the
469
+ # subscription. For example, if the time corresponds to a point before
470
+ # the message retention window (or to a point before the system's
471
+ # notion of the subscription creation time), only retained messages
472
+ # will be marked as unacknowledged, and already-expunged messages will
473
+ # not be restored.
474
+ #
475
+ # @return [Boolean] Returns `true` if the seek was successful.
476
+ #
477
+ # @example Using a snapshot
478
+ # require "google/cloud/pubsub"
479
+ #
480
+ # pubsub = Google::Cloud::Pubsub.new
481
+ # sub = pubsub.subscription "my-sub"
482
+ #
483
+ # snapshot = sub.create_snapshot
484
+ #
485
+ # messages = sub.pull
486
+ # sub.acknowledge messages
487
+ #
488
+ # sub.seek snapshot
489
+ #
490
+ # @example Using a time:
491
+ # require "google/cloud/pubsub"
492
+ #
493
+ # pubsub = Google::Cloud::Pubsub.new
494
+ # sub = pubsub.subscription "my-sub"
495
+ #
496
+ # time = Time.now
497
+ #
498
+ # messages = sub.pull
499
+ # sub.acknowledge messages
500
+ #
501
+ # sub.seek time
502
+ #
503
+ def seek snapshot
504
+ ensure_service!
505
+ service.seek name, snapshot
506
+ true
507
+ end
508
+
379
509
  ##
380
510
  # Gets the [Cloud IAM](https://cloud.google.com/iam/) access control
381
511
  # policy for this subscription.
@@ -383,11 +513,6 @@ module Google
383
513
  # @see https://cloud.google.com/pubsub/docs/reference/rpc/google.iam.v1#iampolicy
384
514
  # google.iam.v1.IAMPolicy
385
515
  #
386
- # @param [Boolean] force Force the latest policy to be retrieved from
387
- # the Pub/Sub service when `true`. Otherwise the policy will be
388
- # memoized to reduce the number of API calls made to the Pub/Sub
389
- # service. The default is `false`.
390
- #
391
516
  # @yield [policy] A block for updating the policy. The latest policy
392
517
  # will be read from the Pub/Sub service and passed to the block. After
393
518
  # the block completes, the modified policy will be written to the
@@ -397,23 +522,13 @@ module Google
397
522
  #
398
523
  # @return [Policy] the current Cloud IAM Policy for this subscription
399
524
  #
400
- # @example Policy values are memoized to reduce the number of API calls:
401
- # require "google/cloud/pubsub"
402
- #
403
- # pubsub = Google::Cloud::Pubsub.new
404
- # sub = pubsub.subscription "my-subscription"
405
- #
406
- # policy = sub.policy # API call
407
- # policy_2 = sub.policy # No API call
408
- #
409
- # @example Use `force` to retrieve the latest policy from the service:
525
+ # @example
410
526
  # require "google/cloud/pubsub"
411
527
  #
412
528
  # pubsub = Google::Cloud::Pubsub.new
413
529
  # sub = pubsub.subscription "my-subscription"
414
530
  #
415
- # policy = sub.policy force: true # API call
416
- # policy_2 = sub.policy force: true # API call
531
+ # policy = sub.policy
417
532
  #
418
533
  # @example Update the policy by passing a block:
419
534
  # require "google/cloud/pubsub"
@@ -421,21 +536,17 @@ module Google
421
536
  # pubsub = Google::Cloud::Pubsub.new
422
537
  # sub = pubsub.subscription "my-subscription"
423
538
  #
424
- # policy = sub.policy do |p|
539
+ # sub.policy do |p|
425
540
  # p.add "roles/owner", "user:owner@example.com"
426
- # end # 2 API calls
427
- #
428
- def policy force: nil
429
- @policy = nil if force || block_given?
430
- @policy ||= begin
431
- ensure_service!
432
- grpc = service.get_subscription_policy name
433
- Policy.from_grpc grpc
434
- end
435
- return @policy unless block_given?
436
- p = @policy.deep_dup
437
- yield p
438
- self.policy = p
541
+ # end
542
+ #
543
+ def policy
544
+ ensure_service!
545
+ grpc = service.get_subscription_policy name
546
+ policy = Policy.from_grpc grpc
547
+ return policy unless block_given?
548
+ yield policy
549
+ self.policy = policy
439
550
  end
440
551
 
441
552
  ##
@@ -453,6 +564,8 @@ module Google
453
564
  # @param [Policy] new_policy a new or modified Cloud IAM Policy for this
454
565
  # subscription
455
566
  #
567
+ # @return [Policy] the policy returned by the API update operation
568
+ #
456
569
  # @example
457
570
  # require "google/cloud/pubsub"
458
571
  #
@@ -468,7 +581,7 @@ module Google
468
581
  def policy= new_policy
469
582
  ensure_service!
470
583
  grpc = service.set_subscription_policy name, new_policy.to_grpc
471
- @policy = Policy.from_grpc grpc
584
+ Policy.from_grpc grpc
472
585
  end
473
586
 
474
587
  ##
@@ -522,6 +635,14 @@ module Google
522
635
 
523
636
  protected
524
637
 
638
+ def duration_to_number duration
639
+ return nil if duration.nil?
640
+
641
+ return duration.seconds if duration.nanos == 0
642
+
643
+ duration.seconds + (duration.nanos / 1000000000.0)
644
+ end
645
+
525
646
  ##
526
647
  # @private Raise an error unless an active connection to the service is
527
648
  # available.