feat: triple exception self (#12039)

* feat: triple exception self

* feat: test default

* feat: test default

* feat: test default

* feat: test default

* feat: test default

* feat: test default

* feat: test default

* feat: test default

* feat: test default

* feat: change protobuf version

* fix compile

* feat: fix equals

* feat: fix ut。。。

* feat: deserialize

* feat: remove unuse

* Revert "feat: remove unuse"

This reverts commit e72f713319.

* remove unused code

---------

Co-authored-by: Albumen Kevin <jhq0812@gmail.com>
Co-authored-by: earthchen <earthchen@apache.org>
This commit is contained in:
aamingaa 2023-04-11 22:56:58 +08:00 committed by GitHub
parent 6df3b9742d
commit 718bdc1a65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 161 additions and 45 deletions

View File

@ -626,4 +626,6 @@ public interface CommonConstants {
String PAYLOAD = "payload";
String DUBBO_METRICS_CONFIGCENTER_ENABLE = "dubbo.metrics.configcenter.enable";
Integer TRI_EXCEPTION_CODE_NOT_EXISTS = 0;
}

View File

@ -35,6 +35,17 @@ public interface PackableMethod {
byte[] pack(Object obj) throws IOException;
}
interface WrapperUnPack extends UnPack {
default Object unpack(byte[] data) throws IOException, ClassNotFoundException {
return unpack(data, false);
}
Object unpack(byte[] data, boolean isReturnTriException) throws IOException, ClassNotFoundException;
}
interface UnPack {
/**
@ -44,6 +55,7 @@ public interface PackableMethod {
* @throws ClassNotFoundException when no class found
*/
Object unpack(byte[] data) throws IOException, ClassNotFoundException;
}
default Object parseRequest(byte[] data) throws IOException, ClassNotFoundException {
@ -51,7 +63,15 @@ public interface PackableMethod {
}
default Object parseResponse(byte[] data) throws IOException, ClassNotFoundException {
return getResponseUnpack().unpack(data);
return parseResponse(data, false);
}
default Object parseResponse(byte[] data, boolean isReturnTriException) throws IOException, ClassNotFoundException {
UnPack unPack = getResponseUnpack();
if (unPack instanceof WrapperUnPack) {
return ((WrapperUnPack) unPack).unpack(data, isReturnTriException);
}
return unPack.unpack(data);
}
default byte[] packRequest(Object request) throws IOException {

View File

@ -26,7 +26,7 @@
<properties>
<skip_maven_deploy>false</skip_maven_deploy>
<protobuf-java.version>3.21.12</protobuf-java.version>
<protobuf-java.version>3.22.2</protobuf-java.version>
<grpc.version>1.41.0</grpc.version>
</properties>

View File

@ -349,7 +349,7 @@ public class ReflectionPackableMethod implements PackableMethod {
}
}
private static class WrapResponseUnpack implements UnPack {
private static class WrapResponseUnpack implements WrapperUnPack {
private final MultipleSerialization serialization;
private final URL url;
@ -367,6 +367,11 @@ public class ReflectionPackableMethod implements PackableMethod {
@Override
public Object unpack(byte[] data) throws IOException, ClassNotFoundException {
return unpack(data, false);
}
public Object unpack(byte[] data, boolean isReturnTriException) throws IOException, ClassNotFoundException {
TripleCustomerProtocolWapper.TripleResponseWrapper wrapper = TripleCustomerProtocolWapper.TripleResponseWrapper
.parseFrom(data);
final String serializeType = convertHessianFromWrapper(wrapper.getSerializeType());
@ -374,6 +379,9 @@ public class ReflectionPackableMethod implements PackableMethod {
CodecSupport.checkSerialization(serializeType, allSerialize);
ByteArrayInputStream bais = new ByteArrayInputStream(wrapper.getData());
if (isReturnTriException) {
return serialization.deserialize(url, serializeType, Exception.class, bais);
}
return serialization.deserialize(url, serializeType, returnClass, bais);
}
}
@ -457,7 +465,7 @@ public class ReflectionPackableMethod implements PackableMethod {
}
}
private class WrapRequestUnpack implements UnPack {
private class WrapRequestUnpack implements WrapperUnPack {
private final MultipleSerialization serialization;
private final URL url;
@ -474,8 +482,7 @@ public class ReflectionPackableMethod implements PackableMethod {
this.allSerialize = allSerialize;
}
@Override
public Object unpack(byte[] data) throws IOException, ClassNotFoundException {
public Object unpack(byte[] data, boolean isReturnTriException) throws IOException, ClassNotFoundException {
TripleCustomerProtocolWapper.TripleRequestWrapper wrapper = TripleCustomerProtocolWapper.TripleRequestWrapper.parseFrom(
data);

View File

@ -46,6 +46,8 @@ public enum TripleHeaderEnum {
TRI_HEADER_CONVERT("tri-header-convert"),
TRI_EXCEPTION_CODE("tri-exception-code"),
;
static final Map<String, TripleHeaderEnum> enumMap = new HashMap<>();

View File

@ -18,6 +18,7 @@
package org.apache.dubbo.rpc.protocol.tri.call;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.StringUtils;
@ -79,6 +80,26 @@ public abstract class AbstractServerCall implements ServerCall, ServerStream.Lis
protected PackableMethod packableMethod;
protected Map<String, Object> requestMetadata;
private Integer exceptionCode = CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS;
public Integer getExceptionCode() {
return exceptionCode;
}
public void setExceptionCode(Integer exceptionCode) {
this.exceptionCode = exceptionCode;
}
private boolean isNeedReturnException = false;
public boolean isNeedReturnException() {
return isNeedReturnException;
}
public void setNeedReturnException(boolean needReturnException) {
isNeedReturnException = needReturnException;
}
AbstractServerCall(Invoker<?> invoker,
ServerStream stream,
FrameworkModel frameworkModel,
@ -187,7 +208,7 @@ public abstract class AbstractServerCall implements ServerCall, ServerStream.Lis
}
@Override
public final void onMessage(byte[] message) {
public final void onMessage(byte[] message, boolean isReturnTriException) {
ClassLoader tccl = Thread.currentThread()
.getContextClassLoader();
try {
@ -272,6 +293,9 @@ public abstract class AbstractServerCall implements ServerCall, ServerStream.Lis
headers.set(TripleHeaderEnum.GRPC_ENCODING.getHeader(),
compressor.getMessageEncoding());
}
if (!exceptionCode.equals(CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS)) {
headers.set(TripleHeaderEnum.TRI_EXCEPTION_CODE.getHeader(), String.valueOf(exceptionCode));
}
// send header failed will reset stream and close request observer cause no more data will be sent
stream.sendHeader(headers)
.addListener(f -> {
@ -323,7 +347,7 @@ public abstract class AbstractServerCall implements ServerCall, ServerStream.Lis
return;
}
closed = true;
stream.complete(status, attachments);
stream.complete(status, attachments, isNeedReturnException, exceptionCode);
}
protected Long parseTimeoutToMills(String timeoutVal) {
@ -361,7 +385,7 @@ public abstract class AbstractServerCall implements ServerCall, ServerStream.Lis
return;
}
closed = true;
stream.complete(status, null);
stream.complete(status, null, false, CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS);
LOGGER.error(PROTOCOL_FAILED_REQUEST, "", "", "Triple request error: service=" + serviceName + " method" + methodName,
status.asException());
}

View File

@ -53,7 +53,7 @@ public interface ClientCall {
* @param status response status
* @param trailers response trailers
*/
void onClose(TriRpcStatus status, Map<String, Object> trailers);
void onClose(TriRpcStatus status, Map<String, Object> trailers, boolean isReturnTriException);
}
/**

View File

@ -46,7 +46,7 @@ public class ObserverToClientCallListenerAdapter implements ClientCall.Listener
}
@Override
public void onClose(TriRpcStatus status, Map<String, Object> trailers) {
public void onClose(TriRpcStatus status, Map<String, Object> trailers, boolean isReturnTriException) {
if (status.isOk()) {
delegate.onCompleted();
} else {

View File

@ -68,7 +68,7 @@ public class TripleClientCall implements ClientCall, ClientStream.Listener {
// stream listener start
@Override
public void onMessage(byte[] message) {
public void onMessage(byte[] message, boolean isReturnTriException) {
if (done) {
LOGGER.warn(PROTOCOL_STREAM_LISTENER, "", "",
"Received message from closed stream,connection=" + connectionClient + " service="
@ -77,13 +77,13 @@ public class TripleClientCall implements ClientCall, ClientStream.Listener {
return;
}
try {
final Object unpacked = requestMetadata.packableMethod.parseResponse(message);
final Object unpacked = requestMetadata.packableMethod.parseResponse(message, isReturnTriException);
listener.onMessage(unpacked);
} catch (Throwable t) {
TriRpcStatus status = TriRpcStatus.INTERNAL.withDescription("Deserialize response failed")
.withCause(t);
cancelByLocal(status.asException());
listener.onClose(status,null);
listener.onClose(status,null, false);
LOGGER.error(PROTOCOL_FAILED_RESPONSE, "", "", String.format("Failed to deserialize triple response, service=%s, method=%s,connection=%s",
connectionClient, requestMetadata.service, requestMetadata.method.getMethodName()), t);
}
@ -98,18 +98,18 @@ public class TripleClientCall implements ClientCall, ClientStream.Listener {
if (requestMetadata.cancellationContext != null) {
requestMetadata.cancellationContext.cancel(status.asException());
}
onComplete(status, null, null);
onComplete(status, null, null, false);
}
@Override
public void onComplete(TriRpcStatus status, Map<String, Object> attachments,
Map<String, String> excludeHeaders) {
Map<String, String> excludeHeaders, boolean isReturnTriException) {
if (done) {
return;
}
done = true;
try {
listener.onClose(status, StreamUtils.toAttachments(attachments));
listener.onClose(status, StreamUtils.toAttachments(attachments), isReturnTriException);
} catch (Throwable t) {
cancelByLocal(
TriRpcStatus.INTERNAL.withDescription("Close stream error").withCause(t)
@ -191,7 +191,7 @@ public class TripleClientCall implements ClientCall, ClientStream.Listener {
requestMetadata.method), t);
cancelByLocal(t);
listener.onClose(TriRpcStatus.INTERNAL.withDescription("Serialize request failed")
.withCause(t), null);
.withCause(t), null, false);
}
}
// stream listener end

View File

@ -38,11 +38,11 @@ public class UnaryClientCallListener implements ClientCall.Listener {
}
@Override
public void onClose(TriRpcStatus status, Map<String, Object> trailers) {
public void onClose(TriRpcStatus status, Map<String, Object> trailers, boolean isReturnTriException) {
AppResponse result = new AppResponse();
result.setObjectAttachments(trailers);
if (status.isOk()) {
if (appResponse instanceof Exception) {
if (isReturnTriException) {
result.setException((Exception) appResponse);
} else {
result.setValue(appResponse);

View File

@ -18,6 +18,7 @@
package org.apache.dubbo.rpc.protocol.tri.call;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.TriRpcStatus;
import org.apache.dubbo.rpc.protocol.tri.observer.ServerCallToObserverAdapter;
@ -55,12 +56,24 @@ public class UnaryServerCallListener extends AbstractServerCallListener {
@Override
protected void doOnResponseHasException(Throwable t) {
if (needWrapper) {
onReturn(t);
onReturnException((Exception) t);
} else {
super.doOnResponseHasException(t);
}
}
private void onReturnException(Exception value) {
TriRpcStatus status = TriRpcStatus.getStatus(value);
int exceptionCode = status.code.code;
if (exceptionCode == TriRpcStatus.UNKNOWN.code.code) {
exceptionCode = RpcException.BIZ_EXCEPTION;
}
responseObserver.setExceptionCode(exceptionCode);
responseObserver.setNeedReturnException(true);
onReturn(value);
}
@Override
public void onComplete() {
invoke();

View File

@ -17,6 +17,7 @@
package org.apache.dubbo.rpc.protocol.tri.observer;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.CancellationContext;
@ -36,6 +37,26 @@ public class ServerCallToObserverAdapter<T> extends CancelableStreamObserver<T>
private Map<String, Object> attachments;
private boolean terminated = false;
private boolean isNeedReturnException = false;
private Integer exceptionCode = CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS;
public Integer getExceptionCode() {
return exceptionCode;
}
public void setExceptionCode(Integer exceptionCode) {
this.exceptionCode = exceptionCode;
}
public boolean isNeedReturnException() {
return isNeedReturnException;
}
public void setNeedReturnException(boolean needReturnException) {
isNeedReturnException = needReturnException;
}
public ServerCallToObserverAdapter(AbstractServerCall call,
CancellationContext cancellationContext) {
this.call = call;
@ -61,6 +82,8 @@ public class ServerCallToObserverAdapter<T> extends CancelableStreamObserver<T>
throw new IllegalStateException(
"Stream observer has been terminated, no more data is allowed");
}
call.setExceptionCode(exceptionCode);
call.setNeedReturnException(isNeedReturnException);
call.sendMessage(data);
}
@ -74,6 +97,8 @@ public class ServerCallToObserverAdapter<T> extends CancelableStreamObserver<T>
if (isTerminated()) {
return;
}
call.setExceptionCode(exceptionCode);
call.setNeedReturnException(isNeedReturnException);
call.close(status, attachments);
setTerminated();
}

View File

@ -52,7 +52,7 @@ public interface ClientStream extends Stream {
* @param reserved triple protocol reserved data
*/
default void onComplete(TriRpcStatus status, Map<String, Object> attachments,
Map<String, String> reserved) {
Map<String, String> reserved, boolean isReturnTriException) {
onComplete(status, attachments);
}

View File

@ -51,7 +51,7 @@ public interface ServerStream extends Stream {
* @param attachments response attachments
* @return a future that indicates the completion of send trailers
*/
Future<?> complete(TriRpcStatus status, Map<String, Object> attachments);
Future<?> complete(TriRpcStatus status, Map<String, Object> attachments, boolean isNeedReturnException, int exceptionCode);
/**
* Send message to client

View File

@ -43,7 +43,7 @@ public interface Stream {
*
* @param message message received from remote peer
*/
void onMessage(byte[] message);
void onMessage(byte[] message, boolean isReturnTriException);
/**
* Callback when receive cancel signal.

View File

@ -17,6 +17,7 @@
package org.apache.dubbo.rpc.protocol.tri.stream;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.TriRpcStatus;
@ -83,6 +84,8 @@ public class TripleClientStream extends AbstractStream implements ClientStream {
private boolean halfClosed;
private boolean rst;
private boolean isReturnTriException = false;
// for test
TripleClientStream(FrameworkModel frameworkModel,
Executor executor,
@ -230,10 +233,10 @@ public class TripleClientStream extends AbstractStream implements ClientStream {
void handleH2TransportError(TriRpcStatus status) {
writeQueue.enqueue(CancelQueueCommand.createCommand(streamChannelFuture, Http2Error.NO_ERROR));
TripleClientStream.this.rst = true;
finishProcess(status, null);
finishProcess(status, null, false);
}
void finishProcess(TriRpcStatus status, Http2Headers trailers) {
void finishProcess(TriRpcStatus status, Http2Headers trailers, boolean isReturnTriException) {
final Map<String, String> reserved = filterReservedHeaders(trailers);
final Map<String, Object> attachments = headersToMap(trailers, () -> {
return reserved.get(TripleHeaderEnum.TRI_HEADER_CONVERT.getHeader());
@ -245,7 +248,7 @@ public class TripleClientStream extends AbstractStream implements ClientStream {
} else {
detailStatus = status;
}
listener.onComplete(detailStatus, attachments, reserved);
listener.onComplete(detailStatus, attachments, reserved, isReturnTriException);
}
private TriRpcStatus validateHeaderStatus(Http2Headers headers) {
@ -286,6 +289,13 @@ public class TripleClientStream extends AbstractStream implements ClientStream {
// todo support full payload compressor
CharSequence messageEncoding = headers.get(TripleHeaderEnum.GRPC_ENCODING.getHeader());
CharSequence triExceptionCode = headers.get(TripleHeaderEnum.TRI_EXCEPTION_CODE.getHeader());
if (triExceptionCode != null) {
Integer triExceptionCodeNum = Integer.parseInt(triExceptionCode.toString());
if (!(triExceptionCodeNum.equals(CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS))) {
isReturnTriException = true;
}
}
if (null != messageEncoding) {
String compressorStr = messageEncoding.toString();
if (!Identity.IDENTITY.getMessageEncoding().equals(compressorStr)) {
@ -303,11 +313,11 @@ public class TripleClientStream extends AbstractStream implements ClientStream {
TriDecoder.Listener listener = new TriDecoder.Listener() {
@Override
public void onRawMessage(byte[] data) {
TripleClientStream.this.listener.onMessage(data);
TripleClientStream.this.listener.onMessage(data, isReturnTriException);
}
public void close() {
finishProcess(statusFromTrailers(trailers), trailers);
finishProcess(statusFromTrailers(trailers), trailers, isReturnTriException);
}
};
deframer = new TriDecoder(decompressor, listener);
@ -324,7 +334,7 @@ public class TripleClientStream extends AbstractStream implements ClientStream {
this.trailers = trailers;
TriRpcStatus status = statusFromTrailers(trailers);
if (deframer == null) {
finishProcess(status, trailers);
finishProcess(status, trailers, false);
}
if (deframer != null) {
deframer.close();
@ -464,7 +474,7 @@ public class TripleClientStream extends AbstractStream implements ClientStream {
executor.execute(() -> {
transportError = TriRpcStatus.CANCELLED
.withDescription("Canceled by remote peer, errorCode=" + errorCode);
finishProcess(transportError, null);
finishProcess(transportError, null, false);
});
}
}

View File

@ -18,6 +18,7 @@
package org.apache.dubbo.rpc.protocol.tri.stream;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.StringUtils;
@ -157,8 +158,8 @@ public class TripleServerStream extends AbstractStream implements ServerStream {
@Override
public ChannelFuture complete(TriRpcStatus status, Map<String, Object> attachments) {
Http2Headers trailers = getTrailers(status, attachments);
public ChannelFuture complete(TriRpcStatus status, Map<String, Object> attachments, boolean isNeedReturnException, int exceptionCode) {
Http2Headers trailers = getTrailers(status, attachments, isNeedReturnException, CommonConstants.TRI_EXCEPTION_CODE_NOT_EXISTS);
return sendTrailers(trailers);
}
@ -183,7 +184,7 @@ public class TripleServerStream extends AbstractStream implements ServerStream {
});
}
private Http2Headers getTrailers(TriRpcStatus rpcStatus, Map<String, Object> attachments) {
private Http2Headers getTrailers(TriRpcStatus rpcStatus, Map<String, Object> attachments, boolean isNeedReturnException, int exceptionCode) {
DefaultHttp2Headers headers = new DefaultHttp2Headers();
if (!headerSent) {
headers.status(HttpResponseStatus.OK.codeAsText());
@ -471,7 +472,7 @@ public class TripleServerStream extends AbstractStream implements ServerStream {
@Override
public void onRawMessage(byte[] data) {
listener.onMessage(data);
listener.onMessage(data, false);
}
@Override

View File

@ -18,6 +18,7 @@
package org.apache.dubbo.rpc.protocol.tri;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.Exporter;
@ -90,7 +91,7 @@ class ExceptionUtilsTest {
ApplicationModel applicationModel = ApplicationModel.defaultModel();
URL providerUrl = URL.valueOf(
"tri://127.0.0.1:" + availablePort + "/" + IGreeter2.class.getName());
"tri://127.0.0.1:" + availablePort + "/" + IGreeter2.class.getName()).addParameter(CommonConstants.TIMEOUT_KEY, 10000);;
ModuleServiceRepository serviceRepository = applicationModel.getDefaultModule()
.getServiceRepository();
@ -111,7 +112,7 @@ class ExceptionUtilsTest {
Exporter<IGreeter2> export = protocol.export(invoker);
URL consumerUrl = URL.valueOf(
"tri://127.0.0.1:" + availablePort + "/" + IGreeter2.class.getName());
"tri://127.0.0.1:" + availablePort + "/" + IGreeter2.class.getName()).addParameter(CommonConstants.TIMEOUT_KEY, 10000);
ConsumerModel consumerModel = new ConsumerModel(consumerUrl.getServiceKey(), null,
serviceDescriptor, null,
@ -128,6 +129,10 @@ class ExceptionUtilsTest {
} catch (IGreeterException e) {
Assertions.assertEquals(EXPECT_RESPONSE_MSG, e.getMessage());
}
Exception e = greeterProxy.echoException(REQUEST_MSG);
Assertions.assertEquals(EXPECT_RESPONSE_MSG, e.getMessage());
export.unexport();
protocol.destroy();
// resource recycle.

View File

@ -28,10 +28,10 @@ class PbUnpackTest {
@Test
void unpack() throws IOException {
HealthCheckRequest req = HealthCheckRequest.newBuilder()
.setService("service")
.build();
PbUnpack<HealthCheckRequest> unpack=new PbUnpack<>(HealthCheckRequest.class);
HealthCheckRequest obj= (HealthCheckRequest) unpack.unpack(req.toByteArray());
Assertions.assertEquals("service",obj.getService());
.setService("service")
.build();
PbUnpack<HealthCheckRequest> unpack = new PbUnpack<>(HealthCheckRequest.class);
HealthCheckRequest obj = (HealthCheckRequest) unpack.unpack(req.toByteArray());
Assertions.assertEquals("service", obj.getService());
}
}

View File

@ -80,7 +80,7 @@ class ReflectionServerCallTest {
Collections.emptyList(),
ImmediateEventExecutor.INSTANCE);
call2.onHeader(Collections.emptyMap());
call2.onMessage(new byte[0]);
call2.onMessage(new byte[0], false);
call2.onComplete();
}
}

View File

@ -66,7 +66,7 @@ class StubServerCallTest {
service, method,
ImmediateEventExecutor.INSTANCE);
call.onHeader(Collections.emptyMap());
call.onMessage(new byte[0]);
call.onMessage(new byte[0], false);
call.onComplete();
}
}

View File

@ -39,7 +39,7 @@ public class MockClientStreamListener implements ClientStream.Listener {
}
@Override
public void onMessage(byte[] message) {
public void onMessage(byte[] message, boolean isNeedReturnException) {
this.message = message;
}

View File

@ -23,4 +23,6 @@ public interface IGreeter2 {
* Use request to respond
*/
String echo(String request) throws IGreeterException;
Exception echoException(String request);
}

View File

@ -21,4 +21,9 @@ public class IGreeter2Impl implements IGreeter2{
public String echo(String request) throws IGreeterException {
throw new IGreeterException("I am self define exception");
}
@Override
public Exception echoException(String request) {
return new IGreeterException("I am self define exception");
}
}