anycable-core 1.3.0 → 1.3.1

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: 215d37d67fe10f536e6eb2a9b8ae5e53603d4653fb2034aff9abece234da7097
4
- data.tar.gz: 50457dfd126925e875f3bb1ab323df90a0381f13de399f07e20a8cd4f2cab5d7
3
+ metadata.gz: 5eaf888f4c9312a81bbadf980e5279efa1a0403760569b0465a537e6bd2ed291
4
+ data.tar.gz: 85206aa6fb8aac5faa0641c889deb9f4c61d40a27211feffb20ab23590313469
5
5
  SHA512:
6
- metadata.gz: 43eac0f870ba33726095d8801772d3b18dd2a909a937c9c03177aab163d2ee93f92979bcfcf4cb3eb2039e80e3f28ec123d9e215ee07fe4b87fb152510f7b87d
7
- data.tar.gz: be1a5de79d480aa5d0b081354103f325cb3f997d8d134ba325b92d233408696236afedd600c7133ccb307ac7ceb9b16c60e284588942aa83886007384002a372
6
+ metadata.gz: 8eb1685bd731c6904126e0ea75a5f4489f268e97f080df60a6eec9ce3ae79cf7c3477ff5cf4add6541a7b09c21455c1d97ababcc1ad818f119e79ac6faf97e56
7
+ data.tar.gz: 9d5c9882b1eb73901e253f64915c3647c38453357560d9ec836a29163aa3b6f24a10b485b1007751e3600f81a4e4a9cb8eb0a37204af35d87cc216934b7530c2
data/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.3.1 (2023-05-12)
6
+
7
+ - Fix gRPC health check response for an empty service. ([@palkan][])
8
+
9
+ As per [docs](https://github.com/grpc/grpc/blob/master/doc/health-checking.md), an empty service is used as the key for server's overall health status. So, if we serve any services, we should return `SERVING` status.
10
+
11
+ - Add gRPC health check when using grpc_kit. ([@palkan][])
12
+
5
13
  ## 1.3.0 (2023-02-28)
6
14
 
7
15
  - Add configuration presets. ([@palkan][])
data/README.md CHANGED
@@ -28,6 +28,8 @@ Check out our 📑 [Documentation](https://docs.anycable.io/v1).
28
28
 
29
29
  ## Links
30
30
 
31
+ - [AnyCable off Rails: connecting Twilio streams with Hanami](https://evilmartians.com/chronicles/anycable-goes-off-rails-connecting-twilio-streams-with-hanami)
32
+
31
33
  - [AnyCable 1.0: Four years of real-time web with Ruby and Go](https://evilmartians.com/chronicles/anycable-1-0-four-years-of-real-time-web-with-ruby-and-go)
32
34
 
33
35
  - [AnyCable: Action Cable on steroids!](https://evilmartians.com/chronicles/anycable-actioncable-on-steroids)
@@ -118,7 +118,7 @@ module AnyCable
118
118
  yield http
119
119
  rescue Timeout::Error, *RECOVERABLE_EXCEPTIONS => e
120
120
  retry_count += 1
121
- if MAX_ATTEMPTS < retry_count
121
+ if retry_count > MAX_ATTEMPTS
122
122
  logger.error("Broadcast request failed: #{e.message}")
123
123
  return
124
124
  end
@@ -31,6 +31,7 @@ module AnyCable
31
31
  )
32
32
  options = AnyCable.config.to_nats_params.merge(options)
33
33
  @nats_conn = ::NATS.connect(nil, options)
34
+ setup_listeners(nats_conn)
34
35
  @channel = channel
35
36
  end
36
37
 
@@ -41,6 +42,19 @@ module AnyCable
41
42
  def announce!
42
43
  logger.info "Broadcasting NATS channel: #{channel}"
43
44
  end
45
+
46
+ private
47
+
48
+ def setup_listeners(nats_client)
49
+ nats_client.on_disconnect { logger.info "NATS client disconnected" }
50
+ nats_client.on_reconnect do
51
+ info = nats_client.server_info
52
+ logger.info "NATS client reconnected: host=#{info[:host]}:#{info[:port]} cluster=#{info[:cluster]}"
53
+ end
54
+ nats_client.on_error do |err|
55
+ logger.warn "NATS client error: #{err.message}"
56
+ end
57
+ end
44
58
  end
45
59
  end
46
60
  end
@@ -21,7 +21,7 @@ module AnyCable
21
21
  #
22
22
  # You can override these params:
23
23
  #
24
- # AnyCable.broadcast_adapter = :redis, url: "redis://my_redis", channel: "_any_cable_"
24
+ # AnyCable.broadcast_adapter = :redis, { url: "redis://my_redis", channel: "_any_cable_" }
25
25
  class Redis < Base
26
26
  attr_reader :redis_conn, :channel
27
27
 
@@ -98,7 +98,7 @@ module AnyCable
98
98
  )
99
99
  health_checker.add_status(
100
100
  "",
101
- Grpc::Health::V1::HealthCheckResponse::ServingStatus::NOT_SERVING
101
+ Grpc::Health::V1::HealthCheckResponse::ServingStatus::SERVING
102
102
  )
103
103
  health_checker
104
104
  end
@@ -0,0 +1,72 @@
1
+ # Copyright 2015 gRPC authors.
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
+ module Grpc
16
+ # Health contains classes and modules that support providing a health check
17
+ # service.
18
+ module Health
19
+ # Checker is implementation of the schema-specified health checking service.
20
+ class Checker < V1::Health::Service
21
+ StatusCodes = GRPC::Core::StatusCodes
22
+ HealthCheckResponse = V1::HealthCheckResponse
23
+
24
+ # Initializes the statuses of participating services
25
+ def initialize
26
+ @statuses = {}
27
+ @status_mutex = Mutex.new # guards access to @statuses
28
+ end
29
+
30
+ # Implements the rpc IDL API method
31
+ def check(req, _call)
32
+ status = nil
33
+ @status_mutex.synchronize do
34
+ status = @statuses["#{req.service}"]
35
+ end
36
+ if status.nil?
37
+ fail GRPC::NotFound.new("Service is not found: #{req.service}")
38
+ end
39
+ HealthCheckResponse.new(status: status)
40
+ end
41
+
42
+ # Adds the health status for a given service.
43
+ def add_status(service, status)
44
+ @status_mutex.synchronize { @statuses["#{service}"] = status }
45
+ end
46
+
47
+ # Adds given health status for all given services
48
+ def set_status_for_services(status, *services)
49
+ @status_mutex.synchronize do
50
+ services.each { |service| @statuses["#{service}"] = status }
51
+ end
52
+ end
53
+
54
+ # Adds health status for each service given within hash
55
+ def add_statuses(service_statuses = {})
56
+ @status_mutex.synchronize do
57
+ service_statuses.each_pair { |service, status| @statuses["#{service}"] = status }
58
+ end
59
+ end
60
+
61
+ # Clears the status for the given service.
62
+ def clear_status(service)
63
+ @status_mutex.synchronize { @statuses.delete("#{service}") }
64
+ end
65
+
66
+ # Clears alls the statuses.
67
+ def clear_all
68
+ @status_mutex.synchronize { @statuses = {} }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
4
+ # source: grpc/health/v1/health.proto
5
+
6
+ require 'google/protobuf'
7
+
8
+ Google::Protobuf::DescriptorPool.generated_pool.build do
9
+ add_message "grpc.health.v1.HealthCheckRequest" do
10
+ optional :service, :string, 1
11
+ end
12
+ add_message "grpc.health.v1.HealthCheckResponse" do
13
+ optional :status, :enum, 1, "grpc.health.v1.HealthCheckResponse.ServingStatus"
14
+ end
15
+ add_enum "grpc.health.v1.HealthCheckResponse.ServingStatus" do
16
+ value :UNKNOWN, 0
17
+ value :SERVING, 1
18
+ value :NOT_SERVING, 2
19
+ end
20
+ end
21
+
22
+ module Grpc
23
+ module Health
24
+ module V1
25
+ HealthCheckRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1.HealthCheckRequest").msgclass
26
+ HealthCheckResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1.HealthCheckResponse").msgclass
27
+ HealthCheckResponse::ServingStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1.HealthCheckResponse.ServingStatus").enummodule
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,41 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # Source: grpc/health/v1/health.proto for package 'grpc.health.v1'
3
+ # Original file comments:
4
+ # Copyright 2015 The gRPC Authors
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ # The canonical version of this proto can be found at
19
+ # https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto
20
+ #
21
+
22
+ module Grpc
23
+ module Health
24
+ module V1
25
+ module Health
26
+ class Service
27
+
28
+ include GRPC::GenericService
29
+
30
+ self.marshal_class_method = :encode
31
+ self.unmarshal_class_method = :decode
32
+ self.service_name = 'grpc.health.v1.Health'
33
+
34
+ rpc :Check, HealthCheckRequest, HealthCheckResponse
35
+ end
36
+
37
+ Stub = Service.rpc_stub_class
38
+ end
39
+ end
40
+ end
41
+ end
@@ -2,6 +2,10 @@
2
2
 
3
3
  require "anycable/grpc/handler"
4
4
 
5
+ require_relative "./health_pb"
6
+ require_relative "./health_services_pb"
7
+ require_relative "./health_checker"
8
+
5
9
  module AnyCable
6
10
  module GRPC
7
11
  raise LoadError, "AnyCable::GRPC::Server has been already loaded!" if defined?(AnyCable::GRPC::Server)
@@ -77,8 +81,8 @@ module AnyCable
77
81
 
78
82
  loop do
79
83
  sock = TCPSocket.new(hostname, port, connect_timeout: 1)
80
- stub = AnyCable::GRPC::Stub.new(sock)
81
- stub.connect(AnyCable::ConnectionRequest.new(env: {}))
84
+ stub = ::Grpc::Health::V1::Health::Stub.new(sock)
85
+ stub.check(::Grpc::Health::V1::HealthCheckRequest.new)
82
86
  sock.close
83
87
  break
84
88
  rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError
@@ -126,8 +130,22 @@ module AnyCable
126
130
 
127
131
  ::GrpcKit::Server.new(min_pool_size: pool_size, max_pool_size: pool_size).tap do |server|
128
132
  server.handle(AnyCable::GRPC::Handler)
133
+ server.handle(build_health_checker)
129
134
  end
130
135
  end
136
+
137
+ def build_health_checker
138
+ health_checker = ::Grpc::Health::Checker.new
139
+ health_checker.add_status(
140
+ "anycable.RPC",
141
+ ::Grpc::Health::V1::HealthCheckResponse::ServingStatus::SERVING
142
+ )
143
+ health_checker.add_status(
144
+ "",
145
+ ::Grpc::Health::V1::HealthCheckResponse::ServingStatus::SERVING
146
+ )
147
+ health_checker
148
+ end
131
149
  end
132
150
  end
133
151
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AnyCable
4
- VERSION = "1.3.0"
4
+ VERSION = "1.3.1"
5
5
  end
@@ -5,6 +5,10 @@ module AnyCable
5
5
  attr_reader channel: String
6
6
 
7
7
  def initialize: (?channel: String channel, **untyped options) -> void
8
+
9
+ private
10
+
11
+ def setup_listeners: (untyped nats_conn) -> void
8
12
  end
9
13
  end
10
14
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anycable-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - palkan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-01 00:00:00.000000000 Z
11
+ date: 2023-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: anyway_config
@@ -210,6 +210,9 @@ files:
210
210
  - lib/anycable/grpc/rpc_services_pb.rb
211
211
  - lib/anycable/grpc/server.rb
212
212
  - lib/anycable/grpc_kit.rb
213
+ - lib/anycable/grpc_kit/health_checker.rb
214
+ - lib/anycable/grpc_kit/health_pb.rb
215
+ - lib/anycable/grpc_kit/health_services_pb.rb
213
216
  - lib/anycable/grpc_kit/server.rb
214
217
  - lib/anycable/health_server.rb
215
218
  - lib/anycable/middleware.rb
@@ -278,7 +281,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
278
281
  - !ruby/object:Gem::Version
279
282
  version: '0'
280
283
  requirements: []
281
- rubygems_version: 3.4.6
284
+ rubygems_version: 3.4.8
282
285
  signing_key:
283
286
  specification_version: 4
284
287
  summary: AnyCable core RPC implementation