gcpc 0.0.6 → 0.0.8

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: d4dfcbba14815f166e194aa5d106bf86c1adb86d4feb7bd1b406808974a2137d
4
- data.tar.gz: ed718afdbaeeb0b415cd9f5923b30f69dd9a17066712f4a932f2d55102da27c1
3
+ metadata.gz: d89748f1a7066c40f0b4c6c4477bab098ab45c206ca7f019d5f29f13be62c875
4
+ data.tar.gz: 76261a92198cd9e53629455aba3859117e649004838da3752ead8dbbe8445f14
5
5
  SHA512:
6
- metadata.gz: 21c978898799abeb533747aca3bcb52d152d9f92c6260db56ca5b0da74b08985a521974b9707a3d36a3772ebe1017edab5a2ee2d948841a81e414594647fa39a
7
- data.tar.gz: 1d99113e0c48bad884963d12c43878efb55681fe47268ce1fbc2bb975ffb9a6d83e426f7dc654810ea6a1b4227542c3b21c6a8c2acd6c2185c6e2a030addc52d
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 ADDED
@@ -0,0 +1,23 @@
1
+ ## Unreleased
2
+
3
+ <!-- When you commit changes, describe the changes above (in the ## Unreleased section). -->
4
+ <!-- All changes (implementation, or doc changes) are worth noting. -->
5
+ <!-- The changes listed above will go below when a new release is being prepared. -->
6
+
7
+ ## 0.0.8
8
+
9
+ - Add an API for heartbeat https://github.com/wantedly/gcpc/pull/25
10
+
11
+ ## 0.0.7
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
15
+
16
+ ## 0.0.6
17
+
18
+ - Add test of interceptors https://github.com/wantedly/gcpc/pull/7
19
+ - Add publish_batch https://github.com/wantedly/gcpc/pull/6
20
+
21
+ ## 0.0.5
22
+
23
+ - Add publish_async https://github.com/wantedly/gcpc/pull/5
data/Gemfile.lock CHANGED
@@ -1,67 +1,82 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gcpc (0.0.6)
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.6.0)
11
- public_suffix (>= 2.0.2, < 4.0)
12
- coderay (1.1.2)
13
- concurrent-ruby (1.1.5)
10
+ addressable (2.8.5)
11
+ public_suffix (>= 2.0.2, < 6.0)
12
+ coderay (1.1.3)
13
+ concurrent-ruby (1.2.2)
14
14
  diff-lcs (1.3)
15
- faraday (0.15.4)
16
- multipart-post (>= 1.2, < 3)
17
- google-cloud-core (1.3.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)
18
30
  google-cloud-env (~> 1.0)
19
- google-cloud-env (1.2.0)
20
- faraday (~> 0.11)
21
- google-cloud-pubsub (0.38.0)
31
+ google-cloud-errors (~> 1.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)
22
36
  concurrent-ruby (~> 1.1)
23
- google-cloud-core (~> 1.2)
24
- google-gax (~> 1.7)
25
- googleapis-common-protos (>= 1.3.9, < 2.0)
26
- grpc-google-iam-v1 (~> 0.6.9)
27
- google-gax (1.7.0)
28
- google-protobuf (~> 3.2)
29
- googleapis-common-protos (>= 1.3.5, < 2.0)
30
- googleauth (>= 0.6.2, < 0.10.0)
31
- grpc (>= 1.7.2, < 2.0)
32
- rly (~> 0.2.3)
33
- google-protobuf (3.9.0-universal-darwin)
34
- googleapis-common-protos (1.3.9)
35
- google-protobuf (~> 3.0)
36
- googleapis-common-protos-types (~> 1.0)
37
- grpc (~> 1.0)
38
- googleapis-common-protos-types (1.0.4)
39
- google-protobuf (~> 3.0)
40
- googleauth (0.8.1)
41
- faraday (~> 0.12)
37
+ google-cloud-core (~> 1.5)
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)
42
+ google-cloud-errors (~> 1.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)
52
+ grpc (~> 1.27)
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)
42
57
  jwt (>= 1.4, < 3.0)
43
58
  memoist (~> 0.16)
44
59
  multi_json (~> 1.11)
45
60
  os (>= 0.9, < 2.0)
46
- signet (~> 0.7)
47
- grpc (1.22.0-universal-darwin)
48
- google-protobuf (~> 3.8)
61
+ signet (>= 0.16, < 2.a)
62
+ grpc (1.56.2)
63
+ google-protobuf (~> 3.23)
49
64
  googleapis-common-protos-types (~> 1.0)
50
- grpc-google-iam-v1 (0.6.9)
51
- googleapis-common-protos (>= 1.3.1, < 2.0)
52
- grpc (~> 1.0)
53
- jwt (2.2.1)
54
- memoist (0.16.0)
55
- method_source (0.9.2)
56
- multi_json (1.13.1)
57
- multipart-post (2.1.1)
58
- os (1.0.1)
59
- pry (0.12.2)
60
- coderay (~> 1.1.0)
61
- method_source (~> 0.9.0)
62
- public_suffix (3.1.1)
63
- rake (10.5.0)
64
- rly (0.2.3)
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)
70
+ memoist (0.16.2)
71
+ method_source (1.0.0)
72
+ multi_json (1.15.0)
73
+ os (1.1.4)
74
+ pry (0.13.1)
75
+ coderay (~> 1.1)
76
+ method_source (~> 1.0)
77
+ public_suffix (5.0.3)
78
+ rake (13.0.1)
79
+ retriable (3.1.2)
65
80
  rspec (3.8.0)
66
81
  rspec-core (~> 3.8.0)
67
82
  rspec-expectations (~> 3.8.0)
@@ -75,9 +90,10 @@ GEM
75
90
  diff-lcs (>= 1.2.0, < 2.0)
76
91
  rspec-support (~> 3.8.0)
77
92
  rspec-support (3.8.0)
78
- signet (0.11.0)
79
- addressable (~> 2.3)
80
- faraday (~> 0.9)
93
+ ruby2_keywords (0.0.5)
94
+ signet (0.17.0)
95
+ addressable (~> 2.8)
96
+ faraday (>= 0.17.5, < 3.a)
81
97
  jwt (>= 1.5, < 3.0)
82
98
  multi_json (~> 1.10)
83
99
 
@@ -85,11 +101,11 @@ PLATFORMS
85
101
  ruby
86
102
 
87
103
  DEPENDENCIES
88
- bundler (~> 1.17)
104
+ bundler
89
105
  gcpc!
90
106
  pry
91
- rake (~> 10.0)
107
+ rake (~> 13.0)
92
108
  rspec (~> 3.2)
93
109
 
94
110
  BUNDLED WITH
95
- 1.17.2
111
+ 2.2.5
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.
@@ -23,8 +23,8 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ["lib"]
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.17"
27
- spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "bundler"
27
+ spec.add_development_dependency "rake", "~> 13.0"
28
28
  spec.add_development_dependency "rspec", "~> 3.2"
29
29
  spec.add_development_dependency "pry"
30
30
  spec.add_runtime_dependency "google-cloud-pubsub"
@@ -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
@@ -1,3 +1,4 @@
1
+ require "forwardable"
1
2
  require "gcpc/publisher/base_interceptor"
2
3
  require "gcpc/publisher/engine"
3
4
  require "gcpc/publisher/topic_client"
@@ -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
@@ -1,3 +1,4 @@
1
+ require "forwardable"
1
2
  require "gcpc/subscriber/base_handler"
2
3
  require "gcpc/subscriber/base_interceptor"
3
4
  require "gcpc/subscriber/default_logger"
data/lib/gcpc/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Gcpc
2
- VERSION = "0.0.6"
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,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gcpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nao Minami
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-05 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
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.17'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.17'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -87,9 +87,10 @@ 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
+ - CHANGELOG.md
93
94
  - Gemfile
94
95
  - Gemfile.lock
95
96
  - LICENSE.txt
@@ -103,6 +104,7 @@ files:
103
104
  - examples/subscriber-example/subscriber-example.rb
104
105
  - gcpc.gemspec
105
106
  - lib/gcpc.rb
107
+ - lib/gcpc/config.rb
106
108
  - lib/gcpc/publisher.rb
107
109
  - lib/gcpc/publisher/base_interceptor.rb
108
110
  - lib/gcpc/publisher/engine.rb
@@ -117,11 +119,12 @@ files:
117
119
  - lib/gcpc/subscriber/handle_engine.rb
118
120
  - lib/gcpc/subscriber/subscription_client.rb
119
121
  - lib/gcpc/version.rb
120
- homepage: https://github.com/south37/gcpc
122
+ - renovate.json
123
+ homepage: https://github.com/wantedly/gcpc
121
124
  licenses:
122
125
  - MIT
123
126
  metadata: {}
124
- post_install_message:
127
+ post_install_message:
125
128
  rdoc_options: []
126
129
  require_paths:
127
130
  - lib
@@ -136,8 +139,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
136
139
  - !ruby/object:Gem::Version
137
140
  version: '0'
138
141
  requirements: []
139
- rubygems_version: 3.0.3
140
- signing_key:
142
+ rubygems_version: 3.4.10
143
+ signing_key:
141
144
  specification_version: 4
142
145
  summary: Google Cloud Pub/Sub Client
143
146
  test_files: []
data/.travis.yml DELETED
@@ -1,19 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.6.2
7
- before_install:
8
- - gem install bundler -v 1.17.2
9
- jobs:
10
- include:
11
- - name: 'test'
12
- script:
13
- - bundle exec rspec
14
- - name: 'test with a emulator'
15
- before_install:
16
- # Start a Cloud Pub/Sub emulator. See https://cloud.google.com/pubsub/docs/emulator
17
- - docker run -d -p 8085:8085 -it google/cloud-sdk:latest gcloud beta emulators pubsub start --host-port=0.0.0.0:8085
18
- script:
19
- - bundle exec rspec --tag emulator