This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-03-25
Channels
- # announcements (30)
- # beginners (4)
- # calva (173)
- # cider (22)
- # clj-kondo (12)
- # clojure-austin (2)
- # clojure-brasil (1)
- # clojure-europe (56)
- # clojure-korea (1)
- # clojure-nl (1)
- # clojure-norway (53)
- # clojure-uk (5)
- # clojurescript (25)
- # data-science (82)
- # hyperfiddle (87)
- # introduce-yourself (11)
- # jobs-discuss (44)
- # malli (4)
- # off-topic (7)
- # pedestal (8)
- # re-frame (16)
- # releases (1)
- # shadow-cljs (41)
- # slack-help (5)
- # sql (1)
- # squint (1)
Morning!
Good morning
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
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.
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.
I am on the CT board yes. Sure we can schedule a chat sometime to discuss these things
Does anyone else feel like
(fn [a b :as args]
...)
ought to work? (Before you head to your REPL: it does not.)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?
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)
yeah, I didn't think it would when I tried it
it just sort of made sense that it might - the intent is fairly clear
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.RabbitMQ already has an RPC thing: https://www.rabbitmq.com/tutorials/tutorial-six-java
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.
I think it would be possible to build the thing mostly without dependencies (except for Transit and MessagePack).
Although since RabbitMQ is already in the picture anyway, using its RPC thing would probably be an easier sell...
define a nice protocol and make the connection (tcp, message broker, maybe core.async) adaptable. 😉
I worked on a project once where we did something very similar also on top of RabbitMQ
I'd really fancy a core.async protokoll over whatever connection you have.
A channel on both sides and a pluggable connection in between.
makes complete sense to me
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.
Anyone ever think to use Redis's serialization protocol for other transports, like instead of JSON? I wonder if it could have better performance
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.
That's the one. What I find interesting is the prefix length encoding may have better performance, especially when building immutable objects
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?
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)
Here's a slightly more involved RESP parser https://github.com/redis/lettuce/blob/main/src/main/java/io/lettuce/core/protocol/RedisStateMachine.java