Fork me on GitHub
#beginners
<
2021-11-24
>
sova-soars-the-sora00:11:45

Hey I'm using Selmer and the {% for item in items ... %} works with collections... Can I do a for loop just on numbers? I pass in a "chapter number" and want to print out as many items as there are chapters. Or must I pass in a collection like (range (inc chapter-number)) ?

sova-soars-the-sora04:11:48

looks like it's gotta be a collection. not a bad thing šŸ˜…

Romit Gandhi04:11:27

Hello, I'm using re-frame with shadow-cljs and for authentication using JWT. In the login/registration API I'm getting JWT along with user info so, I'm storing it in app-db as user-secret and user. Now, when I want to call any API I'm passing that token in headers so, it will verify it so, that's not an issue. But I also want to check whether user and user-secret is present in app-db when user navigate the route (Not in all route like I don't want to check that in login/registration). What is the best way of doing it? Currently, which routes I have to check I pass controllers and start & inside that dispatching an event. Eg:

["/book/add" {:name :add-book
              :view book/add-book
              :controllers [{:start (fn [_]
                                      (rf/dispatch [:check-authentication]))}]}]
And check authentication is like below.
(rf/reg-event-fx
  :check-authentication
  (fn [{:keys [db]}]
    (if (empty? (:user db))
      {:navigate! [:login]})))
Any best alternative for doing this ? Thanks.

Arthur13:11:38

An approach I took when trying to do this was to define a route like

{:name :add-book
 :view book/add-book
 :requires-auth? true}
And, inside my router, subscribe to the db's auth state and check if the desired route requires auth. I'm also interested in seeing how people handle this situation.

Romit Gandhi13:11:14

Great, actually that's a nice idea. Thanks. Do you have any kind of demo so it helps me to do this. Yes, I'm also wondering what are the different approaches that we can use for this situation.

Arthur14:11:05

Something like this:

(defn router-component []
  (let [current-route @(subscribe [::subs/current-route])
        user-is-authenticated? @(subscribe [::subs/is-authenticated?])
        current-route-requires-auth? (-> current-route :data :requires-authentication?)]
   (when current-route
     (if (and  current-route-requires-auth? (or (false? user-is-authenticated?) (nil? user-is-authenticated?)))
       [(login-view)]]
       [(-> current-route :data :view)]]]))))
I am using reitit + re frame btw, which I assume you're also using (judging by the snippet you've posted).

Romit Gandhi17:11:18

Yes, I'm using reitit + re-frame. So, you might be calling this function from rdom/render , right? Like this,

(rdom/render [router-component] (.getElementById js/document "app"))

Arthur17:11:05

Yes, youā€™re right.

Romit Gandhi04:11:57

Thanks, buddy. šŸ™‚

Noah Bogart14:11:58

what purpose does the input type hint serve here?

user=> (defn example [^String coll] (name coll))
#'user/example
user=> (example :hello)
"hello"

Ben Sless14:11:34

Non primitive type hints are there only for the compiler to help it with java interop

šŸ‘ 1
Noah Bogart14:11:46

And ā€œStringā€ isnā€™t a java primitive, I take it?

Noah Bogart14:11:05

thanks, good to know

Ben Sless14:11:16

In clojure, the only primitives which can be used as argument type hints are long and double

šŸ‘ 1
sova-soars-the-sora14:11:19

I have a vector of vectors of maps:

[ [{}{}] [{}{}{}{}] [{}{}{}] [{}] ]
each with a key i'd like to retrieve
[ [{:q 5}{:q 3}] [{:q 1}{:q 7}{:q 9}{:q 8}] [{:q 4}{:q 2}{:q 0}] [{:q 9}] ]
Can this be done w/ filter? What's a decent way to accomplish this?

sova-soars-the-sora14:11:33

I want all the :qs

vanelsas14:11:24

filter only filters the content, it won't give you parts of elements and will return the element for which the filter condition is true.

emccue14:11:01

(mapcat #(map :q %) vals)

šŸ‘€ 1
šŸ™Œ 1
sova-soars-the-sora14:11:06

@U3JH98J4R : o that was fast -- could you explain the logic behind that one for me?

sova-soars-the-sora14:11:50

not 100% sure on how to invoke

emccue14:11:12

sure. mapping :q over a collection of maps gets you a sequence of the qā€™s

emccue14:11:37

(map :q [{:q 5} {:q 3}]) -> (5, 3)

emccue14:11:59

if you map that over each one of the collections you end up with

emccue14:11:26

((5 3) (1 7 9 8) (4 2 0) (9))

emccue14:11:43

and you want to concatenate each one of those to get your result

sova-soars-the-sora14:11:00

excellent explanation thanks šŸ˜„

emccue14:11:12

which mapcat -> map and con*cat* does in. one step

sova-soars-the-sora14:11:52

so for the vals in there... are you passing in the data there?

sova-soars-the-sora14:11:08

because I get clojure.lang.LazySeq@###

sova-soars-the-sora14:11:24

maybe i need to make it realize the sequence somehow

emccue14:11:06

user=> (def data [ [{:q 5}{:q 3}] [{:q 1}{:q 7}{:q 9}{:q 8}] [{:q 4}{:q 2}{:q 0}] [{:q 9}] ])
#'user/data
user=> (mapcat #(map :q %) data)
(5 3 1 7 9 8 4 2 0 9)

sova-soars-the-sora14:11:06

(i'm passing this in as a value to Selmer which seems to be okay with unrealized lazyseq)

sova-soars-the-sora14:11:25

okay cool thank you just confirming šŸ˜„

emccue14:11:32

the other way to do it is

user=> (for [row data
             {:keys [q]} row]
          q)
(5 3 1 7 9 8 4 2 0 9)

emccue14:11:42

which is measurably less clever looking

sova-soars-the-sora14:11:53

yes quite šŸ«–

sova-soars-the-sora15:11:30

destructure by ... keys šŸ˜… that one makes me think

sova-soars-the-sora15:11:44

cool to see an alternative!

sova-soars-the-sora15:11:13

ah the for sets it as one coll/chunk/part of the vector at a time

sova-soars-the-sora15:11:59

thanks a ton šŸ˜„ calling vec on the lazySeq seems to have made it realize

Febin John James15:11:48

(set! (.. MainScene -prototype -create) (fn [] (this-as this (set! (.-player this) (.sprite (.. this -matter -add) 0 0 "player"))))) So this works, but for all the further prototype functions I need to add,"fn[]" "this-as this" and it's repetitive. Is there a way I can remove those two lines using a macro? Or would using macro for this be an overkill?

Ory Band17:11:08

Hi. I'm looking at all Clojure ecosystem HTTP client libraries. Which one would you recommend to use in terms of: ā€¢ Maintenance ā€¢ async.core support (CSP) ā€¢ Ease of adding APM / tracing support, for measuring cross-process latencies and such. From what I understood you get that "for free" using clj-http, I guess because it leverages Apache HttpClient and server? ā€¢ API "comfort" i.e. following conventions you like or consider "a good thing". I know this is subjective. Would like to hear opinions Some options: http-kit, clj-http, aleph, yada

Michael W17:11:17

I'm using clj-http-lite because I can use it the same from clojure, babashka, or graalvm native.

šŸ‘Œ 1
Ben Sless18:11:02

First, regarding support for core.async, you just need to deliver a promise channel in the callback and you're in CSP land, I wouldn't worry about it in particular ā€¢ httpkit: maintained, no external dependencies, convenient API ā€¢ clj-http: Big dependency, rich API ā€¢ aleph: not sure about its status, brings in large dependency and manifold's async model ā€¢ yada: don't know about it

emccue18:11:40

hato is a good one. Uses the standard java http client and no apache dependency

āž• 1
Ory Band19:11:00

added requirement: tracing support, for APM

Ben Sless19:11:14

What resolution of tracing

Ory Band19:11:25

id like to be able to easily instrument datadog apm tracing for http calls. see latency and such, also on jvm level

Ben Sless20:11:03

Metrics and instrumentation - on the JVM you just need to export JVM metrics

Ben Sless20:11:53

For latency, in asynchronous processes you either have support of whatever metrics library you're using, or you could go with a low-tech solution

(let [start (System/currentTimeNanos)] (some-async-fn params (fn callback [response] (let [diff (- (System/currentTimeNanos) start)] (report diff))))
using whatever reporting system you have already as part of your application

emccue20:11:49

yeah i donā€™t think that will do it^. Sidecar monitoring is a whole separate game

emccue20:11:11

@U011QKW5RGF What are you using right now?

Ory Band20:11:35

I'm using http-kit ad hoc, no APM instrumentation at all. From what I understood, an advantage for clj-http is that it leverages Apache HttpClient, which should have good APM support since it is good ol' java

Ory Band20:11:37

Practically speaking, I'm about to write an in-house http library for my company. It should have our own instrumentation and other in-company requirements. Reason for opening this discussion is that I'd like to start with some research and community recommendations.

Ben Sless20:11:41

The first question is what are you monitoring. "APM instrumentation" is wide net. What do you want to see, in what context?

Ory Band20:11:06

Edited more detail in that APM requirement: cross-process instrumentation

Ory Band20:11:02

Example scenarios: We have one app which makes http request i.e. it's a client. Another one is a server. I'd like to see spans joining these two "processes" over a single trace. See example screenshot. Primary use case is to identify performance bottlenecks between http client and server.

Ory Band20:11:41

Can't upload a screenshot, but see the ones in this link https://docs.datadoghq.com/tracing/visualization/#trace Notice it shows different colors for different processes (can be different apps too), and how much time it took for every process to run different functions.

Ory Band15:11:07

Reiterating over this. There's an advantage for http libraries which build upon standard java libs. clj-http uses Apache HttpClient, Aleph uses Netty. These stuff get automatic DataDog APM / tracing. This bums me out because I was leaning towards http-kit, mainly because it is maintained and has its custom Java implementation https://github.com/http-kit/http-kit/tree/master/src/java/org/httpkit/client But I think it's also going to make it hard to instrument its java agent for APM. Followup questions: ā€¢ I'm looking for documentation on why http-kit has its own custom java code instead of either going full clojure or building upon Java libs. Didn't find anything on google or the project GitHub page or its (unmaintained) website. ā€¢ Any idea on how i'm going to add APM instrumentation for http-kit? ā€¢ Regardless, any other opinions on which http client lib you like most?

Ory Band16:11:19

Maybe Aleph is more appropriate for me requirements? Considering it is based on Netty which means free Java APM instrumentation, considering it's a popular library

seancorfield18:11:31

@U011QKW5RGF We switched from http-kit to Hato at work -- we rely heavily on New Relic and it works great with Hato (but didn't work with http-kit).

seancorfield18:11:27

We previously used clj-http (which also worked great for New Relic) but dragged in dependencies we did not want. I blogged a bit about this at https://corfield.org and I'm happy to answer any follow-up questions.

seancorfield18:11:04

(Hato wraps the built-in JDK HttpClient)

Ory Band18:11:58

thanks Sean for the thorough answer, I'll check it out. is it maintained? last commit was 4mo ago, don't know what to make of it

seancorfield18:11:28

Hato? Yeah, it's "done" (i.e., complete) so I wouldn't expect much work needed on it.

seancorfield18:11:15

And four months is nothing in the Clojure world. Several popular libraries haven't had much in the way of updates for years because they're "done". They solve a single, simple problem and they do it well.

Ory Band21:11:46

Thanks Sean. Damn, it looks like JDK HttpClient is still not supported in DataDog https://github.com/DataDog/dd-trace-java/issues/1478 Did you have to do something special to integrate it with New Relic?

Ory Band21:11:20

Looks like New Relic added automated support on March 2021

seancorfield22:11:19

Hmm, I'm a bit surprised it was so recent with New Relic -- but we were mostly blocked by their lack of support for JDK 16 and 17 until recently so we'd held off a lot of refactoring (including the switch to Hato) until they were closer on that.

Ory Band09:12:20

Hi @seancorfield. I have a question about hato and java.net.HttpClient - i see there is no customizable connection pooling. The only way to set the connection pool is to do it "globally" via a jvm parameter. were you ok with that? and if so, why? can this be bypassed by using a different thread executor with multiple hato http-client objects? ā€¢ https://github.com/gnarroway/hato#other-advanced-options ā€¢ https://github.com/gnarroway/hato/issues/12

seancorfield18:12:57

@U011QKW5RGF We use a specific executor for our HTTP client calls (Clojure's own Agent executor) and we create a single client instance for each combination of connection timeout and follow redirects.

seancorfield18:12:27

(defn- build-client
  "Supports :timeout (treated as :connect-timeout).

  Uses :redirect-policy :normal by default.

  Uses the Clojure Agent executor."
  [opts]
  (http/build-http-client (assoc opts :executor clojure.lang.Agent/pooledExecutor)))

(def ^:private client-cache (atom {}))

(defn- ensure-client
  "Given a possible client, a connect timeout (or nil),
  and a redirect flag (boolean), return the client if
  passed in, else get a client that matches the policy
  being requested."
  [client connect-timeout follow-redirects]
  (if client
    client
    (let [cache-key [connect-timeout follow-redirects]]
      (if-let [client (get-in @client-cache cache-key)]
        client
        (get-in (swap! client-cache
                       (fn [cache]
                         ;; avoid race condition on creation:
                         (if (get-in cache cache-key)
                           cache
                           (assoc-in cache cache-key
                                     (build-client (cond-> {:redirect-policy
                                                           (if follow-redirects :normal :never)}
                                                    connect-timeout
                                                    (assoc :connect-timeout connect-timeout)))))))
                cache-key)))))

Ory Band18:12:44

thanks! . wait, are you sure that clojure agent pool executor actually creates different os connection pools using http clients?

seancorfield18:12:40

That's just to reduce thread usage to a "safe" level -- otherwise hato can overwhelm your process creating it's own threads for its default executor. The connection pool is per client instance as I recall? And we just rely on the default behavior (which works fine for us with the above setup).

Ory Band19:12:37

from what i saw the connection pool is global and static as a jvm parameter, so if i deduce correctly it's shared across all client instances. am i wrong? šŸ˜¬

seancorfield21:12:49

I don't remember. I'd have to go read the docs and the source. We do not specify any JVM parameters related to the HttpClient and we have some pretty heavy usage of it so I guess the defaults are good -- modulo my notes above about using a fixed pool executor and a handful of specific singleton client instances.

Ory Band21:12:44

alright. thanks for all the thorough information sean

seancorfield21:12:51

The default executor for Hato is not a good default, in my opinion (we tried it -- briefly! -- but had to switch to a fixed thread pool executor and decided to reuse Clojure's rather than risk adding a new pool and overwhelming our systems).

Ory Band21:12:19

sounds like a good idea

seancorfield21:12:20

Creating a new client for every connection is also not a good default approach. Again, we tried it and quickly decided it wouldn't work for us -- although I don't remember the specific details of that issue. I'd have to dig through our JIRA history for the ticket that switched to singleton client instances based on client options, as noted above.

Ory Band21:12:28

yeah I intend to use a single client as well so I wound reuse the same threads, I'm just worried I won't have os connection pool granularity for different use cases in the same application

Cesar Verdes22:11:52

Hello people. I'm totally new to Clojure, but I'm very excited about reading the book "The Joy of Clojure". In chapter 2 there is an example of how to define an anonymous function, but it's not working for me. Maybe someone can help me understand the error and its cause. The code is: (fnĀ [xĀ y] Ā Ā Ā (printlnĀ "MakingĀ aĀ set") Ā Ā Ā #{xĀ y}) ;;=>Ā #<user$eval1027$fn__1028Ā user$eval1027$fn__1028@e324105> is the expected value but i receive this error message after past the code into REPL: Syntax error reading source at (REPL:3:10). Map literal must contain an even number of forms Any guide will be appreciated :face_with_rolling_eyes:

dpsutton23:11:28

iā€™m trying to replicate but iā€™m not seeing your error

cd /tmp
dan@mbp-m1 /tmp % clj
Clojure 1.10.3
user=> (fn [x y]
   (println "Making a set")
   #{x y})
#object[user$eval136$fn__137 0x648ee871 "user$eval136$fn__137@648ee871"]
user=>

dpsutton23:11:38

can you paste in here exactly what you are typing in?

dpsutton23:11:18

or a screenshot of your repl?

Cesar Verdes23:11:41

Sorry, the HTML version of the book has a button to copy the code, and surely the copied text has some non-valid character. If I paste the code copied from the book's web page I receive the error, but if I type it, the result is correct. What a shame! Excuse me. I will not re-copy the code with the copy button that appears in the HTML version of the book. :man-facepalming: I attaching the screenshots. Thank you very much for your interest in helping me and again I sincerely apologize. šŸ™

dpsutton23:11:04

my pleasure!

Skiamakhos00:11:54

In the REPL, how do you split the line like that? I type (fn [x y]) ...and with the point before the trailing paren, put in by Paredit in my emacs clojure REPL, I want to be able to indicate that it's to continue onto the next line but hitting return submits it to be evaluated. C-RTN doesn't work.

Skiamakhos01:11:13

Got it - C-j,

Ory Band15:11:07

Reiterating over this. There's an advantage for http libraries which build upon standard java libs. clj-http uses Apache HttpClient, Aleph uses Netty. These stuff get automatic DataDog APM / tracing. This bums me out because I was leaning towards http-kit, mainly because it is maintained and has its custom Java implementation https://github.com/http-kit/http-kit/tree/master/src/java/org/httpkit/client But I think it's also going to make it hard to instrument its java agent for APM. Followup questions: ā€¢ I'm looking for documentation on why http-kit has its own custom java code instead of either going full clojure or building upon Java libs. Didn't find anything on google or the project GitHub page or its (unmaintained) website. ā€¢ Any idea on how i'm going to add APM instrumentation for http-kit? ā€¢ Regardless, any other opinions on which http client lib you like most?