Search in sources :

Example 1 with OrcaLoadReport

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);
}
Also used : Metadata(io.grpc.Metadata) OrcaLoadReport(com.github.xds.data.orca.v3.OrcaLoadReport) Test(org.junit.Test)

Example 2 with OrcaLoadReport

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());
}
Also used : ClientStreamTracer(io.grpc.ClientStreamTracer) Metadata(io.grpc.Metadata) OrcaLoadReport(com.github.xds.data.orca.v3.OrcaLoadReport) Test(org.junit.Test)

Example 3 with OrcaLoadReport

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);
}
Also used : Context(io.grpc.Context) Status(io.grpc.Status) Metadata(io.grpc.Metadata) OrcaLoadReport(com.github.xds.data.orca.v3.OrcaLoadReport) InternalCallMetricRecorder(io.grpc.services.InternalCallMetricRecorder) CallMetricRecorder(io.grpc.services.CallMetricRecorder) SimpleForwardingServerCall(io.grpc.ForwardingServerCall.SimpleForwardingServerCall)

Example 4 with OrcaLoadReport

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());
}
Also used : ClientStreamTracer(io.grpc.ClientStreamTracer) Metadata(io.grpc.Metadata) OrcaLoadReport(com.github.xds.data.orca.v3.OrcaLoadReport) Test(org.junit.Test)

Example 5 with OrcaLoadReport

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);
}
Also used : SubchannelStateListener(io.grpc.LoadBalancer.SubchannelStateListener) InOrder(org.mockito.InOrder) OrcaLoadReport(com.github.xds.data.orca.v3.OrcaLoadReport) Test(org.junit.Test)

Aggregations

OrcaLoadReport (com.github.xds.data.orca.v3.OrcaLoadReport)9 Test (org.junit.Test)8 SubchannelStateListener (io.grpc.LoadBalancer.SubchannelStateListener)4 Metadata (io.grpc.Metadata)4 InOrder (org.mockito.InOrder)3 Attributes (io.grpc.Attributes)2 ClientStreamTracer (io.grpc.ClientStreamTracer)2 CreateSubchannelArgs (io.grpc.LoadBalancer.CreateSubchannelArgs)2 Context (io.grpc.Context)1 SimpleForwardingServerCall (io.grpc.ForwardingServerCall.SimpleForwardingServerCall)1 Status (io.grpc.Status)1 CallMetricRecorder (io.grpc.services.CallMetricRecorder)1 InternalCallMetricRecorder (io.grpc.services.InternalCallMetricRecorder)1