using transformToUni - vert.x

being relatively new to mutiny I am having a little difucauly wrapping my head around the following:
given the following working code:
public Uni<Long> getCounterValue() {
return this.vertx.sharedData().getCounter(COUNTER_NAME).onItem().transformToUni(counter->counter.get());
}
I simply want to return a Uni where the Long is a current state of a vert.x shared counter.
what is hard for me is that counter.get() actually already returns a Uni so I feel like I am doing a transformToUni on something that already has the return time I need.
I hope I explained myself. like I said, the code works but its hard for me to get the why... maybe there's also another way, more self explanatory, to achieve this?
(BTW, I looked at the guides but still I am confused)
your comments are appreciated.
thanks

I think the explanation is that you need a new Uni that's aware of the event emitted by getCounter and that will call counter.get(). Or, in general, a new Uni that knows what to do with the result of the previous one and makes sure that everything happens in the right order at subscription.
Let's take a simpler example, we have three Uni:
Uni<?> first = Uni.createFrom,().item(1).invoke(System.out::print);
Uni<?> second = Uni.createFrom().item(2).invoke(System.out::print);
Uni<?> third = first.chain(() -> second);
If you subscribe first, it will print 1.
If you subscribe second, it will print 2.
If you subscribe third, it will print 12.
These are three different Uni, emitting different events at different times.
What you are suggesting is to return second when transformToUni (or chain) is called to create third. But, in that case, the result would be different from what we want.

Related

ReactiveX Retry with Multiple Consumers

Quick question, because I feel like I must be missing something.
I'm using rxjs here because it's what I've got in-front of me, this is a general reactiveX question, I believe.
Let's say I have a set of Observables like so:
network_request = some_thing // An observable that produces the result of a network call
event_stream = network_request.flatMapLatest(function(v) {
return connectToThing(v) // This is another observable that needs v
}) // This uses the result of the network call to form a long-term event-based connection
So, this works ok.
Problem, though.
Sometimes the connection thing fails.
So, if I do event_stream.retry() it works great. When it fails, it redoes the network call and gets a new v to use to make a new connection.
Problem
What happens if I want two things chained off of my network_request?
Maybe I want the UI to do something every time the network call completes, like show something about v in the UI?
I can do:
shared = network_request.share() // Other implementations call this refCount
event_stream = shared.flatMapLatest(...) // same as above
ui_stream = shared.flatMapLatest(...) // Other transformation on network response
If I didn't do share then it would have made two requests, which isn't what I want, but with share, when event_stream later has an error, it doesn't retry the network request because the refcount is still at 1 (due to ui_stream), so it immediately returns completed.
What I want
This is obviously a small example I've made up to explain my confusion.
What I want is that every time the result of event_stream (that long term connection) has an error all of the following happens:
the network request is made again
the new response of that request is used to build a new connection and event_stream goes on with new events like nothing happened
that same response is also emitted in ui_stream to lead to further processing
This doesn't feel like a complicated thing, so I must just be misunderstanding something fundamental when it comes to splitting / fanning out RX things.
Workarounds I think I could do but would like to avoid
I'm looking to export these observables, so I can't just build them again and then say "Hey, here's the new thing". I want event_stream and all the downstream processing to not know there's been a disconnection.
Same for ui_stream. It just got a new value.
I could probably work something out using a Subject as a generation counter that I ping every time I want everything to restart, and put the network_request into a flatMap based on that, so that I can break the share...
But that feels like a really hacky solution, so I feel there has to be a better way than that.
What have I fundamentally misunderstood?
As I've been thinking about this more I've come to the same realization as ionoy, which is that retry just disconnects and reconnects, and upstream doesn't know it was due to an error.
When I thought about what I wanted, I realized I really wanted something like a chain, and also a spectator, so I've got this for now:
network_request = some_thing
network_shadow = new Rx.Subject()
event_stream = network_request.do(network_shadow).flatMapLatest(...)
ui_stream = network_shadow.whatever
This has the property where an retry in event_stream or downstream will cause the whole thing to restart, whereas ui_stream is its own thing.
Any errors over there don't do anything, since network_shadow isn't actually a subscriber to event_stream, but it does peel the values off so long as the main event chain is running.
I feel like this isn't ideal, but it is better than what I was concerned I would have to do, which is have a restartEverything.onNext() in an doOnError, which would have been gross.
I'm going to work with this for now, and we'll see where it bites me...
You need to make your cold observable hot by using Publish. Read http://www.introtorx.com/Content/v1.0.10621.0/14_HotAndColdObservables.html#HotAndCold for a great explanation.

An alternative to "while" for making repeated requests to a server

I have a function which should return a result either from the db or a server. But the server might fail and return nothing and in that case I need to repeat the server request until it returns the result:
def getToken() =
getTokenFromDb orElse getTokenFromServer() map { t =>
saveTokenToDb(t)
t
}
What is a sensible solution for repetitive requests to getTokenFromServer() until I get a good response from it except using while loop? Of maybe using while is a good solution?
This may sound insane, but you could create a stream of infinite server-requests, and then use "takeWhile + isDefined" :) I think that may actually be quite easy to implement. If I get to my code-machine, I'll whip something up :)
Well, as far as you have no specific requirements on how many attempts you want it to try the server, just use recursion. This is in fact almost the same as while loop :) but in more functional style.
So make the getTokenFromServer() recursive.
But do not forget about the tail-recursion, i.e. the recursive call to the getTokenFromServer() from within itself must be a last code statement in it's code. That way you will not get any troubles with stack overflowing.

Passing Args Down Catalyst Chain w/$c->visit

In one of my Catalyst actions, I'm trying to go off and get the body response (HTML) of another action in a different controller. (For the purpose of sort of "embedding" one page in another)
I figured the way to do this was a $c->visit. (If I misunderstood $c->visit, then the rest of my question need not be answered.)
The action in question takes an arg, but not until further down the chain, which looks like this:
/equipment/*/assets/widget
/assets/captureID (1)
-> /assets/base (0)
-> /assets/pageData (0)
=> /assets/widget
As you can see, only the last action in the chain is looking for an arg.
If I try:
$c->visit('/assets/widget',[$arg]);
I would expect it to travel down the chain and give /assets/captureID my $arg. But in fact, it doesn't seem to get passed down the chain at all.
Where have I gone astray?
As you've discovered, the body doesn't exist at that point. You'd have to have made a call to render your view, or make an arrangement for /assets/widget to set $c->res->body($foo) directly. I find the idea of capturing the body of a sub-request unconventional, to put it mildly. I can't imagine what you are going to do with it that isn't going to go against the principles of good MVC design.
It sounds to me like the logic that is in /assets/widget needs to be located in the Model rather than the Controller, so that it can be used by whatever function requires it.
And/or you need to break your templates down into (reusable) components, so that whatever content you planned to embed could be done as part of a single rendering process.
[%- IF foo;
PROCESS widget.tt;
END; -%]
Turns out only the captures, not the args get passed down the chain.
According to the doc:
$c->visit( $action [, \#captures, \#arguments ] )
So I was able to have success by doing the following:
$c->visit('/assets/widget',[$arg],[$arg])
The first array of args hits the first action and stops, but the second array travels all the way down the chain like I wanted.
I expected $c->visit('/assets/widget',[],[$arg]) to work, but it does not.
However, after all that I realized I can't just grab the body response that way, which was the ultimate goal. Either way, hopefully my goose chase was helpful to someone.

What do the various ISubject implementations do and when would they be used?

I have a fairly good idea of what the Subject class does and when to use it, but I've just been looking through the language reference on msdn and see there are various other ISubject implementations such as:
AsyncSubject
BehaviorSubject
ReplaySubject
As the documentation is pretty thin on the ground, whats the point of each of these types and under what situations would you use them?
These subjects all share a common property - they take some (or all) of what gets posted to them via OnNext and record it and play it back to you - i.e. they take a Hot Observable and make it Cold. This means, that if you Subscribe to any of these more than once (i.e. Subscribe => Unsubscribe => Subscribe again), you'll see at least one of the same value again.
ReplaySubject: Every time you subscribe to the Subject, you get the entire history of what has been posted replayed back to you, as fast as possible (or a subset, like the last n items)
AsyncSubject: Always plays back the last item posted and completes, but only after the source has completed. This Subject is awesome for async functions, since you can write them without worrying about race conditions: even if someone Subscribes after the async method completes, they get the result.
BehaviorSubject: Kind of like ReplaySubject but with a buffer of one, so you always get the last thing that was posted. You also can provide an initial value. Always provides one item instantly on Subscribe.
In light of the latest version (v1.0.2856.0) and to keep this question up to date, there has been a new set of subject classes:
FastSubject, FastBehaviorSubject, FastAsyncSubject and FastReplaySubject
As per the release notes they
are much faster than regular subjects
but:
don’t decouple producer and consumer by an IScheduler
(effectively limiting them to
ImmediateScheduler);
don’t protect against stack overflow;
don’t synchronize input messages.
Fast subjects are used by Publish and
Prune operators if no scheduler is
specified.
In regards to AsyncSubject
This code:
var s = new AsyncSubject<int>();
s.OnNext(1);
s.Subscribe(Console.WriteLine);
s.OnNext(2);
s.OnNext(3);
s.OnCompleted();
prints a single value 3. And it prints same if subscription is moved to after completion. So it plays back not the first, but the last item, plays it after completion (until complete, it does not produce values), and it does not work like Subject before completion.
See this Prune discussion for more info (AsyncSubject is basically the same as Prune)
Paul's answer pretty much nails it. There's a few things worth adding, though:
AsyncSubject works as Paul says, but only after the source completes. Before that, it works like Subject (where "live" values are received by subscribers)
AsyncSubject has changed since I last ran tests against it. It no longer acts as a live subject before completion, but waits for completion before it emits a value. And, as Sergey mentions, it returns the last value, not the first (though I should have caught that as that's always been the case)
AsyncSubject is used by Prune, FromAsyncPattern, ToAsync and probably a few others
BehaviorSubject is used by overloads of Publish that accept an initial value
ReplaySubject is used by Replay
NOTE: All operator references above refer to the publishing set of operators as they were before they were replaced with generalised publish operators in rev 2838 (Christmas '10) as it has been mentioned that the original operators will be re-added

What's a good maintainable way to name methods that are intended to be called by IBActions?

I am creating function (for example) to validate content, then if it is valid, close the view, if it is not, present further instructions to the user. (Or other such actions.) When I go to name it, I find myself wondering, should I call it -doneButtonPressed or -validateViewRepairAndClose? Would it be better to name the method after what UI action calls it, or name it after what it does? Sometimes it seems simple, things like -save are pretty clear cut, other times, and I can't thing of a specific example right off, but I know some have seemed like naming them after what they do is just so long and confusing it seems better to just call them xButtonPressed where x is the word on the button.
It's a huge problem!!! I have lost sleep over this.
Purely FWIW ... my vote is for "theSaveButton" "theButtonAtTheTopRight" "userClickedTheLaunchButton" "doubleClickedOnTheRedBox" and so on.
Generally we name all those routines that way. However .. often I just have them go straight to another routine "launchTheRocket" "saveAFile" and so on.
Has this proved useful? It has because often you want to launch the rocket yourself ... in that case call the launchTheRocket routine, versus the user pressing the button that then launches the rocket. If you want to launch the rocket yourself, and you call userClickedTheLaunchButton, it does not feel right and looks more confusing in the code. (Are you trying to specifically simulate a press on the screen, or?) Debugging and so on is much easier when they are separate, so you know who called what.
It has proved slightly useful for example in gathering statistics. The user has requested a rocket launch 198 times, and overall we've launched the rocket 273 times.
Furthermore -- this may be the clincher -- say from another part of your code you are launching the rocket, using the launch-the-rocket message. It makes it much clearer that you are actually doing that rather than something to do with the button. Conversely the userClickedTheLaunchButton concept could change over time, it might normally launch the rocket but sometimes it might just bring up a message, or who knows what.
Indeed, clicking the button may also trigger ancillary stuff (perhaps an animation or the like) and that's the perfect place to do that, inside 'clickedTheButton', as well as then calling the gutsy function 'launchTheRocket'.
So I actually advocate the third even more ridiculously complicated solution of having separate "userDidThis" functions, and then having separate "startANewGame" functions. Even if that means normally the former does almost nothing, just calling the latter!
BTW another naming option would be combining the two... "topButtonLaunchesRockets" "glowingCubeConnectsSocialWeb" etc.
Finally! Don't forget you might typically set them up as an action, which changes everything stylistically.
[theYellowButton addTarget:.. action:#selector(launchRockets) ..];
[theGreenButton addTarget:.. action:#selector(cleanUpSequence) ..];
[thatAnimatingButtonSallyBuiltForUs addTarget:.. action:#selector(resetAll) ..];
[redGlowingArea addTarget:.. action:#selector(tryGetRatingOnAppStore) ..];
perhaps that's the best way, documentarily wise! This is one of the best questions ever asked on SO, thanks!
I would also go with something along the lines of xButtonPressed: or handleXTap: and then call another method from within the handler.
- (IBAction)handleDoneTap:(id)sender {
[self closeView];
}
- (void)closeView {
if ([self validate]) {
// save and close
}
else {
// display error information
}
}