subscription heartbeat (#715)

This commit is contained in:
Vyacheslav
2025-08-26 18:49:54 +03:00
committed by GitHub
parent c75bdf7d92
commit 2ba0dd9979
3 changed files with 24 additions and 3 deletions

View File

@@ -32,5 +32,6 @@ class Defaults {
val grpcServerPermitKeepAliveTime: Long = 15 val grpcServerPermitKeepAliveTime: Long = 15
val grpcServerMaxConnectionIdle: Long = 3600 val grpcServerMaxConnectionIdle: Long = 3600
val multistreamUnavailableMethodDisableDuration: Long = 20 // minutes val multistreamUnavailableMethodDisableDuration: Long = 20 // minutes
val nativeSubscribeHeartbeatInterval: Duration = Duration.ofSeconds(30)
} }
} }

View File

@@ -19,6 +19,7 @@ import com.google.protobuf.ByteString
import io.emeraldpay.api.proto.BlockchainOuterClass import io.emeraldpay.api.proto.BlockchainOuterClass
import io.emeraldpay.api.proto.BlockchainOuterClass.NativeSubscribeReplyItem import io.emeraldpay.api.proto.BlockchainOuterClass.NativeSubscribeReplyItem
import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.SilentException import io.emeraldpay.dshackle.SilentException
import io.emeraldpay.dshackle.upstream.Multistream import io.emeraldpay.dshackle.upstream.Multistream
@@ -34,6 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import java.util.concurrent.atomic.AtomicLong
@Service @Service
open class NativeSubscribe( open class NativeSubscribe(
@@ -51,14 +53,26 @@ open class NativeSubscribe(
.flatMapMany { .flatMapMany {
it -> it ->
val subscriptionId = it.subscriptionId val subscriptionId = it.subscriptionId
Mono.just(it) val dataStream = Mono.just(it)
.flatMapMany { .flatMapMany {
start(it, subscriptionId) start(it, subscriptionId)
} }
.map(this@NativeSubscribe::convertToProto) .map(this@NativeSubscribe::convertToProto)
val lastMessageTime = AtomicLong(System.currentTimeMillis())
val heartbeatStream = Flux.interval(Defaults.nativeSubscribeHeartbeatInterval)
.filter { System.currentTimeMillis() - lastMessageTime.get() >= Defaults.nativeSubscribeHeartbeatInterval.toMillis() }
.map { createHeartbeat() }
Flux.merge(
dataStream.doOnNext { lastMessageTime.set(System.currentTimeMillis()) },
heartbeatStream,
)
.doOnCancel { .doOnCancel {
log.warn("Subscription $subscriptionId cancelled") log.warn("Subscription $subscriptionId cancelled")
}.onErrorMap { }
.onErrorMap {
convertToStatus(it, subscriptionId) convertToStatus(it, subscriptionId)
} }
} }
@@ -172,6 +186,12 @@ open class NativeSubscribe(
return msg.build() return msg.build()
} }
private fun createHeartbeat(): NativeSubscribeReplyItem {
return NativeSubscribeReplyItem.newBuilder()
.setHeartbeat(true)
.build()
}
data class ResponseHolder( data class ResponseHolder(
val response: Any, val response: Any,
val nonce: Long?, val nonce: Long?,