Fork me on GitHub
#clojure
<
2023-05-11
>
jdkealy06:05:16

I'm having a problem in a ring app and it's totally new to me. I had middleware working which would inject :current-user into every request object. All of the sudden I intermittently had certain endpoints returning 403's with the message "you must be logged in" The endpoints are consistent for different endpoint/user combinations. I looked into it and noticed by swap!'ing a debug variable that my handlers are being called twice in the instance of the 403's and only once in the 200's. These are the only clues I could generate about my current bug, what else should I be looking for?

jdkealy06:05:37

e.g. an endpoint like /current-user , the handler could be called twice per network request

igrishaev07:05:43

Maybe it's your browser that duplicates the requests? CORS os favicon.ico? I think it's worth checking the network tab in your browser and check what and who emits those extra requests.

jdkealy07:05:19

the browser definitely doesn't do it

jdkealy07:05:05

In the network tab, I see just one request

jdkealy07:05:09

(def cusess-handlers
  ["/current-user-sessions" {:get {:handler (fn [r]
                                              (swap! dbggg conj r)
                                              (response {:ok true})
                                              ;;(get-current-user-sessions-handler r)
                                              )}
                             :swagger {:tags ["sessions"]}}])

jdkealy07:05:10

In this instance, I can see there's one (swap! dbggg conj r) per request... i.e. the @dbgggg atom increments by one request every request on the endpoint

jdkealy07:05:00

But then if I flip to

{:handler (fn [r]
                                              (swap! dbggg conj r)
                                              ;;(response {:ok true})
                                              (get-current-user-sessions-handler r)
                                              )}
I can see the endpoint is getting hit twice!

igrishaev07:05:58

Maybe there is something in your router or middleware that performs the request twice.

jdkealy07:05:46

makes sense... i think there could be some exception retry handling or something

p-himik08:05:11

> In the network tab, I see just one request Browsers don't show some requests in there. The most robust way to determine it is to read your server's logs or use Wireshark.

p-himik08:05:03

Also, in case you're using Reitit there's a debug route transformer - it will print out request and response information before and after every middleware, including a colorful diff.

jdkealy08:05:34

Thanks. I zero'd in on there not being a second network request. I found the unhandled exception and I don't know why, it's calling the handler to be called a second time.

p-himik08:05:05

What middleware do you have? Easy to imagine for it to be something a tad weird like

(try
  (handle (wrap request))
  (catch Exception _
    (handle request)))

DrLjótsson12:05:19

Have you checked what goes on in the session middleware? Does it receive a cookie and match it to a session?

DrLjótsson12:05:37

Oh, sounds like the 403 has been resolved. Nvm

port1911:05:39

For thread and unwind, do you guys use the clojure- or the cljr- functions?

tomd11:05:53

Is this in emacs? I'm pretty sure the cljr- functions for thread and unwind are obsolete and simply alias the clojure- functions

port1912:05:42

yeah, emacs

tomd13:05:07

There's #C099W16KZ btw. Why do you ask? Have you noticed a difference?

port1915:05:03

No, just configured all my clojure keybindings and saw an overlap

👍 1
pppaul17:05:03

always use clojure mode functions over cljr, as they don't require compiling. I'm a bit biased as my cljr almost never works

Henrique Prange15:05:06

Hi everyone! I’m trying to make an existing Java class implement Seqable. I’ve looked into using extend-type, but it seems that this only allows me to implement protocols, not interfaces. Does anyone have any suggestions for how I can achieve this?

p-himik15:05:37

You can't extend an existing (compiled) Java class to implement a Java interface. You might be able to: • Change that class in the source code so it extends that interface via regular Java means • Create a new class that inherits the existing one and implements the interface • Create a new class that delegates to the existing one and implements the interface

Henrique Prange16:05:04

Unfortunately, I am working with an external library Java class, so I cannot modify its source code to extend the interface directly. Creating a new class that inherits or delegates to the existing one is also not an option for me. Do you know if there’s a protocol I could use instead to work around this problem?

p-himik16:05:14

Are any wrappers completely out of the question? Or only Java ones?

p-himik16:05:56

If you can't wrap instances of the existing class in anything at all, then I believe you're out of luck because the seq function can only be applied to the following things: • Implementers of one of these interfaces Seqable, Iterable, CharSequence, Map • Subclasses of the ASeq class • Instances of the LazySeq class • null • Arrays

👍 1
p-himik16:05:25

If you can create a wrapper in Clojure, then you can simply use reify, just like the iteration function does.

👍 1
Henrique Prange16:05:49

Wrappers are not out of the question. In fact, I have considered creating a protocol that “mimics” the Java class and using reify to implement the protocol and Seqable interface. However, I’m curious if there’s a simpler or more straightforward way to achieve this.

dnolen18:05:11

hrm, what’s the pattern for accessing a static field on a Java interface? I guess I somehow haven’t run into this before

José Javier Blanco Rivero18:05:42

e.g. (Integer/MAX_VALUE)

dnolen18:05:59

on an interface

dnolen18:05:00

not a class

dnolen18:05:28

no worries 🙂

hiredman18:05:41

user=> clojure.asm.Opcodes/ACC_PUBLIC
1
user=>

hiredman18:05:58

it is the same as with a class, and you don't need the parens for either

dnolen18:05:24

I keep getting could not initialize class …

hiredman18:05:34

that is usually a problem with a static init

dnolen18:05:44

yes it’s a static init

hiredman18:05:24

then you need to figure out why the static init is broken and fix that other wise the jvm won't load the class file and you can't read fields

hiredman18:05:07

there may be some way to read static fields from a class without running its static init, but for data types that cannot be serialized directly in byte code, those values need to be constructed and then set as the fields value, which is done in the static init

dnolen18:05:30

thanks for the hint

dnolen18:05:48

was using some random lib testing something, and that dep was messed up

jpmonettas18:05:33

kind of late but you can also add breakpoints to interface static initializers with intelliJ and then fire the load from the repl, maybe that helps debugging those kind of issues

dnolen18:05:43

yeah it was pretty cryptic, thanks for that tip too