如何暂停一个事件流过一个可观察的事件?

时间:2016-05-31 23:47:40

标签: rx-java reactive-programming kotlin

我正在尝试创建一个可以暂停的Observable,使得项目停止被推动通过observable直到它被取消暂停。

此时,我希望它继续处理所有未处理的项目。我的数据源来自课外,所以我看起来像这样:

class Agent {
    val publisher = PublishSubject.create<Event>()
    val subscription = createSubscription()

    fun trackEvent(e: Event) {
        publisher.onNext(e)
    }

    fun pause() {
        // ???
    }

    fun resume() {
        // ???
    }

    private fun createSubscription(): Subscription {
        return publisher
                .map { stringify(it) }
                .buffer(10L, TimeUnit.SECONDS, 500) // capture 500 events or 10 seconds worth, whichever comes first.
                .map { /* create HttpPost request */ }
                .flatMap { /* send request to server */ }
                .subscribe { println("Received response: $it") }
    }
}

我的目标是pause函数会阻止事件进入服务器(但会保留它们直到最终resume)。在发生resume时,我们会发送事件。 (显然,如果我们在暂停状态下发生太多的事件,我们会为背压增加一些额外的帮助。

我尝试过各种缓冲和窗口操作以使其工作,但它实际上从未暂停 observable。相反,发生了两件事之一:

  1. 事件完全被删除(如果是取消订阅,过滤等)
  2. 事件流过,好像什么也没发生。
  3. 我能做些什么来支持这个用例吗?或者我是否应该在期望上述两种结果之一即将发生的情况下写这篇文章?

1 个答案:

答案 0 :(得分:1)

诀窍是使用另一个BehaviorSubject作为关闭事件进行额外的缓冲:

val publisher = PublishSubject.create<Event>()
fun trackEvent(e: Event) {
    publisher.onNext(e)
    isPaused.onNext(isPaused.value)
}

val isActive = BehaviorSubject.create(true)
fun pause() {
    isActive.onNext(false)
}
fun resume() {
    isActive.onNext(true)
}

private fun createSubscription(): Subscription {
    return publisher
            .buffer(10L, TimeUnit.SECONDS, 500) // -> Observable<List<Event>>
            .buffer({ isActive.filter { it } }) // -> Observable<List<List<Event>>>
            .flatMap { Observable.from(it) } // -> Observable<List<Event>>
            .map { /* create HttpPost request */ }
            .flatMap { /* send request to server */ }
            .subscribe { println("Received response: $it") }
}

第一次buffer调用会将传入的事件放入指定大小的存储桶中,或者经过一段时间后。第二个buffer将关闭由observable发出的事件的当前存储桶,指示Agent未暂停(isActive.filter { it })。 isActive会在每个事件上发出一个值,因为isActiveBehaviorSubject,它会向每个新订阅者发出最后一个值。这是在第一个buffer调用发出的每个存储桶上,它将立即继续或等待Agent恢复。