Morning
Aye up! Mornin'
๐
Good Morning!
o/
ยกmรฅnmรฅn!
morn
Mogge
anyone had any experiences (good or bad), with java reactive streams libs from clojure (i.e. not core.async or manifold, but rxjava or reactor) ?
Morn'
Malcolm has used these extensively.
i need to decide which way to go to replace manifold streams on the jvm @malcolmsparks - RxJava seems like the easy choice, but any more nuanced opinions will be gratefully received ๐
There's something being integrated into the jvm I recall. And there's a 2 of something. But that's all I know.
yeah, there's java 9 j.u.c.Flow
but i don't know how that intersects with RxJava and reactor
That Flow is mainly a bunch of the interfaces for the reactive streams spec IIRC, it is intended as a sort of lingua franca type thing
In my (limited) experience Reactor tends to get used more than RxJava, which might just be because it's the Spring WebFlux default
Hi @mccraigmccraig - I've been playing with RxJava2 over the Summer. I can't say anything about Reactor, only that I think it's quite similar, and as @conor.p.farrell says they're both implementations of http://reactive-streams.org, which is a set of Java interfaces that have found their way into the JVM (Java 9), but not in much use in that form yet.
My reaction to RxJava2 is very positive (excuse the pun), Flowable has a huge amount of useful stuff in it, similar to manifold streams. The 'pull' model of back-pressure makes sense to me, whereby each 'subscriber' requests a number of items to be delivered.
I like the reactive-streams interfaces - for me, they are an ideal solution to the non-blocking back-pressured IO that we'd like for Ring 2.1
They solve the problem of how to interoperate between different implementations on the JVM (e.g. RxJava, Reactor, Akka).
The reason I'm looking at this stuff is to research an alternative to aleph/manifold - the past 5 years or so has seen quite a lot of progress/consolidation in async on the JVM. The fact is that there are a lot more people able to contribute and maintain this JVM-wide stack, especially if you include the community around Vert.x.
The integration between Vert.x and RxJava is particularly nice. Many Vert.x concepts, such as AsyncFile, play nicely as both a publisher and subscriber (read and write).
I've been in two minds whether to retreat into the land of blocking streams or double down on async. I've chosen to keep going down the async rabbit hole for now, but feel that if you're going to do that, you've just got to handle back-pressure otherwise it's pointless.
A nice surprise was how well Vert.x does async back-pressured multipart/form-data, which as you know was a significant effort to implement in Clojure in yada, and never felt right at the 'yada' level of abstraction.
Hope this helps - it would be nice to discuss somewhere that retains history ๐
My various code snippets can be found here: https://github.com/juxt/vext
All quite speculative at this point
I'm looking for the the same reasons
i think i must be misunderstanding something about the various backpressure strategies in rxjava though - none of them look like actual backpressure, i.e. slowing or stopping the producer when the consumer can't keep up
ah, ok, i think i get it Subscriber.request
- yes, i agree, handling backpressure is a necessity
I'm quite content using Java interop with RxJava - mostly the 'fluent' API makes this really nice with Clojure - no need to dig out doto
and friends.
Yes, you're right. The request part of the Subscription is key. It says "I can take another 5", and then that will ripple down the publisher chain until it gets to the original publisher, which then calls 'onNext' 5 times.
(where 5 is any number)
Say you have a cond
with N conditions, and for each of those conditions you want to eval some code and return a map
it feels a bit unweldy
can it be done better...
(cond
:foo (do (something blah) {:foo "a message"})
:wibble (do (another wibble) {:amazing true})
:else nil)
both something
and another
are interop stuff that do not return maps
Seems reasonable to me.
I guess you could wrap them up as private functions if you wanted...?
kk ๐
sounds reasonable too ๐
(defn- something [x]
(do-the-interop x)
{:foo "a message"})
...
(cond :foo (something blah) ...)
yeah, perhaps a tad cleaner ๐
I guess it depends whether the map is always associated with that interop code?
yes
much nicer as little functions
ta sean!