I'm trying to repeat a subscribtion on a Flux like this:
DirectProcessor<String> stringDirectProcessor = DirectProcessor.create();
stringDirectProcessor
.repeat(3)
.subscribe(item -> System.out.println(item));
stringDirectProcessor.onNext("one");
stringDirectProcessor.onNext("two");
stringDirectProcessor.onNext("three");
stringDirectProcessor.onComplete();
My expectation would be to see this output:
one
two
three
one
two
three
one
two
three
one
two
three
But I only get
one
two
three
However if I use Flux.just() instead of DirectProcessor I do get the expected output.
What's wrong?
This is the expected behavior of the DirectProcessor. I just read through the documentation and found the following regarding the DirectProcessor:
Once the Processor has terminated (usually through its sink’s error(Throwable) or complete() methods being called), it lets more subscribers subscribe but replays the termination signal to them immediately.
So, since, repeat simply resubscribes, the onComplete handler will be called on them immediately. Are you sure you need the DirectProcessor?
EDIT: This behavior is also documented here
Note: If there are no Subscribers, upstream items are dropped and only the terminal events are retained. A terminated DirectProcessor will emit the terminal signal to late subscribers.
Related
I have a scenario where two functionalities run parallel.
Below is sample pseudo code.
MainActor{
// retrive company ids
//for each company id i need to run another two different actions simultaniously
tell(A_Actor)
tell(B_Actor)
//if I call above they are calling sequentially i.e. first it runs tell(A_Actor)
//then comes to tell(B_Actor).
//If tell(A_Actor) fails it wont run tell(B_Actor).
}
A_Actor{
// do ingest into a file.
}
B_Actor{
// do ingest into a DB.
}
Question :
How to run two functionalities i.e. tell(A_Actor) & tell(B_Actor) run parallel?
The tell method is asynchronous. When you fire a tellto actorA, it doesn't wait until actorA finishes or crashes to execute the next action, which here is to tell actorB
If you need to paralelize the two tell methods, then you can do the following :
val tellActions = Vector(() => actorA.tell(messageA, senderActor), () => actorB.tell(messageB, senderActor))
tellActions.par.foreach(_.apply())
Note that this is Scala code
This has been pointed out in several comments (including mine), but I felt it deserved an answer.
In short, you need to distinguish between calling the tell method in parallel with the functionality that the actors execute within their receive methods being executed in parallel. The functionality will be executed in parallel automatically, and calling the tell method in parallel doesn't make any sense.
The code you show will execute the ingest in a file and ingest into the DB in parallel. This is automatic and requires no action on your part; this is how actors and tell works. And, despite what you say, if something goes wrong with the file ingestion it will not affect the ingestion into the DB. (Assuming you built the actors and messages correctly, since you don't list their implementation.)
The tell method is asynchronous: it returns nearly immediately and doesn't do the actual logic (ingestion in this case): the only thing it does is place the message in the recipient's mailbox. Ismail's answer, in theory, shows you how you could "invoke tell" in parallel, but in that example you "sequentially" are creating the array that is used for parallel tells and the whole process will be very inefficient.) His code, while technically doing what you ask, is nonsensical in practice: it accomplishes nothing except slowing the code down significantly.
In short, I think you either:
Have something fundamentally wrong with your actors and how you are calling them.
You are actually are executing the functionality in parallel and you just aren't realizing it because you are measuring/observing something incorrectly.
Given two Maybe values, how can I combine them into a single Maybe that will either:
call onSuccess() whenever either of the source Maybes calls onSuccess
call onComplete() whenever both of the source Maybes call onComplete()?
(Cf. Option.orElse() in Scala or Vavr.)
E.g., assuming the existence of a combine() method that does what I want:
combine(Maybe.just(a), Maybe.empty()) ≍ Maybe.just(a)
combine(Maybe.empty(), Maybe.just(b)) ≍ Maybe.just(b)
combine(Maybe.empty(), Maybe.empty()) ≍ Maybe.empty()
combine(Maybe.never(), /*anything*/ ) ≍ /*the thing*/
combine(/*anything*/, Maybe.never()) ≍ /*the thing*/
At first I thought amb() & family were what I was looking for, but that completes as soon as either source Maybe completes, meaning if the first Maybe completes without a value, you never get the value from the second Maybe.
Right now I'm using
Maybe.mergeArray(m1, m2).firstElement()
which seems to do what I want, but I’m not certain it’s correct and I’m not certain it’s the cleanest way to do it. (For instance, if there’s some delay, will it call onSuccess() immediately when one or the other source does, or will it wait for both onComplete()s?)
Is this correct? Is there a more idiomatic approach?
ETA: I'm happy taking the first value; I don't need to wait for both to complete:
combine(Maybe.just(a), Maybe.just(b)) ≍ Maybe.just(/* a or b, don't care */)
(I can imagine situations in which I might prefer one or the other and want to indicate that by order of the arguments, but in that situation I suspect sequential would be better than parallel.)
There's a slightly different approach which might be a little nearer to your definition. This would be using Observable.switchMapMaybe():
Maps the upstream items into MaybeSources and switches (subscribes) to the newer ones while disposing the older ones (and ignoring their signals) and emits the latest success value of the current one if available while failing immediately if this Observable or any of the active inner MaybeSources fail.
Observable.just(m1, m2).switchMapMaybe(m -> m).firstElement()
But the approach using Maybe.mergeArray(m1, m2).firstElement() should be sufficient as well. The firstElement() operator emits the first element emitted by the mergeArray() flowable. This one is unordered and thus there's no information about the completion of any of the maybes.
Goal
I'm trying to create a dependency relationship between handlers that's somewhat circular, and I can't quite figure out how to get it right. What I want to achieve is a variation of producer -> [handlers 1-3] -> handler 4.
So, disruptor.handleEventsWith(h1, h2, h3).then(h4);. But I have the additional requirements that
While handlers 1-3 do process messages in parallel, none of them begins to process the next message until they have all finished the previous message.
After the first message, handlers 1-3 wait for handler 4 to have finished the most recent message before processing the next message.
The equivalent execution logic using a single event handler could be:
disruptor.handleEventsWith((event, sequence, endOfBatch) -> {
Arrays.asList(h1, h2, h3).parallelStream()
.forEach(h -> h.onEvent(event, sequence, endOfBatch));
h4.onEvent(event, sequence, endOfBatch);
});
Context
The design context is that handlers 1-3 each update their own state according to the message and that after a message is processed by each of the three they are in a consistent state. Handler 4 then runs some logic based on the state updated by handlers 1-3. So handler 4 should only see consistent states for the data structures maintained by 1-3, which means that handlers 1-3 should not process the next message until handler 4 has finished.
(Though the goal is definitely to use the Disruptor to manage the concurrency, rather than java.util.Stream.)
Not sure if it matters, but it's also the case that handler 4's logic can be broken into two parts, one requiring that none of handlers 1-3 are being updated and the next requiring only that the first part of handler 4 has finished. So handlers 1-3 can be processing a message while the second part of handler 4 is still executing.
Is there a way to accomplish this? Or maybe my design is flawed? I feel like there should be a way to do this via SequenceBarrier but I don't quite understand how to implement this custom barrier. For handlers 1-3, I think I'd like to make a barrier with the logic handlers[1:3].lastProcessedSequence() == handlers[4].lastProcessedSequence(), but I'm not sure where to put that logic.
Thanks!
I would consider having the handlers be stateless, and using the messages processed by them to contain the state of your system. That way you won't need to synchronize your handlers at all.
Here is the problem,
I have a network request which downloads some information. However, it is essential that this request is called only once during some period of time ( you will get the idea later on ) and all subscribers get the same result. My first thought was to use the share() operator, so it would multicast the result while keeping a single request source. But I am not sure what is going to happen if I try to subscribe to it again after the share operator already disposed the resources due to refCount dropping to 0.
The thing I am trying to accomplish here is that every request that I make, is dependent on the current state of information stored and those requests update this information. Once I make the first request, I need to keep a reference to it and inform every subscriber that subscribes until the time of request completion. After the request is finished, all subscribers gets their notification and unsubscribes... However, if there is a new subscription after the disposal I need it to repeat the request, thus resubscribing to the original source observable that was modified using share
Is something like this possible with simple share operator, or do I need to create a subject and control the emissions manually ?
There is a nice library RxReplayingShare, which I think makes exactly, what you are trying to achieve.
It passes the same result to all Subscriber's, when at least one is subscribed. When there are no subscribers anymore, the Observable completes. When subscribing again, the original Observable is called.
The RxMarble shows it better than the description.
Wanted behavior:
subject = BehaviorSubject.create(1);
subject.subscribe(number -> print(number), error -> print(error));
subject.onNext(2);
subject.onNext(3);
subject.onError(new RuntimeException("I'm an error"));
subject.onNext(4);
subject.onNext(5);
With this output:
1
2
3
I'm an error
4
5
My problem is that onNext after onError isn't working (and this is intended, following RxJava rules), but I'll need subject to be resilient to errors, while also passing them down the stream (to show the user some feedback).
Is there a way to do this?
If you want onError and onComplete to be disregarded there is the RxRelay library.
Description:
Subjects are useful to bridge the gap between non-Rx APIs. However, they are stateful in a damaging way: when they receive an onComplete or onError they no longer become usable for moving data. This is the observable contract and sometimes it is the desired behavior. Most times it is not.
Relays are simply Subjects without the aforementioned property. They allow you to bridge non-Rx APIs into Rx easily, and without the worry of accidentally triggering a terminal state.
Try to use .onErrorReturn() just before subscription