problem: doesn't retry on upstream error

This commit is contained in:
Igor Artamonov
2019-08-31 23:31:58 -04:00
parent aa3f66c059
commit 5e6b586cf8
3 changed files with 39 additions and 2 deletions

View File

@@ -134,6 +134,7 @@ class NativeCall(
.flatMap { api ->
api.execute(ctx.id, ctx.payload.method, ctx.payload.params).map { Tuples.of(it, api.upstream!!) }
}
.retry(3)
.reduce(ctx.callQuorum, {res, a ->
if (res.record(a.t1, a.t2)) {
repeatControl.onComplete()

View File

@@ -32,6 +32,7 @@ import reactor.test.StepVerifier
import spock.lang.Specification
import java.time.Duration
import java.util.concurrent.TimeoutException
class NativeCallSpec extends Specification {
@@ -300,4 +301,32 @@ class NativeCallSpec extends Specification {
1 * cacheMock.execute(10, "eth_test", []) >> Mono.just('{"result": "foo"}'.bytes)
new String(act.block().payload) == '{"result": "foo"}'
}
def "Retries on error"() {
setup:
def quorum = Spy(new AlwaysQuorum())
def upstreams = Stub(Upstreams)
RpcClient rpcClient = Stub(RpcClient)
def apiMock = TestingCommons.api(rpcClient)
apiMock.upstream = Stub(Upstream)
apiMock.answer("eth_test", [], null, 1, new TimeoutException("test 1"))
apiMock.answer("eth_test", [], null, 1, new TimeoutException("test 2"))
apiMock.answerOnce("eth_test", [], "bar")
def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper())
def call = new NativeCall.CallContext(1, TestingCommons.aggregatedUpstream(apiMock),
Selector.empty, quorum,
new NativeCall.ParsedCallDetails("eth_test", []))
when:
def resp = nativeCall.executeOnRemote(call).block(Duration.ofSeconds(2))
def act = objectMapper.readValue(resp.payload, Map)
then:
act == [jsonrpc:"2.0", id:1, result: "bar"]
1 * quorum.record(_, _)
1 * quorum.getResult()
}
}

View File

@@ -45,8 +45,9 @@ class EthereumApiMock extends DirectEthereumApi {
return answer(method, params, result, 1)
}
EthereumApiMock answer(@NotNull String method, List<Object> params, Object result, Integer limit = null) {
predefined << new PredefinedResponse(method: method, params: params, result: result, limit: limit)
EthereumApiMock answer(@NotNull String method, List<Object> params, Object result,
Integer limit = null, Throwable exception = null) {
predefined << new PredefinedResponse(method: method, params: params, result: result, limit: limit, exception: exception)
return this
}
@@ -55,6 +56,11 @@ class EthereumApiMock extends DirectEthereumApi {
def predefined = predefined.find { it.isSame(id, method, params) }
ResponseJson json = new ResponseJson<Object, Integer>(id: id)
if (predefined != null) {
if (predefined.exception != null) {
predefined.onCalled()
predefined.print()
throw predefined.exception
}
json.result = predefined.result
} else {
log.error("Method ${method} with ${params} is not mocked")
@@ -84,6 +90,7 @@ class EthereumApiMock extends DirectEthereumApi {
List params
Object result
Integer limit
Throwable exception
boolean isSame(int id, String method, List<?> params) {
if (limit != null) {