@@ -6918,15 +6918,87 @@ public void onClose(Status status, Metadata trailers) {
69186918 clientCall .sendMessage (new ByteArrayInputStream ("hello" .getBytes (StandardCharsets .UTF_8 )));
69196919 clientCall .halfClose ();
69206920
6921- // Verify stream failed
6922- assertThat (extProcLatch .await (5 , TimeUnit .SECONDS )).isTrue ();
69236921 // Verify call completed and failed with INTERNAL status (not fail-open)
69246922 assertThat (callCompletedLatch .await (5 , TimeUnit .SECONDS )).isTrue ();
69256923 assertThat (callStarted .get ()).isTrue ();
69266924 assertThat (closedStatus .get ().getCode ()).isEqualTo (Status .Code .INTERNAL );
69276925 assertThat (closedStatus .get ().getDescription ()).contains ("External processor stream failed" );
69286926 }
69296927
6928+ @ Test
6929+ public void givenObservabilityTrue_whenExtProcStreamFails_thenCallContinues () throws Exception {
6930+ ExternalProcessor proto = createBaseProto (extProcServerName )
6931+ .setObservabilityMode (true )
6932+ .build ();
6933+ ConfigOrError <ExternalProcessorFilterConfig > configOrError =
6934+ provider .parseFilterConfig (Any .pack (proto ), filterContext );
6935+ assertThat (configOrError .errorDetail ).isNull ();
6936+ ExternalProcessorFilterConfig filterConfig = configOrError .config ;
6937+
6938+ ExternalProcessorGrpc .ExternalProcessorImplBase extProcImpl =
6939+ new ExternalProcessorGrpc .ExternalProcessorImplBase () {
6940+ @ Override
6941+ public StreamObserver <ProcessingRequest > process (
6942+ StreamObserver <ProcessingResponse > responseObserver ) {
6943+ responseObserver .onError (Status .UNAVAILABLE .withDescription ("ExtProc down" ).asRuntimeException ());
6944+ return new StreamObserver <ProcessingRequest >() {
6945+ @ Override public void onNext (ProcessingRequest request ) {}
6946+ @ Override public void onError (Throwable t ) {}
6947+ @ Override public void onCompleted () {}
6948+ };
6949+ }
6950+ };
6951+
6952+ grpcCleanup .register (InProcessServerBuilder .forName (extProcServerName )
6953+ .addService (extProcImpl )
6954+ .directExecutor ()
6955+ .build ().start ());
6956+
6957+ CachedChannelManager channelManager = new CachedChannelManager (config -> {
6958+ return grpcCleanup .register (
6959+ InProcessChannelBuilder .forName (extProcServerName )
6960+ .directExecutor ()
6961+ .build ());
6962+ });
6963+
6964+ ExternalProcessorServerInterceptor interceptor = new ExternalProcessorServerInterceptor (
6965+ filterConfig , channelManager , FAKE_CONTEXT );
6966+
6967+ final AtomicBoolean callStarted = new AtomicBoolean (false );
6968+ dataPlaneHandler = new DataPlaneServiceHandler () {
6969+ @ Override
6970+ public void sayHello (InputStream request , StreamObserver <InputStream > responseObserver ) {
6971+ callStarted .set (true );
6972+ responseObserver .onNext (request );
6973+ responseObserver .onCompleted ();
6974+ }
6975+ };
6976+
6977+ startDataPlane (interceptor );
6978+
6979+ io .grpc .ClientCall <InputStream , InputStream > clientCall = dataPlaneChannel .newCall (
6980+ METHOD_SAY_HELLO_RAW , io .grpc .CallOptions .DEFAULT );
6981+
6982+ final CountDownLatch callCompletedLatch = new CountDownLatch (1 );
6983+ final AtomicReference <Status > closedStatus = new AtomicReference <>();
6984+ clientCall .start (new io .grpc .ClientCall .Listener <InputStream >() {
6985+ @ Override
6986+ public void onClose (Status status , Metadata trailers ) {
6987+ closedStatus .set (status );
6988+ callCompletedLatch .countDown ();
6989+ }
6990+ }, new Metadata ());
6991+
6992+ clientCall .request (1 );
6993+ clientCall .sendMessage (new ByteArrayInputStream ("hello" .getBytes (StandardCharsets .UTF_8 )));
6994+ clientCall .halfClose ();
6995+
6996+ assertThat (callCompletedLatch .await (5 , TimeUnit .SECONDS )).isTrue ();
6997+ // Verify call completed and succeeded with OK status even though stream failed
6998+ assertThat (callStarted .get ()).isTrue ();
6999+ assertThat (closedStatus .get ().getCode ()).isEqualTo (Status .Code .OK );
7000+ }
7001+
69307002 // ============================================================================
69317003 // Category 16: Immediate Response Handling
69327004 // ============================================================================
0 commit comments