This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-02-04
Channels
- # announcements (7)
- # babashka (26)
- # babashka-sci-dev (19)
- # beginners (66)
- # calva (4)
- # clj-kondo (55)
- # cljs-dev (173)
- # cljsrn (17)
- # clojure (86)
- # clojure-art (3)
- # clojure-australia (1)
- # clojure-europe (24)
- # clojure-india (1)
- # clojure-nl (3)
- # clojure-uk (6)
- # clojured (5)
- # clojurescript (39)
- # cursive (8)
- # data-oriented-programming (20)
- # datomic (9)
- # emacs (10)
- # events (1)
- # figwheel-main (16)
- # fulcro (33)
- # gratitude (1)
- # helix (2)
- # hugsql (2)
- # jobs (2)
- # kaocha (4)
- # leiningen (5)
- # lsp (110)
- # malli (1)
- # missionary (17)
- # observability (3)
- # re-frame (10)
- # reagent (1)
- # reitit (7)
- # rewrite-clj (3)
- # shadow-cljs (63)
- # sql (19)
- # tools-build (74)
- # tools-deps (32)
- # transit (1)
- # xtdb (5)
What's the state of the art in http server libraries atm? I'm using reitit for routing, I'll probably be using sieppari for interceptors, and I'm curious what the modern recommendation is for servers. Ring is the old stand-by, but it focuses mostly on middleware and while that can be adapted for interceptors that's still stuff I'd have to do for it and it wouldn't likely connect well with the existing ring libraries for auth, sessions, and other stuff. There's http-kit which is pretty cool but the site and docs are unmaintained for the most part (despite the actual lib still seeing updates) and has some interesting features about which I know very little, like websocket promotion.
ring isn't an http server, it is an interface that defines http request responses in terms of clojure function calls. Often when people speak about ring in terms of http servers they are refering to ring-jetty-adapter, but there are are adapters for a number of http servers
right, I suppose I haven't dived into that ecosystem enough to remember that off the top of my head. Thanks for the clarification!
right, and so does http-kit, with a similar api to ring
as to state of the art, interceptors are maybe still that, but they have been around a while and haven't really unseated ring as the go to
we have two services that use bidi for routing (which predates reitit, but provides some features I really like over compojure like reverse routing), and one service that uses a netty based http server
we've experimented with using http-kit over jetty, but didn't get as good newlic metrics reporting
I have seen reverse routing as a feature, but I'll admit I have yet to get when it would be useful.
reverse-routing++ ❤️
the bidi stuff does bite us from time to time because everything else is ring/compojure so sometimes things need to be worked around for one reason or another
(reitit has the same thing and will build the url for you from params)
we use interceptors at nubank for not only web servers, but Kafka message consumption and production
I find an assembly line / bulletin board style of work separation easier to deal with than function composition (ring)
Interceptors are clearly an easier mental model
The downsides are performance, if you care about maximizing latency throughput or minimizing response times. They're still an excellent fit 99% of time, although they can fall into the trap mentioned in out of the tarpit of passing a bit ol' context map which contains too much
that seems pretty cool
interceptors handle request coercion, serialization, validation, auth, signing/validation, all sorts of things
almost 😉 - skimming through pedestal docs looks like the interceptor model is just better when you need async
Here are some non-async things I like about Pedestal's interceptors. Interceptor chains assemble as data, not code. Interceptors' error handling is more purposeful. The context map, distinct from the Request (where the same stuff winds up in Ring), lets my program complain about the Request without including the sausage-making ingredients.
ah just curious, wanted to clarify that point before diving deep in since most seems to doing async stuff with it, thx
I’m struggling to get the -P
switch to work (to cache dependencies in CI)
My makefile contains:
deps:
clojure -P -J-Xmx1024m -X:jar :jar target/app.jar
jar:
clojure -J-Xmx1024m -X:jar :jar target/app.jar
And my dockerfile:
FROM openjdk:12-jdk-alpine AS build
RUN apk add bash curl build-base
RUN curl -O
RUN chmod +x linux-install-1.10.1.478.sh
RUN ./linux-install-1.10.1.478.sh
RUN apk add bash \
gcompat \
libsass
RUN adduser -S app app
WORKDIR /app
COPY Makefile deps.edn ./
RUN chown -R app /app
USER app
RUN make deps
USER root
COPY entrypoint.sh /app/
COPY resources /app/resources/
COPY dev /app/dev/
COPY src /app/src/
RUN chown -R app /app
RUN chmod +x /app/entrypoint.sh
RUN make jar
USER app
EXPOSE 3000
CMD ["/app/entrypoint.sh"]
As you can see make deps
is ran, and a couple of lines down I also run make jar
.
Yet, RUN make jar
will still re-download all the dependencies.
Why isn’t -P
respected?oh dear you’re right, i’m running one as root and the other as app
that’s not it, even if I put them right next to each other, make jar
will re-download the deps
USER app
RUN make deps #bump
RUN make jar
EXPOSE 3000
CMD ["/app/entrypoint.sh"]
^ has the same issueI would replace the calls to make file with the direct calls to the clojure cli for debugging purposes
if it is actually downloading the same stuff again that is very odd, I would start using ls to see if after make deps runs app has an ~/.m2 and it has things in it, is there a .cpcache directory, etc
HI. I wonder why we have a puts queue
for async channel? https://github.com/clojure/core.async/blob/6ac8ed2a26c67bbc3cc43e4e650f97c984666b0c/src/main/clojure/clojure/core/async/impl/channels.clj#L158. Why don’t we directly rely on the channel buffer?
What if you have an unbuffered channel? Have you watched the video which goes a bit into the implementation of channels?
> What if you have an unbuffered channel? Every queue is buffered, why not make the things explicit?
Having a put! only makes things complicated as clojure will from time to time throw exceptions when the puts queue reaches its max size.
But if channels actually register callbacks behind the scenes you need a queue for that
I also remember something about interaction of transducers and async chans. Since transducers may produce multiple results per step, there was a semantic mismatch between limited-buffer channels and transducer logic — so maybe this has something to do with handling this mismatch gracefully?
iirc the way it's handled is with Channels' internal buffers being actually unbounded, and while external "puts" are rejected, they can "overflow" from transducers producing multiple values.
Hello !
is there a "better" way to check if a namespaced keyword is from a specific namespace other than (= (namespace said-keyword) "namespace-name")
?
Thanks in advance !
@U9W44J4RW I'm curious; what do you find lacking in that approach, that you think could be done better?
I guess I expected there to be a (namespaced? ns-symbol key)
thanks guys, I suppose my eyesight isn't that bad
I am using a library that returns values in clj but in cljs it returns a chan that will eventually have that value. This presents a problem that processing of that value must now have split logic for channel vs non-channel value. Is there some sort of small utility library that would smooth over that?
Wouldn't always putting the value in the CLJ case into a channel and then work with a channel in both CLJ and CLJS solve the problem? I doubt adding a whole new library to your project just because of this small thing would be worth it.
Because the original author specifically took values out of channel: https://github.com/fulcrologic/fulcro-rad-kvstore/blob/master/src/main/com/fulcrologic/rad/database_adapters/key_value.cljc#L80
I meant that you can create a new one-off channel on your own, to mimic what's going on in CLJS.
And if the problem arises from calling table->rows
directly then it seems like you could just call kv-konserve/table->rows
instead on the CLJ side of things.
I’ll manage something I think, thanks
I want to put into spec that something is a core.async channel, but I cannot find a predicate for that… am I missing something?
spec does not have a function for that, and indeed core.async itself doesn't have a predicate for channels
the best you can get from what I've seen is satisfies?
with ReadPort
and WritePort
For some reason, the following compiles and runs fine:
(let [{:keys [a b c]
:or {a 1 b 2
c (for [i (range a)
j (range b)]
[i j])}} nil]
[a b c])
;;=> [1 2 ([0 0] [0 1])]
But the following doesn’t:
(defn transform2
[{:keys [algo opts] frame :hydrated fill :compressed}]
(let [{:keys [rcs rsiz csiz]
:or {rsiz (count frame)
csiz (-> frame first count)
rcs (for [i (range rsiz)
j (range csiz)] [i j])}} opts]))
;;=> ... Unable to resolve symbol: csiz in this context
What am I missing? Thanks for any comment..
Your first example isn't considered desired/stable behavior either iirc (using restructured keys in a default that is)
yeah, don't do this
maps are unordered, :or exprs are run in arbitrary order, and we make no promises about when those evaled in combination with let bound keys
can i rely on the observation that (into [] (apply sorted-set (reverse (range 10000)))
produces a sorted vector?
here, yes
Generic Q as somebody who doesn't always follow the Clojure world closely: have there been any announcements/roadmaps about where Clojure is headed now w/ NuBank in play? How has the strategy/roadmap changed? That kind of thing. Thanks.
This statement from Ed when Cognitect joined Nubank is a great overview of intent and (18 months later) continues to be pretty close match https://building.nubank.com.br/welcoming-cognitect-nubank/

we don't really do roadmaps per se, but when we talk about problems we want to solve they are not substantially different now than they were pre-Nubank. they are influenced and informed by being in colocation with the largest Clojure/Datomic user base) but not sure that's really changed the trajectory too much.
(except all the Nubank numbers there seem small now :)