Fork me on GitHub
#clojure
<
2022-11-21
>
tlonist08:11:04

What server libraries are you using for web development? My requirements are that the library should be • performant • supporting web socket (built-in), mainly for graphql subscription • maintained My intention is to check out what others are using mostly and ask questions regarding the library's usability and condition. FYI, I've been using ring-jetty for about 1.5 years and am trying to move onto the one that supports built-in web-socket.

p-himik08:11:44

Aleph.

👍 1
dharrigan09:11:47

This https://github.com/sunng87/ring-jetty9-adapter is a drop-in replacement for ring-jetty-adapter, that supports Jetty 11 and websockets...

👍 1
tlonist09:11:36

@U2FRKM4TW why would you choose Aleph over the others? I'd like to hear your opinions!

p-himik09:11:43

Because at the time when I was choosing a web server, I settled on yada as it seemed like a good choice compared to everything else. Nowadays, I wouldn't recommend it, but it's built on top of Aleph which by itself is pretty good performance- and feature-wise.

1
p-himik09:11:17

But might be a bit too low-level by itself, so maybe there are some libraries that are built on top of it.

niwinz09:11:29

on penpot we using a custom undertow based one: https://github.com/funcool/yetti, I mention it just for information, unless you want to use undertow and ring-2.0 like interface and you are prepared for possible breaking changes in the future, I don't really recommend using it.

sheepy 1
1
tlonist14:11:40

So, so far we have aleph, ring-jetty9-adapter, yetti and kit-clj.. anymore?

seancorfield18:11:05

I'll +1 for ring-jetty9-adapter -- we've used the default Jetty 9 support in Ring for years in production and we recently added our own WS support via Java interop and it was pretty gnarly. However, 9.x is out of community support and we wanted to upgrade to 10 or 11 and so we switched to the sunng adapter and the WS support is very nice and the whole adapter seems to work really well and -- important for us -- Jetty is well-supported by New Relic so we get great observability.

1
seancorfield18:11:43

(the sunng adapter is using Jetty 11.0.12 at this point)

Jungwoo Kim23:11:39

No one mentioned pedestal?!

henrik09:11:08

Anyone else seeing Exception in thread "main" java.lang.NoSuchFieldError: __thunk__0__ when running an uberjar compiled with core.async 1.6.673?

Alex Miller (Clojure team)12:11:03

If you are aot compiling, you may now need to aot compile clojure.core.async.impl.ioc-macros (I’d put it first in your aot list)

Alex Miller (Clojure team)13:11:00

This namespace is now dynamically loaded as of 1.6.673

Alex Miller (Clojure team)13:11:42

I think the error you’re seeing is a result of compile ordering as this namespace is now only needed for go compilation and you shouldn’t actually need it at runtime (which makes loading faster), but I assume there is something weird with compilation load ordering that’s leading to this

henrik08:11:38

i’m compiling with tools.build defaults, so I think that means that the main NS is compiled, but the rest of the app isn’t, correct? The main NS doesn’t contain any core async stuff itself, but transitively it does, via requires. Compiling clojure.core.async.impl.ioc-macros along with the main namespace seems to work.

Alex Miller (Clojure team)12:11:28

Do you know what lib includes core.async in your deps?

henrik12:11:34

It would seem to be Clerk, and also Shadow-cljs.

phill23:11:11

Roping the aforementioned ioc-macros into AOT by requir'ing it in a successfully AOT'd namespace changed the error, thrown by macroexpand of go in an eval, to another unresolved symbol. (With clojure-maven-plugin, I was not sure how to try the exact AOT experiment suggested by @U064X3EF3)

Martynas Maciulevičius13:11:14

Hey. I think that when I switched from Spacemacs to running lein repl I get this weird issue that I get Error: java.lang.NoClassDefFoundError: for my own project namespaces. For instance if I run a REPL for a longer time then for the namespaces that I didn't use for a while I can get this error. I think that somehow it collects my namespace and releases it. I don't understand what it is. Did anybody have anything similar? Why could this happen? My REPL can sometimes use a lot of RAM as the app needs it. :thinking_face:

vemv18:11:16

are you using a bare lein repl, or also have other tooling (like cider-nrepl) around? either way, I'd suggest posting the entire stacktrace :)

Martynas Maciulevičius07:11:56

I use Leiningen and nREPL. Got one more today. My fix is to restart my REPL 🤷

#error {
 :cause "__/parse/json_struct$parse_struct_or_json$to_kw__17761"
 :via
 [{:type java.lang.NoClassDefFoundError
   :message "__/parse/json_struct$parse_struct_or_json$to_kw__17761"
   :at [__.parse.json_struct$parse_struct_or_json invokeStatic "json_struct.clj" 7]}]
 :trace
 [[__.parse.json_struct$parse_struct_or_json invokeStatic "json_struct.clj" 7]
  [__.parse.json_struct$parse_struct_or_json invoke "json_struct.clj" 6]
  [__._.endpoint$parse_inputs invokeStatic "endpoint.clj" 99]
  [__._.endpoint$parse_inputs invoke "endpoint.clj" 94]
  [__._.endpoint$create_handler$fn__17362 invoke "endpoint.clj" 290]
  [__._._$_ invokeStatic "_.clj" 25]
  [__._._$_ invoke "_.clj" 23]
  [__._._$_$fn__26427 invoke "form-init14091282974953506384.clj" 125]
  [__._._$_ invokeStatic "form-init14091282974953506384.clj" 138]
  [__._._$_ invoke "form-init14091282974953506384.clj" 118]
  [__._._$_ invokeStatic "form-init14091282974953506384.clj" 157]
  [__._._$_ doInvoke "form-init14091282974953506384.clj" 154]
  [clojure.lang.RestFn invoke "RestFn.java" 410]
  [__._._.read_test$eval47278 invokeStatic "form-init14091282974953506384.clj" 147]
  [__._._.read_test$eval47278 invoke "form-init14091282974953506384.clj" 147]
  [clojure.lang.Compiler eval "Compiler.java" 7194]
  [clojure.lang.Compiler eval "Compiler.java" 7149]
  [clojure.core$eval invokeStatic "core.clj" 3215]
  [clojure.core$eval invoke "core.clj" 3211]
  [nrepl.middleware.interruptible_eval$evaluate$fn__1459$fn__1460 invoke "interruptible_eval.clj" 87]
  [clojure.lang.AFn applyToHelper "AFn.java" 152]
  [clojure.lang.AFn applyTo "AFn.java" 144]
  [clojure.core$apply invokeStatic "core.clj" 667]
  [clojure.core$with_bindings_STAR_ invokeStatic "core.clj" 1990]
  [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1990]
  [clojure.lang.RestFn invoke "RestFn.java" 425]
  [nrepl.middleware.interruptible_eval$evaluate$fn__1459 invoke "interruptible_eval.clj" 87]
  [clojure.main$repl$read_eval_print__9206$fn__9209 invoke "main.clj" 437]
  [clojure.main$repl$read_eval_print__9206 invoke "main.clj" 437]
  [clojure.main$repl$fn__9215 invoke "main.clj" 458]
  [clojure.main$repl invokeStatic "main.clj" 458]
  [clojure.main$repl doInvoke "main.clj" 368]
  [clojure.lang.RestFn invoke "RestFn.java" 1523]
  [nrepl.middleware.interruptible_eval$evaluate invokeStatic "interruptible_eval.clj" 84]
  [nrepl.middleware.interruptible_eval$evaluate invoke "interruptible_eval.clj" 56]
  [nrepl.middleware.interruptible_eval$interruptible_eval$fn__1492$fn__1496 invoke "interruptible_eval.clj" 152]
  [clojure.lang.AFn run "AFn.java" 22]
  [nrepl.middleware.session$session_exec$main_loop__1562$fn__1566 invoke "session.clj" 218]
  [nrepl.middleware.session$session_exec$main_loop__1562 invoke "session.clj" 217]
  [clojure.lang.AFn run "AFn.java" 22]
  [java.lang.Thread run "Thread.java" 829]]}

pavlosmelissinos14:11:18

Was https://clojars.net ever a valid domain for clojars? For a certain web search I'm getting it as the first clojars related result but its SSL certificate is invalid, so it doesn't seem legit. 😕

Casey16:11:20

IIRC http://clojars.net is owned by the http://clojars.org folks but isn't really used.

Casey16:11:46

I've seen people publish artifacts on clojars with both org.clojars.<username> and net.clojars.<username>

pavlosmelissinos16:11:56

I see... For what it's worth, here's what Firefox reports: > The certificate is only valid for the following names: http://clojars.org, http://beta.clojars.org, http://www.clojars.org, http://ipv6.clojars.org, http://releases.clojars.org > > Error code: SSL_ERROR_BAD_CERT_DOMAIN

pavlosmelissinos16:11:30

Seems like the certificate should also include http://clojars.net ? Not sure who I should notify about this

Casey16:11:18

My guess would be to report it here: https://github.com/clojars/clojars-web

🙏 1
Ben Sless18:11:00

Sorry for cross posting, looking for feedback on this approach or any pointers why it's a terrible idea Still unsolved, inspecting the form before inline is called

jpmonettas18:11:36

is there any official documentation for inline and inline-arities, with some use cases? They aren't documented here, https://clojure.org/reference/vars

jpmonettas18:11:48

having a hard time figuring out what is the purpose of inline when it expands to the same thing as it's body, like in this piece of clojure.core

(defn zero?
  "Returns true if num is zero, else false"
  {
   :inline (fn [num] `(. clojure.lang.Numbers (isZero ~num)))
   :added "1.0"}
  [num] (. clojure.lang.Numbers (isZero num)))

hiredman19:11:01

it is a feature that clojure.core uses for performance optimizations, but I don't think it is considered entirely baked, so not documented

hiredman19:11:25

it is basically like a defining a macro and a function at once

hiredman19:11:03

in higher order usage, where the function being called isn't known statically, you can call it like a function

👍 1
hiredman19:11:38

when directly invoked, the call to the function is replaced by the inlined code

jpmonettas19:11:29

in what situations would you write something like that clojure.core/zero? where you write the same code twice?

hiredman19:11:58

replacing with the inline code for clojure.core allows the compiler to see static method calls directly, and potentially replace the static method call with an intrinsic

jpmonettas19:11:05

but why would you then also write the same code a second time as the defn body, I guess when there is :inline, the body isn't used in this case?

Alex Miller (Clojure team)19:11:57

Inline is an alpha and undocumented feature. It has some sharp edges in practice, particularly around primitives (where it makes the most sense to use it)

👍 1
Alex Miller (Clojure team)19:11:21

And yes, if used as a hof you will get the body

👍 1
Alex Miller (Clojure team)19:11:12

We spent time during the Clojure math work looking at some alternate formulations, but it’s complicated

Alex Miller (Clojure team)19:11:55

I think Rich would prefer to have something more like compiler macros (?) from Common Lisp tbh, which is why this has never really graduated to being official

jpmonettas19:11:30

interesting, I never used compiler macros in CommonLisp

skylize19:11:06

Am I correct in thinking that the inline version of zero avoids boxing? If I am right, then I think that is the "why" that @U0739PUFQ looking for. The bodies are almost the same, but ~num in a macro context is getting you straight to the raw numeric type instead of a number inside an Object.

hiredman19:11:57

boxing is part of it, but because the call to zero would be replaced by the inlined call to the static method, the clojure compiler can directly check if the static method is one it knows how to replace directly with a series of bytecode instructions

👍 1
hiredman19:11:07

so var dereference, function call, static method call, etc all potentially go away, and you just have a bytecode instruction

Alex Miller (Clojure team)19:11:42

There is also a second layer of inlining called intrinsics in the Clojure compiler that does something similar (and another level of intrinsics in the Java compiler that replaces with assembly) and some of these work together

Alex Miller (Clojure team)19:11:25

Some of the new clojure.math calls are inlining calls to Math, which are jvm intrinsics for example

jpmonettas19:11:31

thanks evetybody, I think I understand things a little better now

Ben Sless20:11:42

How are compiler macros different from inline meta? I read the clhs and can't see an immediate difference. What am I missing?

Alex Miller (Clojure team)20:11:19

don't know, this is a dim memory from a conversation like 7 years ago

jpmonettas20:11:50

maybe that compiler macros can wrap any form, while the current :inline is for vars only?

jpmonettas20:11:26

nvm, looking at the Compiler.java code is for any seq expr

Joshua Suskalo21:11:31

To give another example of a usecase for this, in the #C02EEAUHSJJ library I have functions which are allowed to be used as functions, but when you do they have very little information available and so produce extraneous calls to no-op serialization functions which require multimethod dispatch. In the inline definition I am however able to instead generate a function form which is specific to the level of information available at the callsite which reduces overhead of serialization by a huge margin.

shaunlebron22:11:37

How do I keep my program from exiting after a long timeout?

(go
  (<! (timeout 60000)) ;; wait 60 seconds
  ;; NOTE: my program exits here without executing (foo) below
  (foo))

hiredman22:11:40

what keeps the jvm running are non-daemon threads

hiredman22:11:07

or I should say running non-daemon threads

isak22:11:57

So you could create a promise you never deliver (or at least until after (foo)) , then dereference it on the main thread.

hiredman22:11:29

the threadpool go blocks run on are daemon threads, so they don't prevent the jvm from exiting, and even if they were not, what you have there is a callback waiting on the timeout channel, so no running thread daemon or otherwise anywhere

shaunlebron22:11:28

how do people normally keep a clojure process from exiting then if there are go-blocks still running

thheller22:11:29

just do not use go.

thheller22:11:00

or (<!! (go ...)) if you must

😃 1
shaunlebron22:11:21

I just want to run something after n minutes

thheller22:11:55

on the current thread or a "new" thread?

shaunlebron22:11:22

current thread is fine, should I just use thread sleep?

shaunlebron22:11:58

alright I’ll not worry about why go-blocks don’t work then

shaunlebron22:11:48

thanks all 👋