google-cloud-pubsub 0.24.0 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.