This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-20
Channels
- # aws (1)
- # babashka (68)
- # beginners (68)
- # braveandtrue (6)
- # calva (4)
- # cider (10)
- # clj-kondo (26)
- # clojure (76)
- # clojure-dev (18)
- # clojure-europe (1)
- # clojure-norway (25)
- # clojure-spec (8)
- # clojure-sweden (7)
- # clojure-uk (3)
- # clojuredesign-podcast (1)
- # clojurescript (11)
- # conjure (29)
- # cursive (31)
- # datomic (29)
- # emacs (12)
- # fulcro (29)
- # graphql (3)
- # helix (2)
- # hoplon (39)
- # hugsql (4)
- # malli (3)
- # off-topic (62)
- # pedestal (8)
- # re-frame (23)
- # reagent (14)
- # rewrite-clj (10)
- # shadow-cljs (18)
- # spacemacs (3)
- # sql (13)
- # xtdb (32)
What do you think about this interval tree implementation? Any way to make it a bit less fragmented? http://clj-me.cgrand.net/2012/03/16/a-poor-mans-interval-tree/ Looks a bit like a hack, but a convenient and multiplatform one. Rather surprisingly, it looks like there isn't any efficient clj/cljs interval tree out there.
Hi all, after reading this post: https://medium.com/helpshift-engineering/achieving-graceful-restarts-of-clojure-services-b3a3b9c1d60d I started to think about how Clojure deliver to us not only a simpler way to deal with threads and asynchronous primitives from Java in general, but also a easier way as well. But all this can be undermined when one needs to handle the threads lifecycle. Is there some kind of framework a la Stuart Sierra Components to help us with this? Something like a mini Erlang OTP framework for Clojure?
Work has been done here: https://github.com/suprematic/otplike
If you are looking for more complex use cases then ultimately you may want to manage your own thread pools, either directly in java or using Claypool https://github.com/TheClimateCorporation/claypoole Having said that even for lots of complex use cases I was always fine with just using a combination of async (just always make sure you set proper size of async thread pool) and Stuart Sierras component (e.g. here https://github.com/mikub/titanoboa/blob/master/src/clj/titanoboa/server.clj#L135 )
Good example @U5L1P2D9U As I started this question on Clojureverse as well: https://clojureverse.org/t/is-there-a-canonical-way-or-framework-to-handle-threads-lifecycle/6136
I was inspired by the blog post that you've shared and wrote a tiny utility namespace to declare and install shutdown hooks: https://github.com/nomnom-insights/nomnom.utility-belt#lifecycle-hooks - we use this approach across 10+ services, and guarantee safe shutdowns of components, threadpools etc with this approach. It's somewhat simpler than what HelpShift folks did as Component determines the order of start/stops so we didn't have to worry about it.
@seancorfield hey, you wanted me to notify you if I will find alternative to wkhtmltopdf
to generate PDFs in Java / Clojure. I am still during research, but probably /Applications/Google\
is the best. Simple, can be easy run in docker. No extra dependencies. I can test things in Chrome easy. It works like expected so far. It will be funny if this solution after more testing will be the right one. No reason to use pupeteer or selenium or whatever. Probably 😉
Oh, that is an interesting way to do it! Thanks!
--headless --disable-gpu --run-all-compositor-stages-before-draw --timeout=3000 --print-to-pdf=foo.pdf html-to-pdf.html
I added a few parameters, but not sure if they are really useful
BTW this is a conceptually similar approach as I’ve used with OpenOffice / LibreOffice (albeit for format conversions), where we would spin up a pool of OO / LO background processes, and then communicate with them via sockets (they have a primitive socket-based API) to perform conversions.
That said, OpenOffice / LibreOffice weren’t really designed to run as a headless “microservice”, and they’re pretty unstable when used in this way. I would expect / hope Chrome would have better operational characteristics, especially as you’re re-running it each time (rather than leaving it up and running as a daemon).
thank you, the hardest part was to realize that. Whole google saying to use pupeteer, wkhtmltopdf and all other stuff which add extra layers on chrome which today are not really needed. I don’t even want something to effect my HTML. Especially to generate PDF from template. Go outside the trap of using additional libraries is so hard 🙂
That’s great! I wouldn’t have expected Chrome to start up so fast!
But if it’s fast enough to just shell a new Chrome process each time, that’s a great KISS solution! 😉
I wonder if headless Chrome binaries are available in most PAAS runtimes? :thinking_face: (no need to answer that btw - it’s something I can research when I have the need 😉)
I don’t know. I will make all of this in Dockerfile. I just tried to install chromium in clojure:openjdk-14-tools-deps-1.10.1.502-buster
and it looks good
chromium-shell which is headless throw exception, because of no X… it doesn’t make sense. I will just use standard chromium then.
to be precise *chromium - free open version easy to install from command line *Chrome - google product based on chromium
Yeah OO/LO require X too, and IIRC there’s a headless “noop” X server you can install to provide that. But if there’s a chromium package that doesn’t need X at all, all the better. 😉
no, but I need PDFs with precision to each mm, so any markdown will not give me that
there is only one issue with this. I need rotate90 and today it doesn’t work good in chrome. There are differences in position, small, maybe about 1mm or 0,5mm but because of that I have to use something extra to rotate90 all pages in PDF after generate.
(defn rotate90-pdf [path]
(let [document (PDDocument/load (File. path))]
(try
(doseq [page (.getPages document)]
(.setRotation page -90))
(.save document path)
(finally
(.close document)))))
anyone use arcadia?
i need to know how to use dependencies with it
my understanding is that with all of clojure-clr, the current best practice is to use the native clr package manager, with arcadia you might want to use the package managment features of unity
So, the suggestion is not to use core async and use what the CLR provides?
no, the suggestion is that if you use core.async, use the clr package manager to acquire it but as far as I know there's no way to use core.async with clr, as it hasn't been ported to that vm
@seancorfield You wrote a few times (well, at least twice) in the last week that you just evaluate forms to the REPL during development. That's basically my workflow too, but I never was able to do that when changing rout definitions with compojure (I think I tried bidi once and that did not work either). So for a changed route I have to reload the namespace and then my components. Do you have a setup where you can evaluate your routes in the REPL and have them changed instantly without a reload?
Use #'
on the various symbol references, e.g., #'app
instead of plain app
, so that you have an extra level of (Var) indirection, and then you can eval a new version of the function and it will be picked up immediately.
@U0WL6FA77 Not just with alter-var-root
. The #'app
syntax is short for (var app)
which yields the Var
itself that app
is bound to. The Var
then holds the reference to the current definition. So when the Var
is passed around, it is dereferenced when its value is needed, e.g., in a function call.
We use it in production code, even tho' it introduces an overhead due to the extra indirection, because it's very convenient when developing and we don't want to have different code in dev/test vs production.
You can see it in this example repo here https://github.com/seancorfield/usermanager-example/blob/develop/src/usermanager/main.clj#L122-L133 and here https://github.com/seancorfield/usermanager-example/blob/develop/src/usermanager/main.clj#L208-L210
I see, thank you. I was always kind of hesitant to do that as I am afraid it has runtime implications in the production environment. Does that have any drawbacks for production?
I use trick mentioned by @seancorfield with alter-var-root
in user
ns. So I have something like below and can restart the server from the REPL
(ns user
(:require [api.core :as core]
[server.core :as server]
;; ring
[org.httpkit.server :as httpkit]
;[ring.middleware.reload :refer [wrap-reload]]
[ring.middleware.stacktrace :refer [wrap-stacktrace]]
[ring.middleware.session :refer [wrap-session]]
[ring.middleware.session.memory :refer [memory-store]]))
;;; ring
;(def mem (atom {}))
(defn wrap-debug [f]
(fn [{:keys [request-method] :as request}]
(println "request" (pr-str request))
(let [response (f request)]
(println "response" (pr-str response))
response)))
(def app
(-> server/app-stateless
(wrap-stacktrace)
(wrap-debug)
#_(wrap-session {:store (memory-store mem)})))
(defonce app-server nil)
(defn app-ring-start [_]
(httpkit/run-server app {:port 8080}))
(defn app-ring-stop [server]
(when server
(server))
nil)
(defn app-start []
(alter-var-root #'app-server app-ring-start)
:started)
(defn app-stop []
(alter-var-root #'app-server app-ring-stop)
:stopped)
;;; refresh
(defn dev-start []
(app-start))
(defn dev-stop []
(app-stop))
(defn dev-restart []
(dev-stop)
(dev-start)
:restarted)
(comment
(dev-restart)
(refresh)
(refresh :after 'user/dev-start)
(httpkit/run-server (wrap-reload #'user/app) {:port 8080}))
but with current project I use integrant
so I don’t need this anymore. Probably I like more integrant
approach
another way which I use to reload handlers is to reload ns containing handles. It works too without reloading the ring. But you have to do it manually, even if change only files which are dependencies. You have to remember to reload ns with handlers. It can be tricky sometimes to remember.
That code above won't pick up changes to the middleware or the app
function or app-stateless
, without stopping the server, reloading the code, and starting the server again. By using #'
references on those symbols instead, you can update any of those functions while the system is running. That's what we do at work -- we can develop from the editor, via a REPL, into a continually running server app.
@sveri It does introduce a little overhead because of the additional indirection, but we haven't seen it as a problem in production code (accessing the database and/or third-party HTTP services completely overwhelms the small overhead of a few Var
indirections!).
Is there existing tooling that can do either of the following refactors? I need to move a file like `app.ui.foo` to `app.foo` and have all dependent requires updated. I also need to move individual fns from one namespace to another like `app.foo/myfn` to `app.bar/myfn` and have the tooling change all refers from the old ns to the new one.
@thosmos I hear folks talk about Cursive having some sophisticated refactoring. There's also some refactoring stuff in the CIDER stack for Emacs. I don't use either so I can't provide details. There are #cursive and #cider (and #emacs ) channels that might help you get more detailed information about them.
In Cursive you can change ns name, but only on the same level. So a.b.c
can be changed to a.b.d
, but not to a.b
. So far I am doing this job manually.
To be precise: you can refactor only the last part after .
in ns
(unless there is secret way which I don’t know)
@seancorfield Thanks, nice to hear that. I will try that out.
is it completely untenable to embed a JVM inside of an iOS app? like is it just completely disallowed - either by app store rules or some attribute of the platform?
@lilactown my recollection is that code execution is completely blocked. Nothing dynamic. Except JavaScript, that's cool.
In particular the built in JavascriptCore runtime. I think this is what Replete uses?
what's an easy library for plotting charts of data in clojure? I don't need an entire statistical computing system like incanter, and I want something that's easy to use at the repl
I just want to be able to (for example), plot the output of frequencies
on a seq as a histogram at the repl
there currently aren't any built in plotting functions, but this would be simple to do with a library I've been working on, https://github.com/phronmophobic/membrane:
(defn histogram [freq]
(let [plot-height 300
max-freq (reduce max (map second freq))
bars (for [[k n] freq
:let [height (* plot-height (/ n max-freq))
offset (- plot-height height)]]
[(ui/translate 0 offset
(vertical-layout
(ui/filled-rectangle [0 0 1 0.3]
20 height)
(ui/label k)))
(let [val-label (ui/label n)]
(ui/translate 0 offset
val-label))])]
(apply horizontal-layout
bars)))
(let [nums (repeatedly 50 #(rand-int 50))
freq (->> nums
frequencies
(sort-by first))]
(ui/run
#(histogram freq)))
which looks like:if you're interested, I can add a few basic plotting functions to try out
what plots would you be most interested in?