use of com.github.xds.data.orca.v3.OrcaLoadReport in project grpc-java by grpc.
the class OrcaMetricReportingServerInterceptorTest method responseTrailersContainAllReportedMetrics.
@Test
public void responseTrailersContainAllReportedMetrics() {
applicationMetrics.put("cost1", 1231.4543);
applicationMetrics.put("cost2", 0.1367);
applicationMetrics.put("cost3", 7614.145);
ClientCalls.blockingUnaryCall(channelToUse, SIMPLE_METHOD, CallOptions.DEFAULT, REQUEST);
Metadata receivedTrailers = trailersCapture.get();
OrcaLoadReport report = receivedTrailers.get(OrcaMetricReportingServerInterceptor.ORCA_ENDPOINT_LOAD_METRICS_KEY);
assertThat(report.getRequestCostMap()).containsExactly("cost1", 1231.4543, "cost2", 0.1367, "cost3", 7614.145);
}
use of com.github.xds.data.orca.v3.OrcaLoadReport in project grpc-java by grpc.
the class OrcaPerRequestUtilTest method singlePolicyTypicalWorkflow.
/**
* Tests a single load balance policy's listener receive per-request ORCA reports upon call
* trailer arrives.
*/
@Test
public void singlePolicyTypicalWorkflow() {
// Use a mocked noop stream tracer factory as the original stream tracer factory.
ClientStreamTracer.Factory fakeDelegateFactory = mock(ClientStreamTracer.Factory.class);
ClientStreamTracer fakeTracer = mock(ClientStreamTracer.class);
doNothing().when(fakeTracer).inboundTrailers(any(Metadata.class));
when(fakeDelegateFactory.newClientStreamTracer(any(ClientStreamTracer.StreamInfo.class), any(Metadata.class))).thenReturn(fakeTracer);
// The OrcaReportingTracerFactory will augment the StreamInfo passed to its
// newClientStreamTracer method. The augmented StreamInfo's CallOptions will contain
// a OrcaReportBroker, in which has the registered listener.
ClientStreamTracer.Factory factory = OrcaPerRequestUtil.getInstance().newOrcaClientStreamTracerFactory(fakeDelegateFactory, orcaListener1);
ClientStreamTracer tracer = factory.newClientStreamTracer(STREAM_INFO, new Metadata());
ArgumentCaptor<ClientStreamTracer.StreamInfo> streamInfoCaptor = ArgumentCaptor.forClass(null);
verify(fakeDelegateFactory).newClientStreamTracer(streamInfoCaptor.capture(), any(Metadata.class));
ClientStreamTracer.StreamInfo capturedInfo = streamInfoCaptor.getValue();
assertThat(capturedInfo).isNotEqualTo(STREAM_INFO);
// When the trailer does not contain ORCA report, listener callback will not be invoked.
Metadata trailer = new Metadata();
tracer.inboundTrailers(trailer);
verifyNoMoreInteractions(orcaListener1);
// When the trailer contains an ORCA report, listener callback will be invoked.
trailer.put(OrcaReportingTracerFactory.ORCA_ENDPOINT_LOAD_METRICS_KEY, OrcaLoadReport.getDefaultInstance());
tracer.inboundTrailers(trailer);
ArgumentCaptor<OrcaLoadReport> reportCaptor = ArgumentCaptor.forClass(null);
verify(orcaListener1).onLoadReport(reportCaptor.capture());
assertThat(reportCaptor.getValue()).isEqualTo(OrcaLoadReport.getDefaultInstance());
}
use of com.github.xds.data.orca.v3.OrcaLoadReport in project grpc-java by grpc.
the class OrcaMetricReportingServerInterceptor method interceptCall.
@Override
public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
Context ctx = Context.current();
CallMetricRecorder callMetricRecorder = InternalCallMetricRecorder.CONTEXT_KEY.get(ctx);
if (callMetricRecorder == null) {
callMetricRecorder = InternalCallMetricRecorder.newCallMetricRecorder();
ctx = ctx.withValue(InternalCallMetricRecorder.CONTEXT_KEY, callMetricRecorder);
}
final CallMetricRecorder finalCallMetricRecorder = callMetricRecorder;
ServerCall<ReqT, RespT> trailerAttachingCall = new SimpleForwardingServerCall<ReqT, RespT>(call) {
@Override
public void close(Status status, Metadata trailers) {
Map<String, Double> metricValues = InternalCallMetricRecorder.finalizeAndDump(finalCallMetricRecorder);
// Only attach a metric report if there are some metric values to be reported.
if (!metricValues.isEmpty()) {
OrcaLoadReport report = OrcaLoadReport.newBuilder().putAllRequestCost(metricValues).build();
trailers.put(ORCA_ENDPOINT_LOAD_METRICS_KEY, report);
}
super.close(status, trailers);
}
};
return Contexts.interceptCall(ctx, trailerAttachingCall, headers, next);
}
use of com.github.xds.data.orca.v3.OrcaLoadReport in project grpc-java by grpc.
the class OrcaPerRequestUtilTest method twoLevelPoliciesTypicalWorkflow.
/**
* Tests parent-child load balance policies' listeners both receive per-request ORCA reports upon
* call trailer arrives and ORCA report deserialization happens only once.
*/
@Test
public void twoLevelPoliciesTypicalWorkflow() {
ClientStreamTracer.Factory parentFactory = mock(ClientStreamTracer.Factory.class, delegatesTo(OrcaPerRequestUtil.getInstance().newOrcaClientStreamTracerFactory(orcaListener1)));
ClientStreamTracer.Factory childFactory = OrcaPerRequestUtil.getInstance().newOrcaClientStreamTracerFactory(parentFactory, orcaListener2);
// Child factory will augment the StreamInfo and pass it to the parent factory.
ClientStreamTracer childTracer = childFactory.newClientStreamTracer(STREAM_INFO, new Metadata());
ArgumentCaptor<ClientStreamTracer.StreamInfo> streamInfoCaptor = ArgumentCaptor.forClass(null);
verify(parentFactory).newClientStreamTracer(streamInfoCaptor.capture(), any(Metadata.class));
ClientStreamTracer.StreamInfo parentStreamInfo = streamInfoCaptor.getValue();
assertThat(parentStreamInfo).isNotEqualTo(STREAM_INFO);
// When the trailer does not contain ORCA report, no listener callback will be invoked.
Metadata trailer = new Metadata();
childTracer.inboundTrailers(trailer);
verifyNoMoreInteractions(orcaListener1);
verifyNoMoreInteractions(orcaListener2);
// When the trailer contains an ORCA report, callbacks for both listeners will be invoked.
// Both listener will receive the same ORCA report instance, which means deserialization
// happens only once.
trailer.put(OrcaReportingTracerFactory.ORCA_ENDPOINT_LOAD_METRICS_KEY, OrcaLoadReport.getDefaultInstance());
childTracer.inboundTrailers(trailer);
ArgumentCaptor<OrcaLoadReport> parentReportCap = ArgumentCaptor.forClass(null);
ArgumentCaptor<OrcaLoadReport> childReportCap = ArgumentCaptor.forClass(null);
verify(orcaListener1).onLoadReport(parentReportCap.capture());
verify(orcaListener2).onLoadReport(childReportCap.capture());
assertThat(parentReportCap.getValue()).isEqualTo(OrcaLoadReport.getDefaultInstance());
assertThat(childReportCap.getValue()).isSameInstanceAs(parentReportCap.getValue());
}
use of com.github.xds.data.orca.v3.OrcaLoadReport in project grpc-java by grpc.
the class OrcaOobUtilTest method orcaReportingStreamClosedAndRetried.
@Test
public void orcaReportingStreamClosedAndRetried() {
setOrcaReportConfig(orcaHelperWrapper, SHORT_INTERVAL_CONFIG);
createSubchannel(orcaHelperWrapper.asHelper(), 0, Attributes.EMPTY);
FakeSubchannel subchannel = subchannels[0];
OpenRcaServiceImp orcaServiceImp = orcaServiceImps[0];
SubchannelStateListener mockStateListener = mockStateListeners[0];
InOrder inOrder = inOrder(mockStateListener, mockOrcaListener0, backoffPolicyProvider, backoffPolicy1, backoffPolicy2);
deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(mockStateListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(READY)));
assertLog(subchannel.logs, "DEBUG: Starting ORCA reporting for " + subchannel.getAllAddresses());
// Server closes the ORCA reporting RPC without any response, will start backoff
// sequence 1 (11ns).
orcaServiceImp.calls.poll().responseObserver.onCompleted();
assertLog(subchannel.logs, "DEBUG: ORCA reporting stream closed with " + Status.OK + ", backoff in 11" + " ns");
inOrder.verify(backoffPolicyProvider).get();
inOrder.verify(backoffPolicy1).nextBackoffNanos();
verifyRetryAfterNanos(inOrder, orcaServiceImp, 11);
assertLog(subchannel.logs, "DEBUG: Starting ORCA reporting for " + subchannel.getAllAddresses());
// Server closes the ORCA reporting RPC with an error, will continue backoff sequence 1 (21ns).
orcaServiceImp.calls.poll().responseObserver.onError(Status.UNAVAILABLE.asException());
assertLog(subchannel.logs, "DEBUG: ORCA reporting stream closed with " + Status.UNAVAILABLE + ", backoff in 21" + " ns");
inOrder.verify(backoffPolicy1).nextBackoffNanos();
verifyRetryAfterNanos(inOrder, orcaServiceImp, 21);
assertLog(subchannel.logs, "DEBUG: Starting ORCA reporting for " + subchannel.getAllAddresses());
// Server responds normally.
OrcaLoadReport report = OrcaLoadReport.getDefaultInstance();
orcaServiceImp.calls.peek().responseObserver.onNext(report);
assertLog(subchannel.logs, "DEBUG: Received an ORCA report: " + report);
inOrder.verify(mockOrcaListener0).onLoadReport(eq(report));
// Server closes the ORCA reporting RPC after a response, will restart immediately.
orcaServiceImp.calls.poll().responseObserver.onCompleted();
assertThat(subchannel.logs).containsExactly("DEBUG: ORCA reporting stream closed with " + Status.OK + ", backoff in 0" + " ns", "DEBUG: Starting ORCA reporting for " + subchannel.getAllAddresses());
subchannel.logs.clear();
// Backoff policy is set to sequence 2 in previous retry.
// Server closes the ORCA reporting RPC with an error, will start backoff sequence 2 (12ns).
orcaServiceImp.calls.poll().responseObserver.onError(Status.UNAVAILABLE.asException());
assertLog(subchannel.logs, "DEBUG: ORCA reporting stream closed with " + Status.UNAVAILABLE + ", backoff in 12" + " ns");
inOrder.verify(backoffPolicyProvider).get();
inOrder.verify(backoffPolicy2).nextBackoffNanos();
verifyRetryAfterNanos(inOrder, orcaServiceImp, 12);
assertLog(subchannel.logs, "DEBUG: Starting ORCA reporting for " + subchannel.getAllAddresses());
verifyNoMoreInteractions(mockStateListener, mockOrcaListener0, backoffPolicyProvider, backoffPolicy1, backoffPolicy2);
}
Aggregations