solution: health check endpoint

fix: #111
This commit is contained in:
Igor Artamonov
2021-10-20 23:10:41 -04:00
parent a04c1f3e66
commit e205985da3
13 changed files with 471 additions and 7 deletions

View File

@@ -0,0 +1,82 @@
/**
* Copyright (c) 2021 EmeraldPay, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.emeraldpay.dshackle.config
import io.emeraldpay.grpc.Chain
import spock.lang.Specification
class HealthConfigReaderSpec extends Specification {
HealthConfigReader reader = new HealthConfigReader()
def "Read empty"() {
setup:
def config = this.class.getClassLoader().getResourceAsStream("dshackle-health-empty.yaml")
when:
def act = reader.read(config)
then:
!act.enabled
act.port == 8082
act.host == "127.0.0.1"
act.path == "/health"
act.configs().size() == 0
}
def "Read single"() {
setup:
def config = this.class.getClassLoader().getResourceAsStream("dshackle-health-1.yaml")
when:
def act = reader.read(config)
then:
act.enabled
act.port == 8082
act.host == "127.0.0.1"
act.path == "/health"
with(act.configs()) {
size() == 1
with(it[0]) {
it.blockchain == Chain.ETHEREUM
it.minAvailable == 2
}
}
}
def "Read multiple"() {
setup:
def config = this.class.getClassLoader().getResourceAsStream("dshackle-health-2.yaml")
when:
def act = reader.read(config)
then:
act.enabled
act.port == 10003
act.host == "0.0.0.0"
act.path == "/healtz"
with(act.configs().toSorted { it.blockchain.id }) {
size() == 2
with(it[0]) {
it.blockchain == Chain.BITCOIN
it.minAvailable == 1
}
with(it[1]) {
it.blockchain == Chain.ETHEREUM
it.minAvailable == 2
}
}
}
}

View File

@@ -15,7 +15,7 @@
*/
package io.emeraldpay.dshackle.config
import io.emeraldpay.dshackle.FileResolver
import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.grpc.Chain
import spock.lang.Specification
@@ -73,6 +73,16 @@ class MainConfigReaderSpec extends Specification {
blockchain == Chain.TESTNET_RINKEBY
}
}
with(act.health) {
it.enabled
with(it.configs()) {
it.size() == 1
with(it[0]) {
it.blockchain == Chain.ETHEREUM
it.minAvailable == 1
}
}
}
act.upstreams != null
with(act.upstreams) {
defaultOptions != null

View File

@@ -0,0 +1,127 @@
/**
* Copyright (c) 2021 EmeraldPay, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.emeraldpay.dshackle.monitoring
import io.emeraldpay.dshackle.config.HealthConfig
import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
import io.emeraldpay.grpc.Chain
import spock.lang.Specification
class HealthCheckSetupSpec extends Specification {
def "OK when meets availability - 1"() {
setup:
def config = new HealthConfig().tap {
it.chains[Chain.ETHEREUM] = new HealthConfig.ChainConfig(
Chain.ETHEREUM, 1
)
}
def up1 = Mock(Upstream)
def ethereumUpstreams = Mock(Multistream)
def multistream = Mock(MultistreamHolder)
def check = new HealthCheckSetup(config, multistream)
when:
def act = check.health
then:
act == "OK"
1 * multistream.getUpstream(Chain.ETHEREUM) >> ethereumUpstreams
1 * ethereumUpstreams.available >> true
1 * ethereumUpstreams.getAll() >> [up1]
1 * up1.status >> UpstreamAvailability.OK
}
def "OK when meets availability - 1 - bitcoin"() {
setup:
def config = new HealthConfig().tap {
it.chains[Chain.BITCOIN] = new HealthConfig.ChainConfig(
Chain.BITCOIN, 1
)
}
def up1 = Mock(Upstream)
def bitcoinUpstreams = Mock(Multistream)
def multistream = Mock(MultistreamHolder)
def check = new HealthCheckSetup(config, multistream)
when:
def act = check.health
then:
act == "OK"
1 * multistream.getUpstream(Chain.BITCOIN) >> bitcoinUpstreams
1 * bitcoinUpstreams.available >> true
1 * bitcoinUpstreams.getAll() >> [up1]
1 * up1.status >> UpstreamAvailability.OK
}
def "OK when meets availability - 2/3"() {
setup:
def config = new HealthConfig().tap {
it.chains[Chain.ETHEREUM] = new HealthConfig.ChainConfig(
Chain.ETHEREUM, 2
)
}
def up1 = Mock(Upstream)
def up2 = Mock(Upstream)
def up3 = Mock(Upstream)
def ethereumUpstreams = Mock(Multistream)
def multistream = Mock(MultistreamHolder)
def check = new HealthCheckSetup(config, multistream)
when:
def act = check.health
then:
act == "OK"
1 * multistream.getUpstream(Chain.ETHEREUM) >> ethereumUpstreams
1 * ethereumUpstreams.available >> true
1 * ethereumUpstreams.getAll() >> [up1, up2, up3]
1 * up1.status >> UpstreamAvailability.OK
1 * up2.status >> UpstreamAvailability.SYNCING
1 * up3.status >> UpstreamAvailability.OK
}
def "OK when doesn't meet availability - 2/3"() {
setup:
def config = new HealthConfig().tap {
it.chains[Chain.ETHEREUM] = new HealthConfig.ChainConfig(
Chain.ETHEREUM, 2
)
}
def up1 = Mock(Upstream)
def up2 = Mock(Upstream)
def up3 = Mock(Upstream)
def ethereumUpstreams = Mock(Multistream)
def multistream = Mock(MultistreamHolder)
def check = new HealthCheckSetup(config, multistream)
when:
def act = check.health
then:
act != "OK"
1 * multistream.getUpstream(Chain.ETHEREUM) >> ethereumUpstreams
1 * ethereumUpstreams.available >> true
1 * ethereumUpstreams.getAll() >> [up1, up2, up3]
1 * up1.status >> UpstreamAvailability.OK
1 * up2.status >> UpstreamAvailability.SYNCING
1 * up3.status >> UpstreamAvailability.LAGGING
}
}

View File

@@ -16,6 +16,12 @@ cache:
enabled: true
host: redis-master
health:
port: 8083
blockchains:
- chain: ethereum
min-available: 1
proxy:
port: 8082
tls:

View File

@@ -0,0 +1,6 @@
version: v1
health:
blockchains:
- chain: ethereum
min-available: 2

View File

@@ -0,0 +1,11 @@
version: v1
health:
port: 10003
host: 0.0.0.0
path: /healtz
blockchains:
- chain: ethereum
min-available: 2
- chain: bitcoin
min-available: 1

View File

@@ -0,0 +1,3 @@
version: v1
health: