This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-05-18
Channels
- # announcements (2)
- # babashka (35)
- # beginners (59)
- # calva (17)
- # cider (3)
- # clerk (7)
- # clj-kondo (21)
- # cljfx (9)
- # cljs-dev (76)
- # clojure (98)
- # clojure-austin (3)
- # clojure-brasil (1)
- # clojure-europe (11)
- # clojure-gamedev (4)
- # clojurescript (14)
- # consulting (7)
- # cursive (6)
- # datascript (4)
- # datomic (12)
- # emacs (18)
- # events (2)
- # graalvm (9)
- # humbleui (3)
- # hyperfiddle (18)
- # jobs (4)
- # missionary (12)
- # nextjournal (2)
- # nrepl (7)
- # off-topic (31)
- # practicalli (2)
- # rdf (6)
- # releases (2)
- # scittle (10)
- # xtdb (9)
Hi Clojurians, I have below snippet, I am trying to get rid of Concurrency but every time I get rid of this thread pool executor it's resulting in some exception, how can I optimize this code and get rid of thread-pool, please suggest some options.
(defn get-all-offers-attached [context filtered-company-data offers-study-data
actual-discount-map]
(let [split-list (reduce #(let [client-study-id (or (-> (get actual-discount-map
[(:dbid %2) (:sid %2)])
:client_study_id)
"NA")]
(if (contains? offers-study-data [(:dbid %2) (:sid %2)])
(assoc %1 :with-offers
(conj (:with-offers %1)
(let [chan (async/chan 1)
data (assoc %2 :clientStudyId client-study-id)
log-context (or (clog/get-context) {})
data-processor
(fn []
(wrap-with-logging-context
log-context
(let [status (try (get-status-message-match context (:id data)
(:dbid data) (:sid data))
(catch Exception e
(log/error (Throwable->map e))
"ERROR"))]
(assoc data :discountvsoffers status))))]
(.execute @thread-pool-executor
(fn []
(try
(async/put! chan (data-processor))
(finally
(async/close! chan)))))
chan)))
(assoc %1 :without-offers (conj (:without-offers %1) (assoc %2 :discountvsoffers "NA" :clientStudyId client-study-id)))))
{:without-offers [] :with-offers []} filtered-company-data)]
(concat (:without-offers split-list)
(->> (:with-offers split-list)
(async/merge)
(async/reduce conj [])
(async/<!!)))))
To answer specifically, about getting rid of the thread pool:
What is get-status-message-match
doing underneath? If it is an http call for example, you could use non-blocking http client. If you use a non-blocking http client, then you add a core-async wrapper around it, and get rid of the thread-pool.
But more generally:
But I am not 100% sure I understand what your goal is. Why do you want to get of of the concurrency, and what exception are you getting?
there are limited number of threads available, during performance tests we realized if every user hop on to this page the server may run out of threads.
the get-status-message-match
function is doing lot of computations underneath (calling multiple api, db calls etc.)
I am not able to figure out what data structure are best suited for these type of cases.
Where is thread-pool-executor
defined? You could use a FixedThreadPool and shared it across requests. This way, you know you won't create more than the N threads you choose. For a clojure-friendly interface to threadpools, you may like https://github.com/clj-commons/claypoole
---
> I am not able to figure out what data structure are best suited for these type of cases.
Afaik you have two options. You can try to make get-status-message-match
use non-blocking io, and get rid of the thread pool. You can use a non-blocking http client for the api calls. For db calls, you would need a thread-pool though.
You could also do what I suggested above -- just make sure that whatever threadpool you use is constrained.
thanks much for your response - here is the threadpool -
(defonce thread-pool-executor
(delay
(Executors/newFixedThreadPool config/offer-tracking-threads-max-count
(counted-thread-factory "status-thread-%d" false))))
In this case, since the thread-pool is fixed and is defined outside of the request, I don't think the server could run out of threads. What error were you getting?
I am getting error when I am trying to get rid of this threading stuff completely, removing .execute / channel etc. I wanted to convert it into plain code first and see if any optimization is possible with data structures
What does your code look like without the execute / channel, and what error do you see? It should look something like:
(defn get-all-offers-attached [context filtered-company-data offers-study-data
actual-discount-map]
(let [split-list (reduce #(let [client-study-id (or (-> (get actual-discount-map
[(:dbid %2) (:sid %2)])
:client_study_id)
"NA")]
(if (contains? offers-study-data [(:dbid %2) (:sid %2)])
(assoc %1 :with-offers
(conj (:with-offers %1)
(let [data (assoc %2 :clientStudyId client-study-id)
log-context (or (clog/get-context) {})]
(wrap-with-logging-context
log-context
(let [status (try (get-status-message-match context (:id data)
(:dbid data) (:sid data))
(catch Exception e
(log/error (Throwable->map e))
"ERROR"))]
(assoc data :discountvsoffers status))))))
(assoc %1 :without-offers (conj (:without-offers %1) (assoc %2 :discountvsoffers "NA" :clientStudyId client-study-id)))))
{:without-offers [] :with-offers []} filtered-company-data)]
(concat (:without-offers split-list) (->> (:with-offers split-list)))))
Fwiw though, I doubt you would see optimization wins with data structures here, as likely the get-status-message-match
is io-bound.FYI, cross-posting across #C053AK3F9 and #C03S1KBA2 (also #C03S1L9DN) is strongly frowned upon. Best move is probably to just stick with posting in #C053AK3F9 until it doesn't feel right anymore, and then move to #C03S1KBA2 and/or #C03S1L9DN. Personally, I feel somewhere in between. So I post mostly to #C053AK3F9 with questions that feel like beginner naiveté, and sometimes the others with questions that don't seem very beginnner-friendly.
what is the best resource to learn datalog. I am pretty good with SQL and struggling to get basic stuff in datalog
https://max-datom.com/ https://nextjournal.com/try/learn-xtdb-datalog-today/learn-xtdb-datalog-today is quite nice too
If you like videos then this is a good one https://www.youtube.com/watch?v=oo-7mN9WXTw there used to be a site called datascript 101 but it seems to have vanished 😕
The https://cljdoc.org/d/datascript/datascript/0.17.1/doc/readme have a link to DataScript 101, but I don't suggest following the link. It was blocked by UBlock Origin, so I tested it in a Private tab, and it redirects to a spammy sales page.
I'm a little late here but one thing that I skipped reading docs (switching between lot of materials) is thehttps://docs.datomic.com/pro/overview/introduction.html#datomic-does-this-by. At least for me was a game changing to understand the basics and start understanding by myself the https://docs.datomic.com/pro/query/query.html.
Hello would anyone be able to give me a rundown of how "clj -m" command's logic differs from Repl logic? I have a curious situation where the following code:
(defn -main [& args]
(let [[flag & remaining-args] args]
(condp = flag
"-generate" (generate)
"-webserver" (start-webserver)
(println "Invalid flag. Supported flags are -generate and -webserver."))))
Works fine in Repl, when you call -main within repl it works, only executing the condition that matches the input. But when ran through command line with clj -m <ns> "-generate"
for example all options are executed. in this case generate and start-webserver both run every time when called from command line.the code in the example given was not the reason for the fault. The reason was a malformed defonce in the dependencies that started the webserver everytime when the dependency was loaded:
(defonce server
(jetty/run-jetty #'app {:port 8000 :join? false}))
(comment (.start server))
(comment (.stop server))
This code launched the webserver always when called from clj, but never when called from REPL.
To go around the issue the modified code looks like this:
(defonce server (atom nil))
(defn start-webserver []
(when (nil? @server)
(reset! server (jetty/run-jetty #'app {:port 8000 :join? false}))
(println "Web server started.")))
(defn stop-webserver []
(when-not (nil? @server)
(.stop @server)
(reset! server nil)
(println "Web server stopped.")))
(comment (start-webserver))
(comment (stop-webserver))
This seems to work but it's my first time of using atoms and reset! and i'm not sure if it is right or not. Given my intro into clojure it was said to me that it's pretty immutable and now I have introduced something that does mutate overtime.
If you have opinions about "is this correct way to use atoms or not" i would gladly hear them. Just so I won't take bad habbits further than this.Hi, does anybody know how to build something similar to the graph editor that after effects has ? https://www.youtube.com/watch?v=7pOCtlrrE3Y
It's certeinly possible with Clojure2d or Quil. But what do you want to achieve precisely as the result? Path points?
yes i need the path points, at least a certain intervals, in order to calculate the area under sections of the curve
So there are two steps for that, one is a visual tool (Clojure2d or Quil can be useful here) to create the gui (adding/removing/moving points around), the second is to build interpolation between points. You can use fastmath.interpolation
namespace for example to build a function which can be easily integrated.
Thanksss !!!
For a full-blown graph-based visual approach to Clojure computation, you may be interested in: https://www.datarabbit.com/
I have a question about configuring clj kondo for Hiccup. The defelem
macro (used by helpers in the hiccup.form
ns, for example) massages the arglists to include an arity that takes a map of attributes as the first argument. When I try using this arity, clj kondo complains about wrong number of arguments.
I couldn't find a way to teach clj kondo about the new arity. Is there a way to do it?
What I ended up trying was to have clj kondo ignore arity checks on those functions (e.g. form-to
). I followed the https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#invalid-arity, but it didn't seem to make a difference. Inline ignore with a #_
worked, but I'd prefer not to litter those all over the code, though.
I wonder if maybe the linter configuration didn't work because, unlike the example, the function I'm ignoring is generated as a result of macro expansion rather than being a macro (or function) itself? Or maybe I'm just missing something very obvious...
@U04RG9F8UJZ Hi. Can you make a repro (a single file with all I need to know to lint and see the problem?)
Thanks @U04V15CAJ You'll need a project with hiccup as a dependency, and then you can reproduce the linting error as shown here: https://gist.github.com/jbullers/4db8ce3f4ff84ad47c43c6267f7a5c01 Let me know if I should provide something more
@U04RG9F8UJZ Can you also provide the deps.edn with the exact version of hiccup you were using?
@U04V15CAJ I added a deps.edn to the gist. I was also getting all of those functions highlighted (unknown var), but after restarting vs code it worked itself out and I'm left with the arity error described earlier
I recommend going with this config:
{:lint-as
;; This helped remove other linting errors when I used the defelem and defhtml macros
{hiccup.def/defelem clj-kondo.lint-as/def-catch-all
hiccup.def/defhtml clj-kondo.lint-as/def-catch-all}}
Wow 😮 why does that fix it?
Oh, hmm. It seems like it's basically an ignore. If I add more args, it doesn't flag that as wrong
if you want more sophisticated linting, I recommend writing a hook, I think a macroexpand hook will be the easiest: https://github.com/clj-kondo/clj-kondo/blob/master/doc/hooks.md#macroexpand
(defn dissoc-remaining-data-from-input [input]
(let [all-keys (keys input)
keys-to-remove (filter (complement (keys-to-keep) all-keys))]
(dissoc input (object-array keys-to-remove))))
welcome...
a) please use a thread
b) you can reduce or apply with dissoc to supply a list of keys (otherwise dissoc tries to remove the entry with that list as the key)
c) you could also use select-keys
(reduce dissoc {:a 1 :b 2 :c 3} [:a :c])
=> {:b 2}
(apply dissoc {:a 1 :b 2 :c 3} [:a :c])
=> {:b 2}
(select-keys {:a 1 :b 2 :c 3} [:a :b])
=> {:a 1, :b 2}
OMG! So many single-line posts here. I didn't even see the thread already started, and tried to thread off another one.
---
dissoc
takes multiple keys as inputs, not a collection of keys. So, you need to use apply
to spread the collection into the arguments list.
FYI ,`(remove f coll)` is the same as (filter (complement f) coll)
.
(def keepers #{:def :ghi})
(def foos {:abc 1
:def 2
:ghi 3
:jkl 4})
(defn keep-keys [ks m]
(apply dissoc m (remove ks (keys m))))
(keep-keys keepers foos)
; =>
{:def 2, :ghi 3}