Fork me on GitHub
#clojure-europe
<
2024-03-25
>
dharrigan07:03:54

Good Morning!

thomas08:03:31

Good morning

ray08:03:03

Good morning

❤️ 1
plexus08:03:12

Does anyone from Exoscale hang out here?

mpenet08:03:54

I am at my kids school atm, but let me know if I can help. I can always redirect your questions to someone else worst case

plexus08:03:54

Hi! Would you be able to get our Heart of Clojure sponsorship brochure into the right hands? In the past Pierre-Yves was our contact, but it seems he's moved on to something new.

plexus08:03:33

You're also on the Clojure Together board, right? Would be nice to have a chat sometime, see what we can do to represent CT at the conference.

mpenet08:03:42

I am on the CT board yes. Sure we can schedule a chat sometime to discuss these things

👍 1
plexus08:03:35

Thanks! Let's take this to DM.

schmalz09:03:18

Morning all.

imre09:03:34

Good morning folks

maleghast09:03:09

madainn mhath :flag-scotland:

Rachel Westmacott16:03:40

Does anyone else feel like

(fn [a b :as args]
  ...)
ought to work? (Before you head to your REPL: it does not.)

Mario G16:03:59

maybe you meant something like this? (fn [{:keys [a b] :as args}] ...)

Ed16:03:37

maybe ... but

((fn [& [a b :as args]] [a b args]) 1 2 3 4 5)
works though

1
Ed16:03:05

I wonder if the reason it doesn't is for arity disambiguation reasons? ... maybe to get the :as args part to work, the function needs to take any number of arguments, not just 2 or more?

Mario G16:03:36

short answer though: no I didn't expect the first above to work (else it would have been a very welcome something new to learn today)

Rachel Westmacott16:03:56

yeah, I didn't think it would when I tried it

Rachel Westmacott16:03:17

it just sort of made sense that it might - the intent is fairly clear

flowthing18:03:26

So at $WORK, we have many Clojure microservices. They communicate asynchronously via RabbitMQ and synchronously via HTTP. I believe that the actual problems in this scenario are a) the excessive number of services and b) excessive synchronous communication between those services. I don't think either is going away any time soon, though. I find things fiddling with path parameters, query parameters, body parameters, coercion, and other limitations of HTTP APIs quite frustrating. So much effort for so little gain. So I figured maybe I could make an RPC thing that leverage's Clojure's strengths and use that instead of HTTP for communicating with internal Clojure services. Using it would look something like this:

;; OK
(send client {:op :ping})
;;=> {:val :pong :result :ok :id #uuid "c93e56ed-3491-4cfa-a797-70e04926b2fa"}

;; Timeout
(send client {:op :ping :recv-timeout (Duration/of 1 ChronoUnit/NANOS)})
;; => {:result :anomaly :val {:cognitect.anomalies/category :cognitect.anomalies/unavailable}}
So very much nREPL-inspired, but simpler, and without all the dev tooling related bits, of course. Persistent TCP connection with automatic reconnection (retries with exponential backoff and all that jazz), virtual thread per request, Transit over MessagePack for performance and extensibility (Transit handlers), server extensible via multimethods (`(defmethod handle :my-cmd [...] ...)`), built-in distributed tracing support, maybe SSLServerSocket for encryption, etc. Please convince me that this is a horrible idea and that I shouldn't pursue it so that I don't end up wasting dozens of hours building the damn thing.

Ben Sless18:03:55

Hell, go for it Do it on top of a MQ

Ben Sless18:03:42

I did something similar on top of Apache Kafka with broadcast and send semantics

flowthing18:03:35

I figured I'd just use java.util.concurrent.BlockingQueues. 🤷

Ben Sless18:03:35

Well, yes, but the data will get sent to another service in the end?

flowthing18:03:01

Yes, I figured I'd just use sockets.

flowthing18:03:05

I mean I suppose it would have the benefit of retaining messages in case the server is down, but I'm not sure how useful that'd be since I'm sorta looking for something that replaces HTTP, which doesn't have that anyway.

flowthing18:03:43

I think it would be possible to build the thing mostly without dependencies (except for Transit and MessagePack).

flowthing18:03:11

Although since RabbitMQ is already in the picture anyway, using its RPC thing would probably be an easier sell... duckie

Ludger Solbach18:03:32

define a nice protocol and make the connection (tcp, message broker, maybe core.async) adaptable. 😉

flowthing18:03:26

Yeah, that’s a good idea. 🙂

borkdude19:03:31

I worked on a project once where we did something very similar also on top of RabbitMQ

flowthing19:03:50

Interesting! How did it turn out?

Ludger Solbach19:03:27

I'd really fancy a core.async protokoll over whatever connection you have.

Ludger Solbach19:03:21

A channel on both sides and a pluggable connection in between.

borkdude19:03:57

I think we also used core.async

Ludger Solbach19:03:31

makes complete sense to me

flowthing19:03:26

core.async is nice, but it's a pretty hefty dependency, and carries a quite significant startup time penalty. But yes, it should probably be easy to plug it in if you want to.

borkdude19:03:12

you might be able to use virtual threads and perhaps promesa

borkdude19:03:24

anyway, details

😁 1
Ben Sless19:03:35

Anyone ever think to use Redis's serialization protocol for other transports, like instead of JSON? I wonder if it could have better performance

grav19:03:24

It's this one, right? https://redis.io/docs/reference/protocol-spec/ Never heard of it before! But then I've never used Redis either.

Ben Sless19:03:31

That's the one. What I find interesting is the prefix length encoding may have better performance, especially when building immutable objects

grav19:03:47

So https://github.com/benashford/jresp implementation seems to pre-allocate an array of the decoded prefix-size: https://github.com/benashford/jresp/blob/master/src/main/java/jresp/state/AryState.java#L46 I guess that's already on the right track?

grav19:03:03

Whereas the "core" json-parser for Clj seems to create a mutable array and then conj to it as it goes, since it doesn't know how long the array is: https://github.com/clojure/data.json/blob/master/src/main/clojure/clojure/data/json.clj#L331 (If I am reading mutating Clojure-code correctly)