solution: mark Upstream status right after WS connect/disconnect

This commit is contained in:
Igor Artamonov
2021-09-22 17:08:43 -04:00
parent 1f864bdbe3
commit bd8c0f7c19
7 changed files with 55 additions and 14 deletions

View File

@@ -61,7 +61,7 @@ abstract class DefaultUpstream(
return status.get().status
}
fun setStatus(avail: UpstreamAvailability) {
open fun setStatus(avail: UpstreamAvailability) {
status.updateAndGet { curr ->
Status(curr.lag, avail, statusByLag(curr.lag, avail))
}

View File

@@ -74,7 +74,8 @@ open class EthereumRpcUpstream(
open fun createHead(): Head {
return if (ethereumWsFactory != null) {
val ws = ethereumWsFactory.create(null).apply {
// do not set upstream to the WS, since it doesn't control the RPC upstream
val ws = ethereumWsFactory.create(null, null, null).apply {
connect()
}
val wsHead = EthereumWsHead(ws).apply {

View File

@@ -32,7 +32,7 @@ import reactor.core.scheduler.Schedulers
import java.time.Duration
import java.util.concurrent.Executors
class EthereumUpstreamValidator(
open class EthereumUpstreamValidator(
private val upstream: EthereumUpstream,
private val options: UpstreamsConfig.Options
) {
@@ -43,7 +43,7 @@ class EthereumUpstreamValidator(
private val objectMapper: ObjectMapper = Global.objectMapper
fun validate(): Mono<UpstreamAvailability> {
open fun validate(): Mono<UpstreamAvailability> {
return upstream
.getApi()
.read(JsonRpcRequest("eth_syncing", listOf()))

View File

@@ -21,6 +21,8 @@ import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.SilentException
import io.emeraldpay.dshackle.config.AuthConfig
import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.upstream.DefaultUpstream
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import io.emeraldpay.dshackle.upstream.rpcclient.ResponseWSParser
@@ -64,15 +66,17 @@ class EthereumWsFactory(
var basicAuth: AuthConfig.ClientBasicAuth? = null
fun create(rpcMetrics: RpcMetrics?): EthereumWs {
return EthereumWs(uri, origin, basicAuth, rpcMetrics)
fun create(upstream: DefaultUpstream?, validator: EthereumUpstreamValidator?, rpcMetrics: RpcMetrics?): EthereumWs {
return EthereumWs(uri, origin, basicAuth, rpcMetrics, upstream, validator)
}
class EthereumWs(
private val uri: URI,
private val origin: URI,
private val basicAuth: AuthConfig.ClientBasicAuth?,
private val rpcMetrics: RpcMetrics?
private val rpcMetrics: RpcMetrics?,
private val upstream: DefaultUpstream?,
private val validator: EthereumUpstreamValidator?
) : AutoCloseable {
companion object {
@@ -154,6 +158,8 @@ class EthereumWsFactory(
connection = HttpClient.create()
.doOnDisconnected {
log.info("Disconnected from $uri")
// mark upstream as UNAVAIL
upstream?.setStatus(UpstreamAvailability.UNAVAILABLE)
if (keepConnection) {
tryReconnectLater()
}
@@ -203,6 +209,9 @@ class EthereumWsFactory(
//restart backoff after connection
currentBackOff = reconnectBackoff.start()
//validate the connection, it can also be UNAVAIL if market as such after disconnect
validator?.validate()
val consumer = inbound
// Accept up to 15Mb messages, same config is used by Geth
.aggregateFrames(15 * 1024 * 1024)

View File

@@ -53,6 +53,7 @@ class EthereumWsUpstream(
private val api: JsonRpcWsClient
private var validatorSubscription: Disposable? = null
private val validator: EthereumUpstreamValidator
init {
val metricsTags = listOf(
@@ -72,7 +73,9 @@ class EthereumWsUpstream(
.register(Metrics.globalRegistry)
)
connection = ethereumWsFactory.create(metrics)
validator = EthereumUpstreamValidator(this, getOptions())
connection = ethereumWsFactory.create(this, validator, metrics)
head = EthereumWsHead(connection)
api = JsonRpcWsClient(connection)
}
@@ -102,7 +105,6 @@ class EthereumWsUpstream(
head.start()
log.debug("Start validation for upstream ${this.getId()}")
val validator = EthereumUpstreamValidator(this, getOptions())
validatorSubscription = validator.start()
.subscribe(this::setStatus)
}