clojure-uk

A place for people in the UK, near the UK, visiting the UK, planning to visit the UK or just vaguely interested to randomly chat about things (often vi and emacs, occasionally clojure). More general the #ldnclj
alexlynham 2021-03-31T06:51:11.082900Z

morning

dharrigan 2021-03-31T07:04:36.083100Z

Good Morning!

jasonbell 2021-03-31T07:16:43.083300Z

Morning

mccraigmccraig 2021-03-31T07:45:42.083400Z

mawning

danm 2021-03-31T08:18:13.083600Z

Moin moin

danm 2021-03-31T08:56:06.085200Z

Do any folks here have much experience with core.async? I've dropped a query into #core-async about something that sounds sensible to me, but might just be utterly insane because I've not used it much before and haven't properly grokked something. Could do with eyes on, and I suspect most of the rest of the channel is currently in a timezone where they're asleep 😉

mccraigmccraig 2021-03-31T09:35:36.088300Z

had a quick look from a general async perspective @carr0t (i don't use core.async so much, but use manifold-streams lots in similar ways) and it looks generally sane. the only thing i would observe is that you probably want an agent rather than an atom of channel registrations - since atoms will retry swap! actions under load

Atomically swaps the value of atom to be:
(apply f current-value-of-atom args). Note that f may be called
multiple times, and thus should be free of side effects.  Returns
the value that was swapped in.

mccraigmccraig 2021-03-31T09:43:18.092700Z

for similar cases we use a slightly different architecture - api handler async sends an event onto a kafka topic and async subscribes to a gnatsd topic for response, separate kafka-streams app consumes event in kafka's synchronous way, when finished puts message on a gnatsd topic, which wakes the api handler to continue - but it adds another architectural component, which is probably worth avoiding if you don't have a need for it (we did have a need - we drive websockets for large numbers of users, and kafka doesn't play with large numbers of topics)

danm 2021-03-31T09:43:49.093500Z

Does that not run the risk of 2 assoc calls (for different keys) running in parallel against the agent and one of them getting lost in the final version? I mean, if we fail to assoc because state has changed or similar we have to retry before we can continue anyway

mccraigmccraig 2021-03-31T09:44:05.094100Z

but, as long as your atom is just a registration of channels with no side effect it's fine

danm 2021-03-31T09:44:07.094200Z

I've not used agents before, so I'm wary of using them 'wrong' 😉

danm 2021-03-31T09:44:51.095Z

I guess the validator could check that the key exists?

mccraigmccraig 2021-03-31T09:45:18.095500Z

agent serializes the actions

mccraigmccraig 2021-03-31T09:46:43.097200Z

so there will never be two calls running in parallel - they will always run one after the other... but i'm overthinking it - if all your swap! is doing is assoc or dissoc of a chan with no side-effects then it's fine

mccraigmccraig 2021-03-31T09:49:17.098600Z

i'm just a bit scarred by a very non-obvious bug i had which turned out to be because a side-effecting swap! fn was getting repeatedly executed 😬 - but the issue was the side-effect, not the atom

danm 2021-03-31T10:11:28.099500Z

Yeah, I guess there's not much difference between repeated swap! assoc calls until it works, and send assoc followed by await.

mccraigmccraig 2021-03-31T10:21:16.101700Z

yeah, the differences only become apparent when there's a side effect. if you are already async, you don't need to await a send though - you put your continuation action (resolve a promise, send to a chan etc) at the end of your send action, so you get guaranteed serialization of the state change without any blocking

mccraigmccraig 2021-03-31T10:21:34.101900Z

having never really used the STM stuff, serializing side-effecting state updates has been the only time i've ever used an agent in anger

danm 2021-03-31T12:08:31.104100Z

Potentially I don't even need core.async, as @cursork has pointed out. The respond-fn when using ring-jetty-adapter with :async? true already has the context to correctly match up the request. So I could just put the respond-fn for a given request directly into the atom, and have them all executed by the consumer thread. I don't know how much they'd block on sending the response to a servlet over a buffer mind you, but it should be minimal

danm 2021-03-31T12:08:40.104400Z

And probably basically the same as the channel

mccraigmccraig 2021-03-31T12:15:23.105700Z

oh, cool - that's better than introducing a channel

danm 2021-03-31T12:41:11.108300Z

We've ended up going back on that after some more talking it through 😉 The channel gives us a nice mechanism for sending a 504 response to the client and cleaning up expired requests from the atom when a timeout is hit, which putting the entire respond-fn into the atom and responding via the consumer thread doesn't. We could still clean up when we eventually got the message response (assuming a major error downstream didn't mean we never got one), but we wouldn't be able to nicely send the client a 504 if that was a long time after the HTTP timeout

mccraigmccraig 2021-03-31T14:01:04.108600Z

how are you doing your async @carr0t?

danm 2021-03-31T14:01:23.108800Z

What do you mean?

mccraigmccraig 2021-03-31T14:02:37.109200Z

as in are you using raw callbacks, manifold, core.async etc

danm 2021-03-31T14:09:14.109700Z

Current plan is core.async

mccraigmccraig 2021-03-31T15:11:08.112500Z

if you are still at the planning stage (and implementing on the JVM) then for promise-like interactions (i.e. things expected to return single values, rather than streams of values), mpenet/auspex and funcool/promesa are both also worth a look (i'm using ztellman/manifold heavily, but i hesitate to recommend that anymore because it's abandonware)

dharrigan 2021-03-31T15:33:03.112700Z

I hpoe manifold gets adopted as some point

dharrigan 2021-03-31T15:33:06.112900Z

it has nice constructs

2021-03-31T15:33:33.113300Z

I just bought ztellman's book actually and really liking it so far

mccraigmccraig 2021-03-31T16:10:54.115500Z

i agree @dharrigan - promises/deferreds and streams work really nicely together. it has shortcomings too though, mainly around streams - most obviously that there is no error-state for streams (core.async has the same issue) so you end up having to wrap all the manifold.streams fns with versions which interpret errors on the stream

dharrigan 2021-03-31T16:11:40.115900Z

yeah, it could be worked upon to make it better, it would be a shame for it to just stagnate.

harryvederci 2021-03-31T18:00:44.121700Z

Hi! I've been lurking here every now and then. I have been waking up at 5am every day to learn Clojure on my own, hoping that one day it would pay off. Today it has: I've signed my first contract for a role as Clojure developer! 🎉

💯 7
👏 3
🎉 10