I got a simulator class that emit items, it can be controlled to start emitting by:
Simulator.emiting -> Observable, true -> started emitting, false, stopped emitting
The items are exposed: Simulator.items -> Observable
The items will be processed, processing happen much slower than emitting (processing potentially occurs on another thread)
I am trying to get an observable that signal when "emitting+processing" starts and ends, so:
from: start emitting , 1, 2, ,3, end emitting
to: start emitting and processing, 1------, 2-----, 3-----, end emitting and processing
how can I get the emitting+processing observable ? I tried using
simulator.items.map { process(it) }.takeUntil(simulator.emitting.filter { it == false }) but this will stop before processing finishes.
So it looks like this is a trivial problem, using zip operator
val stoppedEmitting = simulator.emitting.filter { it == false }
val emitted = simulator.items.takeUntil(stoppedEmitting )
val processed = emitted.map { item -> process(item) }
then "zip" op will wait until the last item get processed:
val processingFlow = emitted.zipWith(processed) { item, processedItem -> ... }
processing.subscribe { }
Related
I'm already querying some external resource with Flux.using(). Now I want to implement a kind of optimistic locking: read some state before query starts to execute and check if it was updated after query is finished. If so - throw some exception to break http request handling.
I've achieved this by using doOnComplete:
final AtomicReference<String> initialState = new AtomicReference<>();
return Flux.just("some", "constant", "data")
.doOnComplete(() -> initialState.set(getState()))
.concatWith(Flux.using(...)) //actual data query
.doOnComplete(() -> {if (!initialState.get().equals(getState())) throw new RuntimeException();})
.concatWithValues("another", "constant", "data")
My questions:
Is it correct? Is it guaranteed that 1st doOnComplete lambda would be finished before Flux.using() and is it guaranteed that 2nd doOnComplete lambda would be executed strictly after?
Does more elegant solution exists?
The first doOnComplete would be executed after Flux.just("some", "constant", "data") emits all elements and the second one after emitted Publisher defined in concatWith completes successfully. This is working because both publishers have a finite number of elements.
With the proposed approach, however the pre-/postconditions from a particular operation are handled outside of the operations at a higher level. In other words, the condition check belonging to the operation is leaking to the flux definition.
Suggestion, pushing the condition check down to the operation:
var otherElements = Flux.using( // actual data query
() -> "other",
x -> {
var initialState = getState();
return Flux.just(x).doOnComplete(() ->
{ if (!initialState.equals(getState())) throw new IllegalStateException(); }
);
},
x -> { }
);
Flux.just("some", "constant", "data")
.concatWith(otherElements)
.concatWith(Mono.just("another")) // "constant", "data" ...
I have an Observable<Bool> that emits true when an operation begins and false when it ends. I'd like to show a message while the operation is in progress, but only if it takes longer than two seconds to begin. Is there a way I can create an observable that I can bind my message to? Any help much appreciated!
If you switchMap (a flatMap where when a second item is emitted from the source the subscription to the original observable is unsubscribed and the subscription moves to the next) you could do something like this:
booleanObservable
.switchMap ( map true to an observable timer of 2 seconds, map false to an empty observable)
.onNext show your message (next won't fire for the empty and a
quick response would have cut off the 2 second timer).
Note switchMap is 'switchLatest' in RxSwift.
Could become something like this:
booleanObservable
.map { inProgress -> Observable<Bool> in
if inProgress {
return Observable.just(true).delay(time: 2)
} else {
return Observable.just(false)
}
}
.switchLatest()
The question is about RxJava2.
Noticed that zipping Throwable that comes from retryWhen with range emits all items from Observable.range before zipper function has been applied. Also, range emits sequence even if zipWith wasn't called. For example this source code
Observable.create<String> {
println("subscribing")
it.onError(RuntimeException("always fails"))
}
.retryWhen {
it.zipWith(Observable.range(1, 3).doOnNext { println("range $it") },
BiFunction { t: Throwable, i: Int -> i })
.flatMap {
System.out.println("delay retry by $it + second(s)")
Observable.timer(it.toLong(), TimeUnit.SECONDS)
}
}./*subscribe*/
gives the following result
range 1
range 2
range 3
subscribing
delay retry by 1 + second(s)
subscribing
delay retry by 2 + second(s)
subscribing
delay retry by 3 + second(s)
subscribing
onComplete
Replacing onError in observable creation also don't eliminate emitting range items. So the question is why it's happening as Range is cold.
Observables in 2.x don't have backpressure thus a range operator will emit all its items as soon as it can. Your case, however, can use a normal counter incremented along the error notification of the retry handler:
source.retryWhen(e -> {
int[] counter = { 0 };
return e.takeWhile(v -> ++counter[0] < 4)
.flatMap(v -> Observable.timer(counter[0], TimeUnit.SECONDS));
})
I'm trying to figure out how to use Observable.groupBy to limit the number of elements pushed by key over a time frame. I end up with the following construct:
create(emitter -> {
while (true) {
publishedMeter.mark();
emitter.onNext(new Object());
}
})
.window(1000L, TimeUnit.MILLISECONDS)
.flatMap(window -> window.groupBy(o -> o.hashCode() % 10_000).flatMapMaybe(Observable::lastElement))
.subscribe(e -> receivedMeter.mark());
While subscribe's onNext callback is called a few thousand times, which I think should mean that flatMapMaybe does properly subscribe to all GroupedObservableSource. After a short while one of the thread inside RxComputationThreadPool but I don't understand what I'm missing
Let's say you have the following Observable in rxjava-scala-0.18.4
#volatile var dorun = true
var subscriber: Subscriber[String] = null
val myObs = Observable { obs: Subscriber[String] =>
subscriber = obs
Subscription { println("unsubscribed"); dorun = false }
}
val sub = myObs.head.subscribe(println(_))
assertTrue(dorun)
subscriber.onNext("hello")
Thread.sleep(500)
assertFalse(dorun)
subscriber.onNext("world")
Thread.sleep(500)
assertFalse(dorun)
The second assertion fails, which means that head does not unsubscriby. Is my understanding of Observables wrong or should head unsubscribe after the first element got emitted?
Take a look at your subscribe() method: you loop until run is set to false, but the only way for that to happen would be to close the subscription. The problem is that nobody has the subscription yet: the loop keeps you from returning. The head operator can't terminate the underlying subscription after the first item is delivered because it hasn't finished subscribing yet. Thus, you just keep looping forever.
One solution would be to move your loop into an action scheduled on Schedulers.trampoline(). Then the events would be delivered some time after returning from subscribe().
Additionally, in your subscribe() method, it seems you need to add the new subscription object to the Subscriber that gets passed in, like so:
val myObs = Observable {
obs: rx.lang.scala.Subscriber[String] =>
...
obs.add(
Subscription {
dorun = false
println("unsubscribed")
}
)
}