clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
Oliver George 2021-05-27T00:29:01.475800Z

Hello all. I created a #show-and-tell channel today. #announcements channel is lovely for libs but I want to be inspired by the systems and products people are building. What are you building with clojure today?Β Β Show a screenshot and tell us about it. Few fun screenshots at #show-and-tell already.

seancorfield 2021-05-27T00:52:07.476200Z

I found the Figwheel docs and re-frame docs pretty good. But I'm only starting to learn cljs. I've been doing backend Clojure for a decade.

Joel 2021-05-27T04:22:11.480300Z

how can i use the threaded form but avoid particular parts of the thread based on the current threaded value, I'm aware of cond-> but that doesn't test on current value, eg:

(-> data 
    (fn1) 
    (fn2) 
    (thread-if #(= (:needs-doing %)) (needs-doing)) 
    (fn5)

2021-05-27T13:18:15.486500Z

You could make a function for this pretty easily.

(defn when-pred
  [val pred then]
  (if (pred val)
    (then val)
    val))

(defmacro if->
  [val sym test clause]
  `(when-pred ~val (fn [~sym] ~test) (fn [~sym] ~clause)))

(-> data
    fn1
    fn2
    (when-pred :needs-doing needs-doing)
    fn4)

(-> data
    fn1
    fn2
    (if-> val (= (:some-key val) :some-thing) (update val :some-key some-update))
    fn4)

alexmiller 2021-05-27T04:55:03.481200Z

cond->

alexmiller 2021-05-27T04:55:39.481800Z

Or lift the if into a fn above

kirill.salykin 2021-05-27T08:44:28.483100Z

hi please advice is there a smart trick to know if it is a last iteration inside the run! (the consumed sequence is lazy and it is important to keep it lazy)

borkdude 2021-05-27T08:45:03.483600Z

there is no way to know if you're at the last element without looking ahead one element

kirill.salykin 2021-05-27T08:45:31.483900Z

is there a run! which accepts two elements? πŸ™‚

borkdude 2021-05-27T08:45:54.484100Z

I would just implement this using loop probably

kirill.salykin 2021-05-27T08:46:07.484300Z

makes sense!

kirill.salykin 2021-05-27T08:46:07.484500Z

thanks

borkdude 2021-05-27T08:59:34.485500Z

almost. the nil? check would not be enough if the seq also can contain nils, so I would use:

(loop [xs (seq xs0)]
  (let [next-xs (next xs)
         last? (not next-xs)]
   (recur next-xs)

Ed 2021-05-27T09:08:13.486Z

You could also do it with a transducer/eduction

(run! identity (eduction (fn [rf] (fn ([] (rf)) ([r] (prn 'done r) (rf r)) ([r i] (rf r i)))) (range 5)))
but I guess it kinda depends on why you need to know it's the last element

kirill.salykin 2021-05-27T09:09:14.486200Z

it is interesting idea with a transducer thanks!

2021-05-27T13:18:15.486500Z

You could make a function for this pretty easily.

(defn when-pred
  [val pred then]
  (if (pred val)
    (then val)
    val))

(defmacro if->
  [val sym test clause]
  `(when-pred ~val (fn [~sym] ~test) (fn [~sym] ~clause)))

(-> data
    fn1
    fn2
    (when-pred :needs-doing needs-doing)
    fn4)

(-> data
    fn1
    fn2
    (if-> val (= (:some-key val) :some-thing) (update val :some-key some-update))
    fn4)

dpsutton 2021-05-27T13:22:23.487500Z

Could you run! Over but-last and special case the last one?

kirill.salykin 2021-05-27T13:23:37.487700Z

seems like custom loop as simplier solution

kirill.salykin 2021-05-27T13:23:40.487900Z

thanks for the input

Ed 2021-05-27T13:52:27.488100Z

you could also pair each element with the next one and look for where the paired elements run out:

(let [data (range 5)]
    (run! (fn [[a b]] (if (= a ::last) (do (prn b) b) b)) (map vector (concat (drop 1 data) [::last]) data)))
maybe?

kirill.salykin 2021-05-27T13:53:17.488300Z

thanks

sweb 2021-05-27T14:35:34.489700Z

I just got this. Who do I need to poke (if anyone)?: > WARNING: Illegal reflective access by clojure.lang.InjectedInvoker/0x0000000800232040 (file:/C:/Users/x/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar) to method sun.security.x509.X509CertImpl.getSubjectDN() > WARNING: Please consider reporting this to the maintainers of clojure.lang.InjectedInvoker/0x0000000800232040 > WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations > WARNING: All illegal access operations will be denied in a future release

Endre Bakken Stovner 2021-05-27T14:37:29.491700Z

What would be the best way to run command-line tools from Clojure? I do not just want to dispatch jobs, but also be notified when they are finished and learn the exit-code, std(out/err), and so on.

ghadi 2021-05-27T14:37:32.491800Z

can you provide more context around the code that did that?

ghadi 2021-05-27T14:38:03.492Z

--illegal-access=debug @sweb add ^ to your JVM to get some better stacktrace

emilaasa 2021-05-27T14:41:35.494500Z

https://clojuredocs.org/clojure.java.shell/sh perhaps does what you need?

alexmiller 2021-05-27T14:45:34.498Z

https://clojure.org/guides/faq#illegal_access

Ivar Refsdal 2021-05-27T14:47:17.499200Z

I like babashka/process https://github.com/babashka/process as the name implies, it's included in babashka

Endre Bakken Stovner 2021-05-27T14:47:17.499400Z

I am building a (Snake)make-like workflow management system where users provide the rules in text files to be parsed by my program to create a DAG for execution (phew!). The rules look like this (there would obviously be many more rules in a file):

(defrule samtools-sort
  "Sort the bams."
  {:wildcards [:sample :genome]
   :input     "bwa-map.bam"
   :output    ["bam/sorted.bam"]
   :shell     "samtools sort -T {{wildcards.sample}} -O bam {{input.0}} > {{output.0}}"}) 
It would be cool if I could include a :clojure-directive as an alternative to the :shell directive in case users wanted to do their data processing in Clojure rather than in shell, like:
:clojure (-> infile slurp process-data write-result-to-file)
This in itself would not be hard. But it would be cool if it were possible to let users include/require external libraries in the code too. I do not see any easy way to do this as the workflow files are fed to a precompiled program. Any suggestions/ideas?

Endre Bakken Stovner 2021-05-27T14:48:33.499600Z

Thanks. I'll look at both of them!

sweb 2021-05-27T14:49:29.499800Z

The actual code creating the issue is this: (->> cert (.getSubjectDN) (.getName) (drop 3) (apply str))] cert is an X509CertImpl pulled from an sslContext Solution is to use a different method but it asked to warn someone..so here I am.

sweb 2021-05-27T14:50:18Z

So, I have fixed the issue in my code to not use a deprecated function.

alexmiller 2021-05-27T14:51:23.000200Z

unfortunately, because this is in code generated by the compiler on your code's behalf, it will always get reported as if it is Clojure ;)

isak 2021-05-27T14:52:22.000600Z

Call a build tool from your program

sweb 2021-05-27T14:52:41.000700Z

Okies. Thanks

alexmiller 2021-05-27T14:53:28.000900Z

the issue is not actually one of deprecation, but rather calling into a function that you cannot access due to module visibility.

Endre Bakken Stovner 2021-05-27T14:55:25.001100Z

I guess. This would require me to learn lots more about tooling. Up to this day I've just cargo-culted and used luminus-recipes XD

1
Endre Bakken Stovner 2021-05-27T14:55:33.001300Z

Thanks, btw.

Endre Bakken Stovner 2021-05-27T14:57:08.001500Z

For now clojure.ava.shell.sh is enough. It is synchronous though. But I am sure I can just use Thread to make it non-synchronous.

sweb 2021-05-27T14:58:11.001700Z

And it's true that switching from getSubjectDN to getSubjectX500Principal still gives an error

alexmiller 2021-05-27T15:01:39.002Z

this being one of the internal sun jdk methods, you're not supposed to use this class directly

ghadi 2021-05-27T15:02:25.002200Z

can you post the full stacktrace from --illegal-access=debug?

ghadi 2021-05-27T15:02:42.002400Z

I'd like to know if it's the Reflector at fault or something else

sweb 2021-05-27T15:03:04.002600Z

I'll have a look

alexmiller 2021-05-27T15:03:10.002800Z

yeah, would be curious to see the code

alexmiller 2021-05-27T15:03:37.003Z

probably should be using java.security.cert.X509Certificate ?

sweb 2021-05-27T15:08:56.003300Z

ok here is what I got for you: > WARNING: Illegal reflective access by clojure.lang.InjectedInvoker/0x0000000800232040 (file:/C:/Users/sweb/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar) to method sun.security.x509.X509CertImpl.getSubjectX500Principal() > at clojure.lang.Reflector.canAccess(Reflector.java:49) > at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:156) > at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:438) > at url_check.core$wildcard_QMARK_.invokeStatic(core.clj:70) > at url_check.core$wildcard_QMARK_.invoke(core.clj:67) > at url_check.core$eval8394.invokeStatic(form-init16933106916591026780.clj:205) > at url_check.core$eval8394.invoke(form-init16933106916591026780.clj:205) > at clojure.lang.Compiler.eval(Compiler.java:7177) > at clojure.lang.Compiler.eval(Compiler.java:7132) > at clojure.core$eval.invokeStatic(core.clj:3214) > at clojure.core$eval.invoke(core.clj:3210) > at clojure.main$repl$read_eval_print__9086$fn__9089.invoke(main.clj:437) > at clojure.main$repl$read_eval_print__9086.invoke(main.clj:437) > at clojure.main$repl$fn__9095.invoke(main.clj:458) > at clojure.main$repl.invokeStatic(main.clj:458) > at clojure.main$repl.doInvoke(main.clj:368) > at clojure.lang.RestFn.invoke(RestFn.java:1523) > at nrepl.middleware.interruptible_eval$evaluate.invokeStatic(interruptible_eval.clj:79) > at nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:55) > at nrepl.middleware.interruptible_eval$interruptible_eval$fn__3452$fn__3456.invoke(interruptible_eval.clj:142) > at clojure.lang.AFn.run(AFn.java:22) > at nrepl.middleware.session$session_exec$main_loop__3553$fn__3557.invoke(session.clj:171) > at nrepl.middleware.session$session_exec$main_loop__3553.invoke(session.clj:170) > at clojure.lang.AFn.run(AFn.java:22) > at java.base/java.lang.Thread.run(Thread.java:834) > WARNING: Illegal reflective access by clojure.lang.Reflector (file:/C:/Users/sweb/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar) to method sun.security.x509.X509CertImpl.getSubjectX500Principal() > at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:167) > at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:438) > at url_check.core$wildcard_QMARK_.invokeStatic(core.clj:70) > at url_check.core$wildcard_QMARK_.invoke(core.clj:67) > at url_check.core$eval8394.invokeStatic(form-init16933106916591026780.clj:205) > at url_check.core$eval8394.invoke(form-init16933106916591026780.clj:205) > at clojure.lang.Compiler.eval(Compiler.java:7177) > at clojure.lang.Compiler.eval(Compiler.java:7132) > at clojure.core$eval.invokeStatic(core.clj:3214) > at clojure.core$eval.invoke(core.clj:3210) > at clojure.main$repl$read_eval_print__9086$fn__9089.invoke(main.clj:437) > at clojure.main$repl$read_eval_print__9086.invoke(main.clj:437) > at clojure.main$repl$fn__9095.invoke(main.clj:458) > at clojure.main$repl.invokeStatic(main.clj:458) > at clojure.main$repl.doInvoke(main.clj:368) > at clojure.lang.RestFn.invoke(RestFn.java:1523) > at nrepl.middleware.interruptible_eval$evaluate.invokeStatic(interruptible_eval.clj:79) > at nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:55) > at nrepl.middleware.interruptible_eval$interruptible_eval$fn__3452$fn__3456.invoke(interruptible_eval.clj:142) > at clojure.lang.AFn.run(AFn.java:22) > at nrepl.middleware.session$session_exec$main_loop__3553$fn__3557.invoke(session.clj:171) > at nrepl.middleware.session$session_exec$main_loop__3553.invoke(session.clj:170) > at clojure.lang.AFn.run(AFn.java:22) > at java.base/java.lang.Thread.run(Thread.java:834)

alexmiller 2021-05-27T15:14:34.004400Z

line #s don't seem right there though

sweb 2021-05-27T15:15:10.004600Z

indeed I am doing something along the same lines. I hadn't seen this repo before though

alexmiller 2021-05-27T15:16:47.004800Z

or maybe that's your code? I'm just guessing from the ns

sweb 2021-05-27T15:17:14.005Z

ha, no it's not although we have the same ns.

alexmiller 2021-05-27T15:17:47.005200Z

ok, well what's your code at line 70?

sweb 2021-05-27T15:18:07.005400Z

he seems to be checking for a well formed response from a server. I am checking cookie compliance, form usage, cert validity (where I am running into the interop issues) etc

sweb 2021-05-27T15:19:08.005700Z

(let [n (->> cert (.getSubjectX500Principal) (.getName) (drop 3) (apply str))]

Eugen 2021-05-27T15:22:40.007400Z

any hints on how to debug a memory leak / performance leak in a clojure app on production ? The normal way to look on gc generation does not really help because clojure does not have classes.

Endre Bakken Stovner 2021-05-27T15:25:23.007500Z

It seems like this will be really easy with the clj command-line tool :thumbsup:

Ed 2021-05-27T15:25:58.008200Z

how are you starting the java process? if you want to download code from the internet and add it to your classpath, you may want to look at something like the add-lib branch of the clj tool (which is currently work in progress)

Endre Bakken Stovner 2021-05-27T15:27:18.008400Z

My Clojure program will be a jar πŸ™‚

Endre Bakken Stovner 2021-05-27T15:27:19.008600Z

https://insideclojure.org/2018/05/04/add-lib/

Endre Bakken Stovner 2021-05-27T15:27:40.008900Z

Cool! Will keep my eyes open for updates on the tool 😎

Ed 2021-05-27T15:27:45.009100Z

yeah ... that's the bunny πŸ˜‰

Ed 2021-05-27T15:31:51.011900Z

I've used this a little in the past too: https://github.com/pallet/alembic

1πŸ™
borkdude 2021-05-27T15:33:06.013100Z

Clojure does produce classes

Ivar Refsdal 2021-05-27T15:33:12.013300Z

for what it's worth: nREPL 0.7 got sideloader: #97: Added a sideloader, a network classloader that allows dependencies to be added even when the source/class files are not available on the server JVM's classpath (e.g. supplied by the client). https://github.com/nrepl/nrepl/releases (I haven't tried this feature myself)

Endre Bakken Stovner 2021-05-27T15:33:27.013700Z

I am following the https://clojure.org/guides/deps_and_cli#_using_a_main but I cannot find out how to run the example program from a different folder:

clj -X hello/run 
Like, my code resides at ~/code/hello/, but I want to run it from ~/whatevz/some/bogus/folder. Is there a way? I know I could just use pushd ~/code/hello; clj -X hello/run; popd, but I was hoping there existed a way that did not involve jumping between paths.

borkdude 2021-05-27T15:33:38.013800Z

Perhaps with VisualVM: https://docs.oracle.com/javase/8/docs/technotes/guides/visualvm/heapdump.html

3πŸ™3😎
sweb 2021-05-27T15:34:02.014Z

as per your faq, changing it to: > (let [n (->> ^java.security.cert.X509Certificate cert > (.getSubjectX500Principal) > (.getName) > (drop 3) > (apply str))] worked without error.

Endre Bakken Stovner 2021-05-27T15:34:02.014200Z

Cool to know about πŸ™‚

Eugen 2021-05-27T15:35:51.014900Z

bash-5.0# jcmd 1 GC.class_histogram -all > GC.class_histogram.csv bash-5.0# head GC.class_histogram.csv 1: num #instances #bytes class name (module) ------------------------------------------------------- 1: 96854702 3099350464 clojure.lang.LazySeq 2: 64655045 2068961440 clojure.lang.Cons 3: 5122755 394906984 [Ljava.lang.Object; (java.base@11.0.10) 4: 3382334 157481032 [B (java.base@11.0.10) 5: 3323357 79760568 java.lang.String (java.base@11.0.10) 6: 1509001 60360040 clojure.lang.PersistentVector 7: 2059526 49428624 clojure.lang.PersistentVector$Node

borkdude 2021-05-27T15:37:11.015200Z

hmm, this seems to indicate holding onto the head of lazy sequences

1☝️
Eugen 2021-05-27T15:38:10.016Z

yes, and because clojure lacks types it's hard to know where this is comming from

Eugen 2021-05-27T15:38:46.017Z

in Java, with types you would see the name of the class somewhere there

alexmiller 2021-05-27T15:38:56.017600Z

no, not with using clj -X

2πŸ™
borkdude 2021-05-27T15:40:19.018600Z

@eugen.stan did you try to force a GC before taking this data?

Eugen 2021-05-27T15:42:30.018900Z

no

Endre Bakken Stovner 2021-05-27T15:43:24.019100Z

I see there is a -Jopt. Will read up on the possible flags I can send there.

Ed 2021-05-27T15:43:29.019300Z

if you take a thread dump can you see something in the list of things that the process is doing that's a common code path that looks like it might be holding onto the head of something large?

Eugen 2021-05-27T15:44:20.019500Z

I don't have one now

Eugen 2021-05-27T15:44:23.019700Z

thanks

Eugen 2021-05-27T15:45:19.019900Z

it's a bit difficult since it's hard to reproduce the performance issue that triggers the issue and the app runs remotely inside docker

Ed 2021-05-27T15:46:25.020100Z

what kind of things is it connected to? if it's selecting large amounts of data from a db, and trying to serve that up over http it might be calling doall on something before trying to convert it to an http response?

Ivar Refsdal 2021-05-27T15:51:55.020300Z

Can you dump the heap on out of memory exception and have it written to a mounted docker volume to be inspected later? https://www.baeldung.com/java-heap-dump-capture#automatically

isak 2021-05-27T15:54:27.020600Z

Yea exactly, I was gonna say may not be as hard as you think

Eugen 2021-05-27T15:56:37.020800Z

thanks - the app does not throw memory exception - it starts lots of threads and it slows down to a halt

Eugen 2021-05-27T15:57:02.021Z

at the same time memory consumption is very high and these are related

Eugen 2021-05-27T15:57:14.021200Z

but because there is no OOM it might not be a leak ?!

Ivar Refsdal 2021-05-27T15:57:34.021400Z

are you catching and logging/printing uncaught thread exceptions?

Ed 2021-05-27T15:57:40.021600Z

if there's a leak, you'll eventually get an OomException

Ed 2021-05-27T15:58:26.021800Z

which gc algorithm are you using?

Ed 2021-05-27T15:59:37.022Z

have you tried the old strategy of doubling the heap size and seeing what happens over longer periods of time?

borkdude 2021-05-27T15:59:47.022200Z

@eugen.stan > it starts lots of threads can you see what the app is doing in those threads?

Eugen 2021-05-27T16:01:23.022400Z

@l0st3d default with java 11 - G1

Eugen 2021-05-27T16:01:42.022600Z

@borkdude: I am working on that

Eugen 2021-05-27T16:03:10.022800Z

@ivar.refsdal: not sure how to reply

Ed 2021-05-27T16:04:24.023Z

I think @ivar.refsdal meant are you doing this: https://stuartsierra.com/2015/05/27/clojure-uncaught-exceptions ?

Eugen 2021-05-27T16:06:11.023300Z

thanks @l0st3d, will check

Eugen 2021-05-27T16:06:50.023500Z

thanks for the feedback so far, I'll see what I can do further

Ed 2021-05-27T16:06:52.023700Z

if you've got multiple docker processes to play with, you could always have one start up with the serial collector, which is a bit easier to follow what's getting cleaned up, because it just stops the world rather than trying to let all the threads progress ... (just as an idea of trying to work out what's going on πŸ˜‰ )

Ivar Refsdal 2021-05-27T16:07:56.023900Z

Yes that's what I was suggesting

Eugen 2021-05-27T16:08:36.024100Z

the performance issue is difficult to trigger, the app uses ~ 12 - 23 GB of ram and needs a cache, db and queue - these make things difficult to debug

alexmiller 2021-05-27T16:15:07.024300Z

that just lets you use any jvm option

ghadi 2021-05-27T16:24:55.024600Z

class histo indicates a 96 million entry seq -- at least

ghadi 2021-05-27T16:26:44.026700Z

you could take a memory dump and examine any instance of the LazySeq, check its .s field

Eugen 2021-05-27T16:27:02.027300Z

I will do that, thanks

ghadi 2021-05-27T16:27:55.028400Z

your step 1 class_histo was the absolute correct thing to do

Charlie Briggs 2021-05-27T16:28:11.028800Z

Any advice on propagating errors when you have multiple long-running threads in a clojure service on the jvm? i.e. my-process returns [input-ch done-ch] and starts some background some work somehow -`ExecutorService`, async/thread, future, etc. The problem is all these wrappers to background work end up with uncaught exceptions not being handled (i.e. by top-level Thread$UncaughtExceptionHandler unless a specific uncaught exception handler is added to the thread, and this then needs to exit the process. It seems possible to return a future and deref futures from all these processes, but this doesn’t seem to be the way, as the deref order on the main thread then matters or you end up with the same problem :thinking_face: I’ve read this from a few years ago, but I’m not sure what the best approach is https://stuartsierra.com/2015/05/27/clojure-uncaught-exceptions

Eugen 2021-05-27T16:30:07.029200Z

thank you, I found a very good presentation on the subject: https://www.youtube.com/watch?v=_gineh_HcoQ (shorter version available online someplace)

ghadi 2021-05-27T16:33:36.029900Z

wow 3hrs πŸ™‚

ghadi 2021-05-27T16:38:02.030200Z

jcmd <pid> GC.heap_dump file_destination

Eugen 2021-05-27T16:38:44.030400Z

thanks, I am putting some load on the system now (trying, I can't seem to be able πŸ˜„ ) .

rmcv 2021-05-27T16:45:14.033300Z

https://github.com/clojure-goes-fast/clj-async-profiler. I found the flame graph quite useful in analysing both space and time issues.

Eugen 2021-05-27T16:46:18.033600Z

this looks interesting, thanks rmcv

ghadi 2021-05-27T17:00:18.033800Z

@eugen.stan if you can download the heapdump, you can offline analyze it with https://visualvm.github.io/download.html

ghadi 2021-05-27T17:00:47.034Z

I just re-tested it out and it was easy to tell what's in the LazySeq

Eugen 2021-05-27T17:01:10.034200Z

thanks. Will try it out. I don't lknow how useful it will be for me now since I can't seem to reproduce the issue

Eugen 2021-05-27T17:01:21.034400Z

I think it's affraid πŸ™‚

ghadi 2021-05-27T17:09:28.034600Z

you definitely have a thing hanging onto a LazySeq -- it's absolutely clear

Eugen 2021-05-27T17:10:03.034800Z

seems I can't create a heap dump - size is 0. tried with both jcmd and jmap - files have size 0

phronmophobic 2021-05-27T17:18:41.035100Z

Most (all?) of the ExecutorService implementations allow you to provide a ThreadFactory which would allow you to set an uncaught exception handler

phronmophobic 2021-05-27T17:20:46.035400Z

The error handling strategy will depend on the use case. Generally, it's hard to recover from unexpected errors from arbitrary processes.

phronmophobic 2021-05-27T17:23:32.035600Z

As far as using something like core.async, I would generally turn all "outputs" (including exceptions) into data. That can mean wrapping work in a try/catch

2021-05-27T17:31:10.035800Z

+1 on this, the ideal here is to start all your processes with core.async and then use alt to wait for the first one to fail and then exit on that.

Ivar Refsdal 2021-05-27T17:36:14.036200Z

Because the system is stalled or wrong pid? I did it like this some time ago:

$ docker exec my-service ps
PID   USER     TIME   COMMAND
    1 java       0:00 /dev/init -- java -Xmx8g -Dcom.sun.management.jmxremote.rmi.port=19090 -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=19090 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.local.only=true -Djava.rmi.server.hostname=localhost -jar /my-jar.jar
    8 java       0:26 java -Xmx8g -Dcom.sun.management.jmxremote.rmi.port=19090 -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=19090 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.local.only=true -Djava.rmi.server.hostname=localhost -jar /my-jar.jar
  256 java       0:00 ps

# Make a heap dump for PID 8
$ docker exec my-service jcmd 8 GC.heap_dump /tmp/docker.hprof

Ivar Refsdal 2021-05-27T17:37:12.036400Z

and then:

docker cp my-service:/tmp/docker.hprof .

Eugen 2021-05-27T17:37:58.036600Z

it works now, I changed the path

emccue 2021-05-27T17:57:45.037700Z

There are some types in the transit spec like "point in time" that are listed as "extension" types

emccue 2021-05-27T17:58:48.039200Z

but i'm unclear if making a type like "~y123" is doable

emccue 2021-05-27T17:59:27.040100Z

most of the examples make it seem like the one letter, string prepending tagged values are an internal thing

emccue 2021-05-27T17:59:43.040500Z

and custom types i support myself would have to be

emccue 2021-05-27T17:59:52.040800Z

["~#y" "123"]

ghadi 2021-05-27T18:02:25.041500Z

I'm not clear what your question is

borkdude 2021-05-27T18:03:48.042Z

@emccue these types should be handled by registering transit handlers for those with a tag

emccue 2021-05-27T18:04:34.042400Z

for context, I am circling back to writing a transit impl for Elm

1πŸ‘
borkdude 2021-05-27T18:05:07.042900Z

cool, I like transit and would like to see it be extended to other languages

emccue 2021-05-27T18:08:13.044100Z

One aspect is that it won't be idiomatic to have dynamic handlers registered

emccue 2021-05-27T18:09:37.044800Z

so its important to understand how these special cases work

emccue 2021-05-27T18:10:00.045100Z

like Symbol is listed as an extension type

emccue 2021-05-27T18:10:12.045400Z

but it affects how caching works

emccue 2021-05-27T18:10:19.045700Z

so that makes it an intrinsic thing

emccue 2021-05-27T18:10:30.046100Z

but ~i123 is a ground type...

emccue 2021-05-27T18:10:32.046400Z

and so on

alexmiller 2021-05-27T18:12:50.046600Z

transit has been extended to many languages

emccue 2021-05-27T18:19:11.048500Z

yeah one of the challenges is that all the community implementations seem to take the same "pass a map of handlers" approach so I don't have much prior art to look at

emccue 2021-05-27T18:19:23.048800Z

the simplest case would be something like

emccue 2021-05-27T18:21:00.050600Z

[["~#point", [3, 4]], ["~#point", [5, 6]]]

emccue 2021-05-27T18:21:33.051200Z

in most implementations you would do something like

emccue 2021-05-27T18:22:15.052100Z

(transit/read {"point" point-handler} transit-val)

emccue 2021-05-27T18:22:41.052800Z

and how to interpret a value tagged with "point" is encoded all the way down the tree

emccue 2021-05-27T18:23:53.053600Z

but in elm, we don't have much of a choice but to use an api similar to elm/json where you put explicit expectations at each point

2021-05-27T18:24:47.054400Z

Does anyone know if there's an existing macro/library/idiom for using something like let with channels for fan-in? For example:

(let* [thing1 (<!! (do-thing1-returning-channel))
       thing2 (<!! (do-thing2-returning-channel))]
  [thing1 thing2])
The naive way to write this does thing1 and thing2 sequentially. It seems so natural to want to do them in parallel and allow the let to gather results that I wonder if someone has written the macro already...

emccue 2021-05-27T18:26:00.055700Z

import Array
import Transit.Decode as TD

type alias Point =
    { x : Int
    , y : Int
    }

decoder : TD.Decoder (List Point)
decoder =
    TD.vector 
      (TD.map2 Point
         (TD.tagged "point" (TD.index 0 <http://TD.int|TD.int>))
         (TD.tagged "point" (TD.index 1 <http://TD.int|TD.int>)))
    |&gt; TD.map Array.toList

ghadi 2021-05-27T18:26:02.055800Z

core.async/merge

ghadi 2021-05-27T18:26:18.056Z

(one way to do it)

2021-05-27T18:26:54.056200Z

Yeah, I can think of several good ways to get it done, just don't want to recreate someone's prior art needlessly

emccue 2021-05-27T18:28:04.057Z

so how I would handle TD.tagged "y" is an open question

emccue 2021-05-27T18:28:18.057400Z

since a since character could be a string tag

emccue 2021-05-27T18:28:36.057800Z

or it could be a tag for a composite value

p-himik 2021-05-27T18:35:19.058Z

Manifold has its own version of let , IIRC.

2021-05-27T18:37:13.058200Z

ooh, that's very promising, thanks

2021-05-27T19:02:41.058400Z

regarding using deref to test future failure, you can use the second and third args to deref to time out and provide a placeholder value if the future isn't ready, then move to the next future

2021-05-27T19:09:47.058600Z

contrived example:

(cmd)user=&gt; (def futs (map future-call (repeat 10 #(doto (rand-int 20000) (Thread/sleep)))))
#'user/futs
(cmd)user=&gt; (do (doall (take-while #{:waiting} (map #(deref % 1000 :waiting) (cycle futs)))) (map #(deref % 1000 :waiting) futs))
(6165 :waiting 7143 1631 :waiting 1091 :waiting :waiting :waiting :waiting)

Oliver George 2021-05-27T21:21:58.060300Z

Hello all. I created a #show-and-tell channel today. (Resend for us time zones) #announcements channel is lovely for libs but I want to be inspired by the systems and products people are building. What are you building with clojure today?Β Β Show a screenshot and tell us about it. Few fun screenshots at #show-and-tell already.

max minoS 2021-05-27T21:25:11.060400Z

thanks! I will check them out

zendevil 2021-05-27T21:30:53.060600Z

If I’m applying a filter on a set, what is the time complexity, where the size of the set n?

2021-06-02T18:26:30.289600Z

for a sorted-set you can get better time complexity for a split based on the ordering if you use subseq

borkdude 2021-05-27T21:46:45.060800Z

O(n)