fixed re-subscription

This commit is contained in:
Maksim Fomenkov
2022-12-20 16:33:25 +03:00
parent f6c6c8d4ef
commit a1c234d3bf

View File

@@ -17,6 +17,7 @@ import reactor.core.publisher.SignalType
import reactor.core.publisher.Sinks import reactor.core.publisher.Sinks
import java.time.Duration import java.time.Duration
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.function.Consumer
@Service @Service
class SubscribeNodeStatus( class SubscribeNodeStatus(
@@ -51,7 +52,7 @@ class SubscribeNodeStatus(
.flatMap { ms -> .flatMap { ms ->
ms.getAll().map { up -> ms.getAll().map { up ->
knownUpstreams[up.getId()] = true knownUpstreams[up.getId()] = true
subscribeUpstreamUpdates(ms.chain, up, duration) subscribeUpstreamUpdates(ms.chain, up, duration) { r -> knownUpstreams.remove(r) }
} }
} }
) )
@@ -64,7 +65,10 @@ class SubscribeNodeStatus(
.distinctUntilChanged { .distinctUntilChanged {
it.getId() it.getId()
} }
.filter { knownUpstreams.getOrDefault(it.getId(), false) }.flatMap { .filter {
!knownUpstreams.getOrDefault(it.getId(), false)
}
.flatMap {
knownUpstreams[it.getId()] = true knownUpstreams[it.getId()] = true
Flux.concat( Flux.concat(
Mono.just( Mono.just(
@@ -74,7 +78,7 @@ class SubscribeNodeStatus(
.setStatus(buildStatus(it.getStatus(), it.getHead().getCurrentHeight())) .setStatus(buildStatus(it.getStatus(), it.getHead().getCurrentHeight()))
.build() .build()
), ),
subscribeUpstreamUpdates(ms.chain, it, duration) subscribeUpstreamUpdates(ms.chain, it, duration) { r -> knownUpstreams.remove(r) }
) )
} }
} }
@@ -86,30 +90,48 @@ class SubscribeNodeStatus(
private fun subscribeUpstreamUpdates( private fun subscribeUpstreamUpdates(
chain: Chain, chain: Chain,
upstream: Upstream, upstream: Upstream,
timespan: Duration timespan: Duration,
onUnavailable: Consumer<String>
): Flux<NodeStatusResponse> { ): Flux<NodeStatusResponse> {
val retry = Sinks.many().multicast().directBestEffort<Boolean>() val retry = Sinks.many().multicast().directBestEffort<Boolean>()
val heads = Mono.just(upstream).repeatWhen { retry.asFlux() }.sample(RETRY_TIMEOUT).flatMap { up -> val cancel = Sinks.many().multicast().directBestEffort<Boolean>()
up.getHead().getFlux().map { block ->
NodeStatusResponse.newBuilder() val heads = Mono.just(upstream)
.setNodeId(up.getId()) .repeatWhen {
.setStatus(buildStatus(up.getStatus(), block.height)) retry.asFlux()
.build() }
}.doFinally { .sample(RETRY_TIMEOUT)
// retry when subscribed head stopped .takeUntilOther(cancel.asFlux()).flatMap { up ->
if (it == SignalType.ON_COMPLETE) { up.getHead().getFlux()
retry.tryEmitNext(true) .takeUntilOther(cancel.asFlux())
} .map { block ->
} NodeStatusResponse.newBuilder()
}.sample(timespan) .setNodeId(up.getId())
.setStatus(buildStatus(up.getStatus(), block.height))
.build()
}.doFinally {
// retry when subscribed head stopped
if (it == SignalType.ON_COMPLETE) {
retry.tryEmitNext(true)
}
}
}.sample(timespan)
val statuses = upstream.observeStatus()
.distinctUntilChanged()
.takeUntil{it == UpstreamAvailability.UNAVAILABLE}
.map {
if (it == UpstreamAvailability.UNAVAILABLE) {
onUnavailable.accept(upstream.getId())
cancel.tryEmitNext(true)
}
NodeStatusResponse.newBuilder()
.setNodeId(upstream.getId())
.setStatus(buildStatus(it, upstream.getHead().getCurrentHeight()))
.setDescription(buildDescription(chain, upstream))
.build()
}.sample(timespan)
val statuses = upstream.observeStatus().distinctUntilChanged().map {
NodeStatusResponse.newBuilder()
.setNodeId(upstream.getId())
.setStatus(buildStatus(it, upstream.getHead().getCurrentHeight()))
.setDescription(buildDescription(chain, upstream))
.build()
}.sample(timespan)
return Flux.merge(heads, statuses) return Flux.merge(heads, statuses)
} }