Delay RPC arguments deserialisation to allow routing of errors

This commit is contained in:
Andras Slemmer
2017-09-26 10:53:07 +01:00
parent 20a9892123
commit 9d115a2111
5 changed files with 36 additions and 60 deletions

View File

@ -19,6 +19,7 @@ import net.corda.core.internal.LifeCycle
import net.corda.core.messaging.RPCOps
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationDefaults.RPC_SERVER_CONTEXT
import net.corda.core.serialization.deserialize
import net.corda.core.utilities.Try
import net.corda.core.utilities.debug
import net.corda.core.utilities.loggerFor
@ -260,34 +261,26 @@ class RPCServer(
private fun clientArtemisMessageHandler(artemisMessage: ClientMessage) {
lifeCycle.requireState(State.STARTED)
// Attempt de-serialisation of the RPC request message, in such a way that we can route the error back to
// the RPC that was being tried if it fails in a method/rpc specific way.
val clientToServerTry = Try.on { RPCApi.ClientToServer.fromClientMessage(RPC_SERVER_CONTEXT, artemisMessage) }
val clientToServer = try {
clientToServerTry.getOrThrow()
} catch (e: RPCApi.ArgumentDeserialisationException) {
// The exception itself has a more informative error message, and this could be caused by buggy apps, so
// let's just log it as a warning instead of an error. Relay the failure to the client so they can see it.
log.warn("Inbound RPC failed", e)
sendReply(e.reqWithNoArguments.id, e.reqWithNoArguments.clientAddress, Try.Failure(e.cause!!))
return
} catch (e: Exception) {
// This path indicates something more fundamental went wrong, like a missing message header.
log.error("Failed to parse an inbound RPC: version skew between client and server?", e)
return
} finally {
artemisMessage.acknowledge()
}
// Now try dispatching the request itself.
val clientToServer = RPCApi.ClientToServer.fromClientMessage(artemisMessage)
log.debug { "-> RPC -> $clientToServer" }
when (clientToServer) {
is RPCApi.ClientToServer.RpcRequest -> {
val rpcContext = RpcContext(currentUser = getUser(artemisMessage))
rpcExecutor!!.submit {
val result = invokeRpc(rpcContext, clientToServer.methodName, clientToServer.arguments)
sendReply(clientToServer.id, clientToServer.clientAddress, result)
val arguments = Try.on {
clientToServer.serialisedArguments.deserialize<List<Any?>>(context = RPC_SERVER_CONTEXT)
}
when (arguments) {
is Try.Success -> {
val rpcContext = RpcContext(currentUser = getUser(artemisMessage))
rpcExecutor!!.submit {
val result = invokeRpc(rpcContext, clientToServer.methodName, arguments.value)
sendReply(clientToServer.id, clientToServer.clientAddress, result)
}
}
is Try.Failure -> {
// We failed to deserialise the arguments, route back the error
log.warn("Inbound RPC failed", arguments.exception)
sendReply(clientToServer.id, clientToServer.clientAddress, arguments)
}
}
}
is RPCApi.ClientToServer.ObservablesClosed -> {