Fork me on GitHub
#reitit
<
2019-09-11
>
Misha Bohdan13:09:36

Hello, I have a problem with a coercion. I have a following route

(def routes
  ["/branch" 
   ["/:branch-id" {:parameters {:path {:branch-id ::specs/id}}
                  :coercion   reitit.coercion.spec/coercion}
    subbranch-routes]])

(def a (atom {}))

(def subbranch-routes
  ["/subbranch" {}
   ["/say-hello" (fn [request] (reset a request) (response/ok "Hello"))
    {:post {:handler 
            :responses {200 ::specs/response}}}]])
After performing request to /branch/1/subbranch/say-hello I’ve found following in a
(-> @a first :path-params)
{:branch-id "1"}
but I expected
{:branch-id 1}
Could someone help me with this? PS: I used following middlewares for coercion
coercion/coerce-exceptions-middleware
                   coercion/coerce-request-middleware
                   coercion/coerce-response-middleware

ikitommi15:09:16

@bohdan.mikhail the coerced parameters are written under :parameters, so (-> @a first :parameters :path) should do it

Misha Bohdan15:09:13

Thanks! For some reason, coercion doesn’t work at all. If I use interceptors and middlewares at the same time which one will run first?

ikitommi15:09:52

middleware & interceptors are not compatible. You should pick one. The request differs shows which mw/int are run and how they modify the request.

ikitommi15:09:18

could record some tutorial videos on those..

Misha Bohdan15:09:30

Is there will be some warning or so if you trying to use both at the same time? It will be very helpful.

ikitommi15:09:16

you can turn on the spec validation for route data and use closed specs, will error on undefined keys

kenny18:09:34

Is there a way to wrap all calls after a particular interceptor in a binding?

ikitommi18:09:07

I believe Pedestal has something for that. Sieppari doesn't and most likely, never will. Mixing thread-local bindings with potentially async code is not a good idea, IMO.

kenny18:09:59

Hmm. Previously we would have a map of key-values that would get included in all log messages by binding in a top-level middleware. Is there an alternative with Reitit? For example, when a request comes in, tag it with a Request-ID and all log messages after that will include the request-id in the their message.

kenny18:09:01

I could do something like this:

(def mdc (proxy [ThreadLocal] []
           (initialValue []
             (atom {}))))
That assumes the 1 thread per request model though. I assume if you use core.async, it is no longer 1 thread per request.

kenny18:09:14

Logback's MDC is also thread local: https://logback.qos.ch/manual/mdc.html. How does returning a core.async channel as a response fit into this?

ikitommi18:09:42

Pedestal1 stores the bindings in a request map and it works with core.async too. So if you need that, you could use reitit-pedestal instead of reitit-sieppari, see http://pedestal.io/reference/context-map#_description

ikitommi18:09:45

It is handy, but meant for single-threaded environments. To be pure, you could just put the raw info into context and have a context-logger that takes the context as argument and reads those from there.

kenny18:09:19

In an ideal world, that's how it would work. We need to interop with Java libs that support MDC contexts. Further, I don't want to pass a whole context map to every single function that wants to log something, that's simply not scalable.

thomascothran20:09:30

Is there a known cause for Reitit memory consumption to continually increase when serving large maps? Curious if I'm configuring it wrong. In my application, if the :body key is a map and there's a client continuously polling that endpoint, memory consumption will increase until an OOM. However, if I convert the map to a JSON string myself, this doesn't happen. (These maps are quite large.)

thomascothran20:09:22

Here's an example

thomascothran21:09:13

In this example, the left side of the screen is being polled without manually converting the body to a JSON string, and the right side of the screen is converting the body to a JSON string with clojure.data.json. (In the middle of the screen, the client has stopped polling.)

thomascothran22:09:55

One thing I am doing is customizing the way JSON is decoded:

(def m
  (muuntaja.core/create
   (assoc-in muuntaja.core/default-options
             [:formats "application/json" :decoder-opts]
             {:decode-key-fn identity})))
Then I'm using m in ring-router. Something like this:
(ring-router
   ... routes here
   {:data {:muuntaja m
           ...}})
I think that's the only non-standard thing I'm doing.

ikitommi04:09:09

what web server are you using? if that supports byte-arrays, you could try assoccing :return :bytes to muuntaja config.

ikitommi04:09:40

but, need to find the original cause and fix that.

thomascothran13:09:51

@ikitommi I'm using Aleph 0.4.7-alpha5. I'll see if I can get a repro together.

thomascothran13:09:22

Also, this isn't urgent from my perspective. I know things are probably busy with ClojuTRE coming up, and I'm able to prevent the OOM errors by converting to a JSON string myself.

👍 4
thomascothran19:09:04

Here's a small repro of the memory leak: https://github.com/thomascothran/memory-leak-repro (Haven't tried the :return :bytes suggestion yet)

thomascothran19:09:00

If I set :return to :bytes in the Muuntaja config, I don't get the memory leak. Thanks for that pointer @ikitommi