Class: Async::Service::Supervisor::Envoy::Monitor

Inherits:
Monitor
  • Object
show all
Defined in:
lib/async/service/supervisor/envoy/monitor.rb

Overview

Represents a supervisor monitor that publishes worker endpoints and optionally clusters to Envoy using xDS.

The monitor always serves a dedicated EDS stream and can additionally serve CDS, leaving ADS available to another control plane.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bind: nil, delegate: Delegate.new, control_plane: Async::GRPC::XDS::ControlPlane.new, management_cluster: "xds_cluster", publish_clusters: true, health_checks: [], orca: false, processor: nil, utilization_monitor: nil, interval: 1, **options) ⇒ Monitor

Initialize the monitor.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 44

def initialize(
	bind: nil,
	delegate: Delegate.new,
	control_plane: Async::GRPC::XDS::ControlPlane.new,
	management_cluster: "xds_cluster",
	publish_clusters: true,
	health_checks: [],
	orca: false,
	processor: nil,
	utilization_monitor: nil,
	interval: 1,
	**options
)
	super(interval: interval, **options)
	
	@bind = bind
	@delegate = delegate
	@control_plane = control_plane
	@eds_config = Async::GRPC::XDS::ConfigSource.grpc(management_cluster)
	@publish_clusters = publish_clusters
	@health_checks = health_checks
	@interval = interval
	@orca = orca
	@controllers = {}
	@published_clusters = {}
	@published_endpoints = {}
	@mutex = Mutex.new
	
	if @orca
		raise ArgumentError, "ORCA reporting requires a TCP bind address!" unless @bind
		raise ArgumentError, "ORCA reporting requires a utilization monitor!" unless utilization_monitor
		
		@orca_port = server_endpoint.url.port
		raise ArgumentError, "ORCA reporting requires a fixed TCP port!" unless @orca_port&.positive?
		
		@processor = processor || Process::Metrics::Processor.new
		@utilization_monitor = utilization_monitor
		@request_totals = {}
		@load_reports = {}
		@authorities = {}
	end
end

Instance Attribute Details

#control_planeObject (readonly)

Returns the value of attribute control_plane.



88
89
90
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 88

def control_plane
  @control_plane
end

#delegateObject (readonly)

Returns the value of attribute delegate.



91
92
93
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 91

def delegate
  @delegate
end

#The xDS control plane receiving cluster and endpoint updates.(xDScontrolplanereceivingcluster) ⇒ Object (readonly)



88
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 88

attr :control_plane

Instance Method Details

#as_jsonObject

Convert the currently published endpoints to JSON-compatible data.



145
146
147
148
149
150
151
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 145

def as_json
	@mutex.synchronize do
		{
			clusters: build_clusters
		}
	end
end

#load_report(authority) ⇒ Object

Get the latest ORCA report for a worker authority.



165
166
167
168
169
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 165

def load_report(authority)
	return unless @orca
	
	@mutex.synchronize{@load_reports[authority]}
end

#register(supervisor_controller) ⇒ Object

Register a supervisor worker with Envoy.



96
97
98
99
100
101
102
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 96

def register(supervisor_controller)
	@mutex.synchronize do
		@controllers[supervisor_controller.id] = supervisor_controller
		@authorities[worker_hostname(supervisor_controller)] = supervisor_controller.id if @orca
		reconcile
	end
end

#remove(supervisor_controller) ⇒ Object

Remove a supervisor worker from Envoy.



107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 107

def remove(supervisor_controller)
	@mutex.synchronize do
		@controllers.delete(supervisor_controller.id)
		if @orca
			hostname = worker_hostname(supervisor_controller)
			@authorities.delete(hostname)
			@load_reports.delete(hostname)
			@request_totals.delete(supervisor_controller.id)
		end
		reconcile
	end
end

#run(parent: Async::Task.current) ⇒ Object

Run the monitor and optional discovery server task.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 123

def run(parent: Async::Task.current)
	task = super(parent: parent)
	
	if @bind
		parent.async do
			services = [Async::GRPC::XDS::EndpointDiscoveryService]
			services.unshift(Async::GRPC::XDS::ClusterDiscoveryService) if @publish_clusters
			
			server = Async::GRPC::XDS::Server.new(
				@control_plane,
				services: services
			)
			server.dispatcher.register(ORCAService.new(self, minimum_interval: @interval)) if @orca
			server.run(server_endpoint)
		end
	end
	
	task
end

#run_onceObject

Refresh endpoint health and publish updated EDS state.



173
174
175
176
177
178
179
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 173

def run_once
	sample_load_reports if @orca
	
	@mutex.synchronize do
		reconcile
	end
end

#The delegate used to map supervisor state into Envoy endpoints.=(delegateusedtomapsupervisorstateintoEnvoyendpoints. = (value)) ⇒ Object



91
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 91

attr :delegate

#worker?(authority) ⇒ Boolean

Determine whether an ORCA worker authority is currently registered.

Returns:

  • (Boolean)


156
157
158
159
160
# File 'lib/async/service/supervisor/envoy/monitor.rb', line 156

def worker?(authority)
	return false unless @orca
	
	@mutex.synchronize{@authorities.key?(authority)}
end