使用改造和 kotlin 通道实施长轮询
Implementing long polling with retrofit and kotlin channels
我正在尝试实现生命周期感知的长轮询(在 Activity/Fragment 中)。轮询将限定在每隔固定时间间隔向服务器发送 API 请求的片段。但是,我无法实现它。
这就是我想要的实现方式
- Have a hard timeout on client-side without considering any extra delay incurred in receiving the response.
- Wait for the response of previous API call before sending the next request. i.e., the request in polling queue should wait for response irrespective of its priority due to polling interval
考虑:
HARD_TIMEOUT = 10s
POLLING_INTERVAL = 2s
Request 1: Started at: 0sec Response delay:1.2sec Duration left: 0.8sec
Request 2: Started at: 2sec Response delay:0.4sec Duration left: 1.6sec
Request 3: Started at: 4sec Response delay:2.5sec Duration left: 0sec
Request 4: Started at: 6.5sec Response delay:0.5sec Duration left: 1.0sec
Request 5: Started at: 8sec Response delay:0.8sec Duration left: 1.2sec
对于这个用例,我想使用轮询而不是套接字。任何 Idea/solutions 将不胜感激。谢谢。
好的,想出了一个使用通道进行轮询的解决方案。这应该有助于搜索示例的人。
private val pollingChannel = Channel<Deferred<Result<OrderStatus>>>()
val POLLING_TIMEOUT_DURATION = 10000L
val POLLING_FREQUENCY = 2000L
A channel is required to hold your asynchronous request just in case more request comes in while your async task is being executed.
val pollingChannel = Channel<Deferred<Pair<Int,Int>>>()
QUEUE EXECUTOR: It will pick an async task and start executing them in FIFO order.
CoroutineScope(Dispatchers.IO).launch {
for (i in pollingChannel) {
val x = i.await()
println("${SimpleDateFormat("mm:ss.SSS").format(Calendar.getInstance().time)} Request ${x.first}: value ${x.second}")
}
}
POLLING FUNCTION: Adds your async task to the polling channel every fixed interval of time until timeout.
CoroutineScope(Dispatchers.IO).launch {
var reqIndex = 1
val timedOut = withTimeoutOrNull(POLLING_TIMEOUT_DURATION) {
while (receiverJob.isActive) {
pollingChannel.send(async {
getRandomNumber(reqIndex++)
})
delay(POLLING_FREQUENCY)
}
}
}
ASYNCHRONOUS OPERATION
为了避免回答冗长,我创建了一个随机延迟的函数,请替换为所需的 API 调用
private suspend fun getRandomNumber(index: Int): Pair<Int,Int> {
val randomDuration = (1..6L).random() * 500
delay(randomDuration)
return Pair(index,(0..100).random())
}
样本输出
我正在尝试实现生命周期感知的长轮询(在 Activity/Fragment 中)。轮询将限定在每隔固定时间间隔向服务器发送 API 请求的片段。但是,我无法实现它。
这就是我想要的实现方式
- Have a hard timeout on client-side without considering any extra delay incurred in receiving the response.
- Wait for the response of previous API call before sending the next request. i.e., the request in polling queue should wait for response irrespective of its priority due to polling interval
考虑:
HARD_TIMEOUT = 10s
POLLING_INTERVAL = 2s
Request 1: Started at: 0sec Response delay:1.2sec Duration left: 0.8sec
Request 2: Started at: 2sec Response delay:0.4sec Duration left: 1.6sec
Request 3: Started at: 4sec Response delay:2.5sec Duration left: 0sec
Request 4: Started at: 6.5sec Response delay:0.5sec Duration left: 1.0sec
Request 5: Started at: 8sec Response delay:0.8sec Duration left: 1.2sec
对于这个用例,我想使用轮询而不是套接字。任何 Idea/solutions 将不胜感激。谢谢。
好的,想出了一个使用通道进行轮询的解决方案。这应该有助于搜索示例的人。
private val pollingChannel = Channel<Deferred<Result<OrderStatus>>>()
val POLLING_TIMEOUT_DURATION = 10000L
val POLLING_FREQUENCY = 2000L
A channel is required to hold your asynchronous request just in case more request comes in while your async task is being executed.
val pollingChannel = Channel<Deferred<Pair<Int,Int>>>()
QUEUE EXECUTOR: It will pick an async task and start executing them in FIFO order.
CoroutineScope(Dispatchers.IO).launch {
for (i in pollingChannel) {
val x = i.await()
println("${SimpleDateFormat("mm:ss.SSS").format(Calendar.getInstance().time)} Request ${x.first}: value ${x.second}")
}
}
POLLING FUNCTION: Adds your async task to the polling channel every fixed interval of time until timeout.
CoroutineScope(Dispatchers.IO).launch {
var reqIndex = 1
val timedOut = withTimeoutOrNull(POLLING_TIMEOUT_DURATION) {
while (receiverJob.isActive) {
pollingChannel.send(async {
getRandomNumber(reqIndex++)
})
delay(POLLING_FREQUENCY)
}
}
}
ASYNCHRONOUS OPERATION
为了避免回答冗长,我创建了一个随机延迟的函数,请替换为所需的 API 调用
private suspend fun getRandomNumber(index: Int): Pair<Int,Int> {
val randomDuration = (1..6L).random() * 500
delay(randomDuration)
return Pair(index,(0..100).random())
}
样本输出