gcpc 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5fdb3019e64a9e547b7fb58a1a5ebf45b82020029f047dc2f7fcaa237d720093
4
- data.tar.gz: 02a5b5b94f4bed91f1d49bd8c8bf0f97fa568b02bd05d543205b482c9fa47570
3
+ metadata.gz: d89748f1a7066c40f0b4c6c4477bab098ab45c206ca7f019d5f29f13be62c875
4
+ data.tar.gz: 76261a92198cd9e53629455aba3859117e649004838da3752ead8dbbe8445f14
5
5
  SHA512:
6
- metadata.gz: ff644c9d6d8257aa128e940547a31db1a9190e6a8165bf6ad0e776c3cc6aef00ed22f68f98812fa938186ea0cba069fb2d53c29e478ea5ec92a6de7b7bac5d5d
7
- data.tar.gz: c50b8e7e95f3c1651c0ecfdb6ef85e16ba4503eced5a74331eb6173ad2ebe87f5475287097b5ab3912ae20d0989e5462ab4578b0e866f4211843cb1b70f69bdc
6
+ metadata.gz: fdf792b95470615cc0e9967dab7efaccde16aa62a60dbde2c0c0728df37e13d51cc3f046585152fde3a528032ebe39b59fee8a05e0f86680ffafb37bfd4b5350
7
+ data.tar.gz: 77b9b3d6f3a61bfeef13b4094363aa98c1a91679dd532712753061abc761d4a13e31696b7036b9d84c9b78a9b6cd3e055b896923624859d8a82cf4693af2762b
@@ -0,0 +1,24 @@
1
+ name: test
2
+
3
+ on:
4
+ push:
5
+
6
+ jobs:
7
+ test:
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ matrix:
11
+ ruby-version: ['3.2', '3.1', '3.0']
12
+ steps:
13
+ - uses: actions/checkout@v3
14
+ - name: Set up Ruby ${{ matrix.ruby-version }}
15
+ uses: ruby/setup-ruby@v1
16
+ with:
17
+ ruby-version: ${{ matrix.ruby-version }}
18
+ bundler-cache: true
19
+ - name: Run rspec
20
+ run: bundle exec rspec
21
+ - name: run pubsub emulator
22
+ run: docker run -d -p 8085:8085 -it gcr.io/google.com/cloudsdktool/google-cloud-cli:latest gcloud beta emulators pubsub start --host-port=0.0.0.0:8085
23
+ - name: Run rspec with emulator
24
+ run: bundle exec rspec --tag emulator
data/CHANGELOG.md CHANGED
@@ -4,16 +4,20 @@
4
4
  <!-- All changes (implementation, or doc changes) are worth noting. -->
5
5
  <!-- The changes listed above will go below when a new release is being prepared. -->
6
6
 
7
+ ## 0.0.8
8
+
9
+ - Add an API for heartbeat https://github.com/wantedly/gcpc/pull/25
10
+
7
11
  ## 0.0.7
8
12
 
9
- - Add explicit loading of forwardable https://github.com/south37/gcpc/pull/10
10
- - Add ruby 2.7 as a test target https://github.com/south37/gcpc/pull/12
13
+ - Add explicit loading of forwardable https://github.com/wantedly/gcpc/pull/10
14
+ - Add ruby 2.7 as a test target https://github.com/wantedly/gcpc/pull/12
11
15
 
12
16
  ## 0.0.6
13
17
 
14
- - Add test of interceptors https://github.com/south37/gcpc/pull/7
15
- - Add publish_batch https://github.com/south37/gcpc/pull/6
18
+ - Add test of interceptors https://github.com/wantedly/gcpc/pull/7
19
+ - Add publish_batch https://github.com/wantedly/gcpc/pull/6
16
20
 
17
21
  ## 0.0.5
18
22
 
19
- - Add publish_async https://github.com/south37/gcpc/pull/5
23
+ - Add publish_async https://github.com/wantedly/gcpc/pull/5
data/Gemfile.lock CHANGED
@@ -1,74 +1,82 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gcpc (0.0.7)
4
+ gcpc (0.0.8)
5
5
  google-cloud-pubsub
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- addressable (2.7.0)
11
- public_suffix (>= 2.0.2, < 5.0)
10
+ addressable (2.8.5)
11
+ public_suffix (>= 2.0.2, < 6.0)
12
12
  coderay (1.1.3)
13
- concurrent-ruby (1.1.7)
13
+ concurrent-ruby (1.2.2)
14
14
  diff-lcs (1.3)
15
- faraday (1.3.0)
16
- faraday-net_http (~> 1.0)
17
- multipart-post (>= 1.2, < 3)
18
- ruby2_keywords
19
- faraday-net_http (1.0.0)
20
- gapic-common (0.3.4)
21
- google-protobuf (~> 3.12, >= 3.12.2)
22
- googleapis-common-protos (>= 1.3.9, < 2.0)
23
- googleapis-common-protos-types (>= 1.0.4, < 2.0)
24
- googleauth (~> 0.9)
25
- grpc (~> 1.25)
26
- google-cloud-core (1.5.0)
15
+ faraday (2.7.10)
16
+ faraday-net_http (>= 2.0, < 3.1)
17
+ ruby2_keywords (>= 0.0.4)
18
+ faraday-net_http (3.0.2)
19
+ faraday-retry (2.2.0)
20
+ faraday (~> 2.0)
21
+ gapic-common (0.19.1)
22
+ faraday (>= 1.9, < 3.a)
23
+ faraday-retry (>= 1.0, < 3.a)
24
+ google-protobuf (~> 3.14)
25
+ googleapis-common-protos (>= 1.3.12, < 2.a)
26
+ googleapis-common-protos-types (>= 1.3.1, < 2.a)
27
+ googleauth (~> 1.0)
28
+ grpc (~> 1.36)
29
+ google-cloud-core (1.6.0)
27
30
  google-cloud-env (~> 1.0)
28
31
  google-cloud-errors (~> 1.0)
29
- google-cloud-env (1.4.0)
30
- faraday (>= 0.17.3, < 2.0)
31
- google-cloud-errors (1.0.1)
32
- google-cloud-pubsub (2.3.0)
32
+ google-cloud-env (1.6.0)
33
+ faraday (>= 0.17.3, < 3.0)
34
+ google-cloud-errors (1.3.1)
35
+ google-cloud-pubsub (2.15.4)
33
36
  concurrent-ruby (~> 1.1)
34
37
  google-cloud-core (~> 1.5)
35
- google-cloud-pubsub-v1 (~> 0.0)
36
- google-cloud-pubsub-v1 (0.2.0)
37
- gapic-common (~> 0.3)
38
+ google-cloud-pubsub-v1 (~> 0.8)
39
+ retriable (~> 3.1)
40
+ google-cloud-pubsub-v1 (0.17.3)
41
+ gapic-common (>= 0.19.1, < 2.a)
38
42
  google-cloud-errors (~> 1.0)
39
- grpc-google-iam-v1 (>= 0.6.10, < 2.0)
40
- google-protobuf (3.14.0)
41
- googleapis-common-protos (1.3.10)
42
- google-protobuf (~> 3.11)
43
- googleapis-common-protos-types (>= 1.0.5, < 2.0)
43
+ google-iam-v1 (>= 0.4, < 2.a)
44
+ google-iam-v1 (0.5.2)
45
+ gapic-common (>= 0.19.1, < 2.a)
46
+ google-cloud-errors (~> 1.0)
47
+ grpc-google-iam-v1 (~> 1.1)
48
+ google-protobuf (3.23.4)
49
+ googleapis-common-protos (1.4.0)
50
+ google-protobuf (~> 3.14)
51
+ googleapis-common-protos-types (~> 1.2)
44
52
  grpc (~> 1.27)
45
- googleapis-common-protos-types (1.0.5)
46
- google-protobuf (~> 3.11)
47
- googleauth (0.14.0)
48
- faraday (>= 0.17.3, < 2.0)
53
+ googleapis-common-protos-types (1.8.0)
54
+ google-protobuf (~> 3.18)
55
+ googleauth (1.7.0)
56
+ faraday (>= 0.17.3, < 3.a)
49
57
  jwt (>= 1.4, < 3.0)
50
58
  memoist (~> 0.16)
51
59
  multi_json (~> 1.11)
52
60
  os (>= 0.9, < 2.0)
53
- signet (~> 0.14)
54
- grpc (1.34.0)
55
- google-protobuf (~> 3.13)
61
+ signet (>= 0.16, < 2.a)
62
+ grpc (1.56.2)
63
+ google-protobuf (~> 3.23)
56
64
  googleapis-common-protos-types (~> 1.0)
57
- grpc-google-iam-v1 (0.6.10)
58
- google-protobuf (~> 3.11)
59
- googleapis-common-protos (>= 1.3.10, < 2.0)
60
- grpc (~> 1.27)
61
- jwt (2.2.2)
65
+ grpc-google-iam-v1 (1.3.0)
66
+ google-protobuf (~> 3.18)
67
+ googleapis-common-protos (~> 1.4)
68
+ grpc (~> 1.41)
69
+ jwt (2.7.1)
62
70
  memoist (0.16.2)
63
71
  method_source (1.0.0)
64
72
  multi_json (1.15.0)
65
- multipart-post (2.1.1)
66
- os (1.1.1)
73
+ os (1.1.4)
67
74
  pry (0.13.1)
68
75
  coderay (~> 1.1)
69
76
  method_source (~> 1.0)
70
- public_suffix (4.0.6)
77
+ public_suffix (5.0.3)
71
78
  rake (13.0.1)
79
+ retriable (3.1.2)
72
80
  rspec (3.8.0)
73
81
  rspec-core (~> 3.8.0)
74
82
  rspec-expectations (~> 3.8.0)
@@ -82,10 +90,10 @@ GEM
82
90
  diff-lcs (>= 1.2.0, < 2.0)
83
91
  rspec-support (~> 3.8.0)
84
92
  rspec-support (3.8.0)
85
- ruby2_keywords (0.0.2)
86
- signet (0.14.0)
87
- addressable (~> 2.3)
88
- faraday (>= 0.17.3, < 2.0)
93
+ ruby2_keywords (0.0.5)
94
+ signet (0.17.0)
95
+ addressable (~> 2.8)
96
+ faraday (>= 0.17.5, < 3.a)
89
97
  jwt (>= 1.5, < 3.0)
90
98
  multi_json (~> 1.10)
91
99
 
data/README.md CHANGED
@@ -154,7 +154,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
154
154
 
155
155
  ## Contributing
156
156
 
157
- Bug reports and pull requests are welcome on GitHub at https://github.com/south37/gcpc.
157
+ Bug reports and pull requests are welcome on GitHub at https://github.com/wantedly/gcpc.
158
158
 
159
159
  ## License
160
160
 
data/gcpc.gemspec CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
 
12
12
  spec.summary = %q{Google Cloud Pub/Sub Client}
13
13
  spec.description = %q{Google Cloud Pub/Sub Client}
14
- spec.homepage = "https://github.com/south37/gcpc"
14
+ spec.homepage = "https://github.com/wantedly/gcpc"
15
15
  spec.license = "MIT"
16
16
 
17
17
  # Specify which files should be added to the gem when it is released.
@@ -0,0 +1,18 @@
1
+ require "singleton"
2
+
3
+ module Gcpc
4
+ class Config
5
+ include Singleton
6
+ attr_reader :beat
7
+
8
+ def initialize
9
+ @beat = []
10
+ end
11
+
12
+ def on(event, &block)
13
+ raise ArgumentError, "Invalid event name: #{event}" if event != :beat
14
+
15
+ @beat << block
16
+ end
17
+ end
18
+ end
@@ -4,6 +4,9 @@ module Gcpc
4
4
  class Subscriber
5
5
  class Engine
6
6
  WAIT_INTERVAL = 1
7
+ WORKER_DEAD_THRESHOLD = 30 # second
8
+ BEAT_INTERVAL = 10
9
+ HEART_BEAT_WORKER_NAME = 'heartbeat-worker'
7
10
 
8
11
  # @param [Google::Cloud::Pubsub::Subscription] subscription
9
12
  # @param [<#handle, #on_error>] interceptors
@@ -20,6 +23,9 @@ module Gcpc
20
23
  @interceptors = interceptors
21
24
  @ack_immediately = ack_immediately
22
25
  @logger = logger
26
+ @subscriber_thread_status = {}
27
+ @subscriber_thread_status_mutex = Mutex.new
28
+ @heartbeat_worker_thread = nil
23
29
 
24
30
  @subscriber = nil # @subscriber is created by calling `#run`
25
31
  @handler = nil # @handler must be registered by `#handle`
@@ -47,6 +53,8 @@ module Gcpc
47
53
 
48
54
  @logger.info("Started")
49
55
 
56
+ run_heartbeat_worker
57
+
50
58
  loop_until_receiving_signals(signals)
51
59
  end
52
60
 
@@ -64,6 +72,16 @@ module Gcpc
64
72
  @logger.info('Stopping, will wait for background threads to exit')
65
73
 
66
74
  @subscriber.stop
75
+
76
+ begin
77
+ @heartbeat_worker_thread&.wakeup
78
+ # ThreadError exeption will be raised when the thread already dead
79
+ rescue ThreadError => e
80
+ @logger.error(e.message)
81
+ end
82
+
83
+ @heartbeat_worker_thread&.join
84
+
67
85
  @subscriber.wait!
68
86
 
69
87
  @logger.info('Stopped, background threads are shutdown')
@@ -92,12 +110,51 @@ module Gcpc
92
110
  stop unless stopped?
93
111
  end
94
112
 
113
+ def run_heartbeat_worker
114
+ @heartbeat_worker_thread = Thread.new do
115
+ @logger.info("Starting heartbeat worker...")
116
+ begin
117
+ loop do
118
+ break if stopped?
119
+
120
+ next unless alive?
121
+
122
+ Gcpc::Config.instance.beat.each(&:call)
123
+
124
+ sleep BEAT_INTERVAL
125
+ end
126
+ ensure
127
+ @logger.info("heartbeat worker stopped")
128
+ end
129
+ end
130
+
131
+ @heartbeat_worker_thread.name = HEART_BEAT_WORKER_NAME
132
+ end
133
+
134
+ def alive?
135
+ # ・When processing a message, write the thread_id and timestamp at the start time into @subscriber_thread_status,
136
+ # and remove that information from @subscriber_thread_status when the processing within that thread is finished.
137
+ # @subscriber_thread_status = {#<Thread:0x000000010302cd40 run>=>1690757417}
138
+ # ・If the processing of the message gets stuck, the key, value will not be removed from @subscriber_thread_status.
139
+ # ・Since the application holds as many callback_threads as @subscriber.callback_threads with Subscription,
140
+ # if the number of threads that have gotten stuck exceeds that callback_threads, it is considered that the worker unable to process Subscription queue.
141
+ return false unless @subscriber && @subscriber.started?
142
+ return false if @subscriber.stopped?
143
+
144
+ number_of_dead_threads = @subscriber_thread_status.count { |_, v| v < Time.now.to_i - WORKER_DEAD_THRESHOLD }
145
+
146
+ return @subscriber.callback_threads > number_of_dead_threads
147
+ end
148
+
149
+
95
150
  # @param [Google::Cloud::Pubsub::ReceivedMessage] message
96
151
  def handle_message(message)
152
+ write_heartbeat_to_subscriber_thread_status
153
+
97
154
  ack(message) if @ack_immediately
98
155
 
99
156
  begin
100
- worker_info("Started hanlding message")
157
+ worker_info("Started handling message")
101
158
  @handler.handle(message)
102
159
  worker_info("Finished hanlding message successfully")
103
160
  rescue => e
@@ -110,11 +167,13 @@ module Gcpc
110
167
 
111
168
  def ack(message)
112
169
  message.ack!
170
+ cleanup_subscriber_thread_status
113
171
  worker_info("Acked message")
114
172
  end
115
173
 
116
174
  def nack(message)
117
175
  message.nack!
176
+ cleanup_subscriber_thread_status
118
177
  worker_info("Nacked message")
119
178
  end
120
179
 
@@ -139,6 +198,27 @@ module Gcpc
139
198
  def stopped?
140
199
  @stopped_mutex.synchronize { @stopped }
141
200
  end
201
+
202
+ def write_heartbeat_to_subscriber_thread_status
203
+ begin
204
+ @subscriber_thread_status_mutex.synchronize do
205
+ @subscriber_thread_status[Thread.current] = Time.now.to_i
206
+ end
207
+ rescue ThreadError => e
208
+ @logger.info("Falied to write subscriber_thread_status. thread_id: #{Thread.current.object_id}, subscriber_thread_status: #{@subscriber_thread_status}, error: #{e.message}")
209
+ end
210
+ end
211
+
212
+ def cleanup_subscriber_thread_status
213
+ begin
214
+ @subscriber_thread_status_mutex.synchronize do
215
+ # cleanup to avoid memory leak
216
+ @subscriber_thread_status.delete(Thread.current)
217
+ end
218
+ rescue ThreadError => e
219
+ @logger.info("Falied to cleanup subscriber_thread_status. thread_id: #{Thread.current.object_id}, subscriber_thread_status: #{@subscriber_thread_status}, error: #{e.message}")
220
+ end
221
+ end
142
222
  end
143
223
  end
144
224
  end
data/lib/gcpc/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Gcpc
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
data/lib/gcpc.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "gcpc/version"
2
2
  require "gcpc/publisher"
3
3
  require "gcpc/subscriber"
4
+ require "gcpc/config"
4
5
 
5
6
  module Gcpc
6
7
  end
data/renovate.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": [
3
+ "config:base"
4
+ ]
5
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gcpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nao Minami
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-12 00:00:00.000000000 Z
11
+ date: 2023-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -87,9 +87,9 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
+ - ".github/workflows/ci.yml"
90
91
  - ".gitignore"
91
92
  - ".rspec"
92
- - ".travis.yml"
93
93
  - CHANGELOG.md
94
94
  - Gemfile
95
95
  - Gemfile.lock
@@ -104,6 +104,7 @@ files:
104
104
  - examples/subscriber-example/subscriber-example.rb
105
105
  - gcpc.gemspec
106
106
  - lib/gcpc.rb
107
+ - lib/gcpc/config.rb
107
108
  - lib/gcpc/publisher.rb
108
109
  - lib/gcpc/publisher/base_interceptor.rb
109
110
  - lib/gcpc/publisher/engine.rb
@@ -118,7 +119,8 @@ files:
118
119
  - lib/gcpc/subscriber/handle_engine.rb
119
120
  - lib/gcpc/subscriber/subscription_client.rb
120
121
  - lib/gcpc/version.rb
121
- homepage: https://github.com/south37/gcpc
122
+ - renovate.json
123
+ homepage: https://github.com/wantedly/gcpc
122
124
  licenses:
123
125
  - MIT
124
126
  metadata: {}
@@ -137,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
139
  - !ruby/object:Gem::Version
138
140
  version: '0'
139
141
  requirements: []
140
- rubygems_version: 3.1.4
142
+ rubygems_version: 3.4.10
141
143
  signing_key:
142
144
  specification_version: 4
143
145
  summary: Google Cloud Pub/Sub Client
data/.travis.yml DELETED
@@ -1,21 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.6.6
7
- - 2.7.3
8
- before_install:
9
- - gem install bundler
10
- jobs:
11
- include:
12
- - name: 'test'
13
- script:
14
- - bundle exec rspec
15
- - name: 'test with a emulator'
16
- before_install:
17
- # Start a Cloud Pub/Sub emulator. See https://cloud.google.com/pubsub/docs/emulator
18
- # We use `google/cloud-sdk:321.0.0` because we can't start pubsub with the latest.
19
- - docker run -d -p 8085:8085 -it google/cloud-sdk:321.0.0 gcloud beta emulators pubsub start --host-port=0.0.0.0:8085
20
- script:
21
- - bundle exec rspec --tag emulator