hyperprobe-agent 1.2.27.pre.1 → 1.2.27.pre.3

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.
@@ -2,17 +2,14 @@
2
2
 
3
3
  require 'securerandom'
4
4
  require 'socket'
5
- require_relative '../protos'
5
+ require 'json'
6
6
 
7
7
  if RUBY_PLATFORM !~ /java/
8
- begin
9
- require 'grpc'
10
- rescue LoadError
11
- # Handled gracefully if grpc gem is absent
12
- end
8
+ require 'grpc'
13
9
  else
14
- require 'java'
10
+ require_relative 'transports/java_grpc'
15
11
  end
12
+ require_relative '../protos'
16
13
 
17
14
  module HyperProbe
18
15
  module Core
@@ -34,19 +31,24 @@ module HyperProbe
34
31
  @commit_sha = commit_sha.to_s
35
32
  @agent_id = agent_id || SecureRandom.uuid
36
33
  @agent_version = agent_version.to_s
37
- @rpc_timeout_sec = rpc_timeout_sec.to_f
34
+ @rpc_timeout_sec = valid_timeout(rpc_timeout_sec)
38
35
  @hostname = ENV['HOSTNAME'] || Socket.gethostname rescue 'unknown'
39
36
  @is_jruby = RUBY_PLATFORM =~ /java/
40
- @log = Logger.get_logger('hyperprobe:broker')
41
37
 
42
38
  if @is_jruby
43
- init_jruby_client(broker_url)
39
+ @transport = Transports::JavaGrpc.new(broker_url, @service_id, enable_keep_alive)
44
40
  else
45
- init_cruby_client(broker_url, enable_keep_alive)
41
+ @calls_mutex = Mutex.new
42
+ @active_calls = []
43
+ @closed = false
44
+ target, creds, channel_args = parse_broker_url(broker_url, enable_keep_alive)
45
+ @channel = GRPC::Core::Channel.new(target, channel_args, creds)
46
+ @stub = Hyperprobe::Agent::V1::AgentBroker::Stub.new(target, creds, channel_override: @channel)
46
47
  end
47
48
  end
48
49
 
49
50
  def get_probes(timeout_sec = nil)
51
+ deadline = calculate_deadline(timeout_sec || @rpc_timeout_sec)
50
52
  req = Hyperprobe::Agent::V1::GetProbesRequest.new(
51
53
  agent_id: @agent_id,
52
54
  service_id: @service_id,
@@ -58,96 +60,66 @@ module HyperProbe
58
60
  )
59
61
 
60
62
  if @is_jruby
61
- call_jruby_rpc('/hyperprobe.agent.v1.AgentBroker/GetProbes', req, Hyperprobe::Agent::V1::GetProbesResponse, timeout_sec)
63
+ call_jruby_rpc('hyperprobe.agent.v1.AgentBroker/GetProbes', req, Hyperprobe::Agent::V1::GetProbesResponse, deadline)
62
64
  else
63
- deadline = calculate_deadline(timeout_sec || @rpc_timeout_sec)
64
- metadata = { 'x-hp-service-id' => @service_id }
65
- @stub.get_probes(req, metadata: metadata, deadline: deadline)
65
+ call_cruby_rpc(:get_probes, req, deadline)
66
66
  end
67
67
  end
68
68
 
69
69
  def report_telemetry(events, timeout_sec = nil)
70
70
  return [] if events.nil? || events.empty?
71
71
 
72
+ deadline = calculate_deadline(timeout_sec || @rpc_timeout_sec)
72
73
  proto_events = events.map { |evt| build_telemetry_event_proto(evt) }
73
- batch = Hyperprobe::Agent::V1::TelemetryBatch.new(
74
- agent_id: @agent_id,
75
- events: proto_events
76
- )
77
-
78
- if @is_jruby
79
- response = call_jruby_rpc('/hyperprobe.agent.v1.AgentBroker/ReportTelemetry', batch, Hyperprobe::Agent::V1::TelemetryResponse, timeout_sec)
80
- response.finished_probe_ids.to_a
81
- else
82
- deadline = calculate_deadline(timeout_sec || @rpc_timeout_sec)
83
- metadata = { 'x-hp-service-id' => @service_id }
84
- response = @stub.report_telemetry(batch, metadata: metadata, deadline: deadline)
85
- response.finished_probe_ids.to_a
86
- end
74
+ batch = Hyperprobe::Agent::V1::TelemetryBatch.new(agent_id: @agent_id, events: proto_events)
75
+
76
+ response = if @is_jruby
77
+ call_jruby_rpc('hyperprobe.agent.v1.AgentBroker/ReportTelemetry', batch, Hyperprobe::Agent::V1::TelemetryResponse, deadline)
78
+ else
79
+ call_cruby_rpc(:report_telemetry, batch, deadline)
80
+ end
81
+ response.finished_probe_ids.to_a
87
82
  end
88
83
 
89
84
  def estimate_event_size(event)
90
85
  proto = build_telemetry_event_proto(event)
91
- proto.to_proto.bytesize
86
+ proto.respond_to?(:serialized_size) ? proto.serialized_size : proto.to_proto.bytesize
92
87
  rescue StandardError
93
88
  JSON.generate(event).bytesize rescue 512
94
89
  end
95
90
 
96
91
  def shutdown
97
- # No-op / cleanup
98
- end
99
-
100
- private
101
-
102
- def init_cruby_client(broker_url, enable_keep_alive)
103
- target, creds, channel_args = parse_broker_url(broker_url, enable_keep_alive)
104
- @stub = Hyperprobe::Agent::V1::AgentBroker::Stub.new(
105
- target,
106
- creds,
107
- channel_args: channel_args
108
- )
109
- end
110
-
111
- def init_jruby_client(broker_url)
112
- raw_url = broker_url.to_s.strip
113
- if raw_url.start_with?('http://', 'https://')
114
- @base_url = raw_url
92
+ if @is_jruby
93
+ @transport.shutdown
115
94
  else
116
- @base_url = "http://#{raw_url}"
95
+ calls = @calls_mutex.synchronize do
96
+ @closed = true
97
+ @active_calls.dup
98
+ end
99
+ # Closing a C-core channel alone does not cancel outstanding Ruby operations.
100
+ calls.each(&:cancel)
101
+ @channel.close
117
102
  end
118
-
119
- timeout_ms = (@rpc_timeout_sec * 1000).to_i
120
- @http_client = java.net.http.HttpClient.newBuilder
121
- .version(java.net.http.HttpClient::Version::HTTP_2)
122
- .connectTimeout(java.time.Duration.ofMillis(timeout_ms))
123
- .build
124
103
  end
125
104
 
126
- def call_jruby_rpc(method_path, request_proto, response_class, timeout_sec)
127
- raw_bytes = request_proto.to_proto
128
- framed = "\x00" + [raw_bytes.bytesize].pack('N') + raw_bytes
129
-
130
- uri = java.net.URI.create("#{@base_url}#{method_path}")
131
- body_publisher = java.net.http.HttpRequest::BodyPublishers.ofByteArray(framed.to_java_bytes)
105
+ private
132
106
 
133
- req_builder = java.net.http.HttpRequest.newBuilder(uri)
134
- .version(java.net.http.HttpClient::Version::HTTP_2)
135
- .header('Content-Type', 'application/grpc')
136
- .header('TE', 'trailers')
137
- .header('x-hp-service-id', @service_id)
138
- .POST(body_publisher)
107
+ def call_cruby_rpc(method, request, deadline)
108
+ operation = @stub.public_send(method, request, metadata: { 'x-hp-service-id' => @service_id },
109
+ deadline: deadline, return_op: true)
110
+ @calls_mutex.synchronize do
111
+ raise IOError, 'Broker transport is shut down' if @closed
139
112
 
140
- effective_timeout = timeout_sec || @rpc_timeout_sec
141
- if effective_timeout && effective_timeout.positive?
142
- req_builder.timeout(java.time.Duration.ofMillis((effective_timeout * 1000).to_i))
113
+ @active_calls << operation
143
114
  end
115
+ operation.execute
116
+ ensure
117
+ @calls_mutex.synchronize { @active_calls.delete(operation) }
118
+ end
144
119
 
145
- http_response = @http_client.send(req_builder.build, java.net.http.HttpResponse::BodyHandlers.ofByteArray)
146
- response_bytes = String.from_java_bytes(http_response.body)
147
-
148
- # Strip 5-byte gRPC prefix header (1 byte compression flag + 4 bytes length)
149
- proto_payload = response_bytes.length >= 5 ? response_bytes[5..-1] : ''
150
- response_class.decode(proto_payload)
120
+ def call_jruby_rpc(method_path, request_proto, response_class, deadline)
121
+ payload = request_proto.to_proto
122
+ response_class.decode(@transport.call(method_path, payload, deadline))
151
123
  end
152
124
 
153
125
  def build_telemetry_event_proto(evt)
@@ -180,15 +152,20 @@ module HyperProbe
180
152
  end
181
153
 
182
154
  def calculate_deadline(timeout_sec)
183
- return nil unless timeout_sec && timeout_sec.positive?
155
+ now = @is_jruby ? Process.clock_gettime(Process::CLOCK_MONOTONIC) : Time.now
156
+ now + valid_timeout(timeout_sec)
157
+ end
158
+
159
+ def valid_timeout(value)
160
+ timeout = Float(value)
161
+ raise ArgumentError, 'RPC timeout must be finite and positive' unless timeout.finite? && timeout.positive?
184
162
 
185
- Time.now + timeout_sec
163
+ timeout
186
164
  end
187
165
 
188
166
  def parse_broker_url(url, enable_keep_alive)
189
167
  raw_url = url.to_s.strip
190
168
  channel_args = {}
191
-
192
169
  if enable_keep_alive
193
170
  channel_args['grpc.keepalive_time_ms'] = 60_000
194
171
  channel_args['grpc.keepalive_timeout_ms'] = 20_000
@@ -196,16 +173,9 @@ module HyperProbe
196
173
  end
197
174
 
198
175
  if raw_url.start_with?('https://')
199
- target = raw_url.sub('https://', '')
200
- creds = GRPC::Core::ChannelCredentials.new
201
- [target, creds, channel_args]
202
- elsif raw_url.start_with?('http://')
203
- target = raw_url.sub('http://', '')
204
- creds = :this_channel_is_insecure
205
- [target, creds, channel_args]
176
+ [raw_url.sub('https://', ''), GRPC::Core::ChannelCredentials.new, channel_args]
206
177
  else
207
- creds = :this_channel_is_insecure
208
- [raw_url, creds, channel_args]
178
+ [raw_url.sub(/\Ahttp:\/\//, ''), :this_channel_is_insecure, channel_args]
209
179
  end
210
180
  end
211
181
  end