This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-02-19
Channels
- # announcements (10)
- # aws (3)
- # aws-lambda (1)
- # babashka (24)
- # beginners (57)
- # boot (5)
- # calva (20)
- # chlorine-clover (3)
- # cider (14)
- # clj-kondo (37)
- # clojars (17)
- # clojure (200)
- # clojure-dev (40)
- # clojure-europe (9)
- # clojure-france (7)
- # clojure-gamedev (5)
- # clojure-hungary (4)
- # clojure-italy (8)
- # clojure-losangeles (2)
- # clojure-nl (9)
- # clojure-uk (97)
- # clojurebridge (1)
- # clojured (3)
- # clojuredesign-podcast (23)
- # clojurescript (13)
- # code-reviews (2)
- # component (22)
- # core-typed (7)
- # cursive (64)
- # datascript (12)
- # datomic (60)
- # emacs (6)
- # fulcro (54)
- # graalvm (11)
- # graphql (3)
- # hoplon (25)
- # jobs (1)
- # joker (85)
- # juxt (5)
- # kaocha (10)
- # klipse (8)
- # malli (2)
- # off-topic (36)
- # parinfer (1)
- # pathom (1)
- # re-frame (9)
- # reagent (4)
- # reitit (1)
- # remote-jobs (1)
- # shadow-cljs (24)
- # spacemacs (1)
- # sql (39)
- # tools-deps (10)
- # tree-sitter (18)
- # xtdb (18)
Would anyone have example, or link to examples where we can enable/setup/retrieve some stats/metrics from aleph
server (started using aleph.http/start-server
) for things like, error count/error rate in the last 5 mins?
You can subscribe to connection-pool stats via register-connection-stats-callback
and there is also a rejected-handler
you can override in start-server
.
https://aleph.io/codox/aleph/aleph.http.html#var-register-connection-stats-callback
https://aleph.io/codox/aleph/aleph.http.html#var-start-server
If you're handling the request via manifold.executor, there is also register-execute-pool-stats-callback
and register-wait-pool-stats-callback
I am not using executor in our app. Did an experiment the register-connection-stats-callback
callback appears to be stats for when using aleph as http client. Not stats for server started using start-server
.
Its doc says Registers a callback which will be called with connection-pool stats.
. Where I think connection-pool is not for a http-server.
@UM8SD6W8G good point about the http client stats-callback; if you're not passing in an explicit executor, aleph is creating an utilization-executor
[0]. You probably need to pass in an instance of instrumented-executor
[1] to your start-server
. This should give you the ability to monitor the stats.
[0] https://github.com/ztellman/aleph/blob/5cc7bcab723bf3b64de7998fc782531c554636e5/src/aleph/http/server.clj#L532-L536
[1] https://github.com/ztellman/manifold/blob/master/src/manifold/executor.clj#L83-L95
Trying to get started using origami (http://origamidocs.hellonico.info/#/?id=origami-computer-vision-made-simple) , created a new lein app, then ran lein deps and it retrieved all packages....however, when then running lein repl it couldn't find opencv-native
anybody having the same issue? I can't load the repl since the opencv-native package can't be found....any help is greatly appreciated, thanks!
Has anyone ever use Taoensso's libary, Tufte? If yes, how could I format the stats map to comeback as a string saying 12.00ms
instead a long integer?
@contact904 can you provide more context on what you're seeing? the standard out looks like the percentiles should be in ms
Was this good context?
hello, how to I use this *TransferLearningHelper*(*ComputationGraph* orig, java.lang.String... frozenOutputAt)
in clojure?
That's one of the gotchas of Java interop. For vararg you need to pass an actual Java array.
I come from a Rails background. What is the quickest or default way to do web development in Clojure especially with Datomic.
This is a nice overview article: https://purelyfunctional.tv/mini-guide/what-web-framework-should-i-use-in-clojure/ There's also this: https://luminusweb.com/ But I agree with didibus and with the article in that it's better to start with small independent components and build your system up from that. Personally, I like using https://github.com/juxt/edge as a starting point and a "glue".
It's neither quick* nor the default** way; but I feel https://fulcro.fulcrologic.com/ is a nice one-stop-shop for building SPAs in Clojure. (And the Pathom integration is a well-paved path to using Datomic). *I wouldn't call it quick, because there is a lot of things to learn. **There is no default. :)
The Datomic requirement is the most hard to reconcile coming from a Rails background (I'm also a Rails-er) For me it was somewhat hard to completelly ditch Rails' ActiveRecord because it's a really nice ORM. I think the last two nails in the coffin were: https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/EffectivePrograms.md https://github.com/jkk/honeysql
@ujjwalt Clojure doesn't have a canonical web development framework the way that Ruby has Rails, and Python has Django. The best way to learn (and get started) is for you to try and build a minimal website using Ring: https://github.com/ring-clojure/ring , Ring defaults: https://github.com/ring-clojure/ring-defaults , Compojure: https://github.com/weavejester/compojure and Hiccup: https://github.com/weavejester/hiccup with Datomic as your DB
If you run lein new compojure
you'll get a minimal project setup with ring, ring-defaults and compojure. You'll need to add hiccup manually after that to it.
I got an issue in clj-kondo which uses transit-clj with a warning that transit-clj depends on a package with a security issue: https://github.com/borkdude/clj-kondo/issues/762
They should report it on transit-clj
bumping message pack versions is potentially a non-trivial update so not something to do without some review
@alexmiller do they have a lot of breaking changes?
not to my memory, but there are sometimes changes that affect transit, particularly when making big updates
sometimes also raises questions about updating msgpack on the other transit libs too
still worthy of periodic review :)
avoiding dependency checker false positives has some value too
most people don't look too closely at the CVEs
How do I get the data from a tagged literal? eg: #time/offset-date-time "2020-04-04T18:30+02:00"
depends whether you have a data reader defined for that tag or not
if so, then that data reader will be automatically called, which creates an object, and how you get data out of it depends entirely on what that object/data is
if not, then there are ways to use a generic reader like tagged-literal
to just read it as tag+form
but that is not installed by default
I’m using the Tick library for extra context. I think all I need is to read it though as I am putting it into JSON for later consumption.
Hello, I can see some readers defined in *data-readers*
How do I define more readers and writers? In particular I am trying to send JS objects thru wire
I'm considering to change the reader conditional logic for babashka. The reason is that many .cljc libs already work without changing the code, but babashka currently only chooses the :bb
branch in a reader conditional. This means that a lib like lambdaisland/regal has to be forked and all :clj
branches have to be copied to a :bb
branch: https://github.com/borkdude/regal/commit/42906e57bf45e9d6cb699700ea19e653757f535d
What I'm proposing is that babashka takes the first :bb
or :clj
branch (whichever comes first). Anything I should be aware of why this may be bad design?
ideally reader conditionals should be making greater leverage of the :default
branch such that this wouldn't be needed
https://clojure.org/reference/reader#_reader_conditionals for more on :default
most often libs have specific :clj
or :cljs
branches concerning interop differences. a :default
interop branch probably doesn't work an "all remaining platforms"
yeah, it depends a lot on the details
what's right for bb is hard to say
I mean in bb you control the reader, so you could make it pretend to be :clj platform
or inject both :clj and :bb features
by allowing both, users can always override :clj by putting :bb first. where it might not be so nice is in requires:
(:require #?(:bb nil :clj foo :cljs bar))
(this is incorrect syntax) but you can always (:require #?@(:bb [] :clj [foo] :cljs [bar])
as a workaround.
I'd kind of recommend a qualified keyword for your platform feature too (I don't think that's doc'ed anywhere, but seems like it would follow other such advice)
I've just followed what other platforms already were doing: :clj
, :cljs
, :cljr
, :clje
(Erlang), :joker
What is joker platform 😮
Clojure interpreter written in Go
to be clear, only those first three are "official" :)
just b/c others did it, doesn't make it right :)
I added a note to that page :)
"Implementors of non-official Clojure platforms should use a qualified keyword for their platform feature."
do you have any suggestions what kind of namespace those platforms should use? clojerl/foo
joker/foo
?
I ended up just calling (str …)
on it. Achieves the same result. 😅
how does platform/foo
help anyone? I don't see the point. if everyone uses platform
you still could get clashes?
unless someone can convince me of the need to change the current feature name and has a concrete suggestion, I'll probably leave it for now
it helps to identify what bb means. There might be many bbs, but there is only one borkdude 🙂
I'm willing to add another feature name to the babashka reader if there is somewhat more clear guidance on what to name these things, but :bb
has been in use for a while and I'm going to keep supporting that because of not breaking things
what about :`bb/clj` the platform is bb
and it's compatible with clj
. Who knows there will be a version that supports cljs
For Sci this is more clear, there is a :cljs
and :clj
mode (or I think there will have to be one in the future)
sci is configurable: you can say what features you want to read in the eval-string
options
ah yeah that's true, never mind than 🙂
oh wait I do have an example with Sci in mind 🙂 I have code that I want to run on the server and on the client, but they would be different in implementation so it would :sci/clj
and :sci/cljs
, but yeah I could control the reader myself indeed 🙂
the purpose of using a qualifier is to avoid collisions, and the only way to do that is with a qualifier you "control" either via dns, or trademark, or maybe some conferred identity like github
so "platform" provides no value
Ok makes sense. Would you consider bb
a trademark in this case?
@alexmiller if the goal is to avoid collisions, you don't need namespaced keywords. you can just use :nl.michielborkent.babashka
as the keyword
no, as I presume it has not been trademarked
.'s should only be used in the qualifier part of a keyword
per https://clojure.org/reference/reader on keywords, "They cannot contain '.' in the name part, or name classes"
babashka is trademarked via Dutch copyright (auteursrecht) i think (but I'm not a laywer)
Hi. Is someone using AWS lambda with a handler that :implements [com.amazonaws.services.lambda.runtime.RequestHandler]
? I'd like to know how to destructure the context argument as in (defn -handleRequest [this event context]
It has type of lambdainternal.api.LambdaContext
In Python it's smth like context.log_stream_name
ok, since the goal is to avoid collisions, I'm happy to talk with anyone who thinks he/she has more rights to the :bb
tag and I'll make changes if necessary to avoid a lawsuit.
Alex: might be nice to add "to avoid collissions" to the sentence here to give a reason why it's good practice to do this: > Implementors of non-official Clojure platforms should use a qualified keyword for their platform feature.
Hey everyone. I have a vector with email addresses in strings ["[email protected]"]
. I have a function that matches a email with a regex , but now i have to check each address in this vector. i tought of use doseq but it always returns me a nil. Can you folks have an idea?
(defn- match-regex?
"Check if the string matches the regex"
[v regex]
(boolean (re-matches regex v)))
(defn is-email-address?
"Check if input is a valid email address"
[input]
(if (nil? input)
false
(doseq [inputs input] )
(match-regex? input email-address-regex)))
My current code. it gets one string and matches with the regex for emailAnything that starts with do...
is primarily used for the side-effects. The return value becomes less important and they are often nil
.
Thank you for this tip.
Except for do
, where the last thing is returned. Many forms have an implicit do
in them such as when
, let
, fn
. That is how they support multiple expressions in them and the last one is returned.
Otherwise, for
etc. don't even support multiple expressions in them. if
supports exactly two but you can omit the second.
Thank you !!
Hello folks 🙂
I am currently having some trouble with protocols and I think I have misunderstood them a bit.
I have a piece of code that talks to an AWS queue that I would like to test, so I want to
create an abstraction over the queue so I can provide a stub for testing.
My code needs to call (sqs/find-queue credentials queue-name)
which returns a url.
I can then send a message to that queue with (sqs/send-message credentials queue message)
.
I thought it would be a good idea to create a protocol and implement it with a deftype
but I am
unsure if a) this is the right approach and b) if it is where sqs/find-queue ...
should go.
(defprotocol Queue
(send-message [message]))
(deftype SQSQueue [credentials queue-name]
;; somehow call find-queue
(send-message [message]
(sqs/send-message credentials queue message)) ;;not sure how I can get queue in there?
Any help is appreciated :)You could certainly call find-queue in send-message
(send-message [message]
(let [queue (sqs/find-queue credentials queue-name)]
(sqs/send-message credentials queue message)))
since you are storing the queue-name and not the actual queue you’ll need to retrieve it before sending the message
I think your deftype should implement the protocol as well
(deftype SQSQueue [credentials queue-name]
Queue
(send-message ...))
ahh yeah, i call that first arg this
to not forget
@hiredman Sorry, yes you are right I just wrote it directly in slack.
@christian.gonzalez I don't want to call find-queue
every time as it is an extra network call. I think it would be nicer to only find the queue once and then keep the reference somewhere.
i would instead store the queue instead of (or in addition to) the queue-name when creating your SQSQueue
I think the trappings of these other things are obscuring it, if you just write some functions the answer the pretty apparent
yeah, probably not the best starting approach unless it’s an exercise in learning protocols
I am definitely not stuck on the approach. I come from an OO background so my brain goes "I need an interface". Happy to do something that is more idiomatic in clojure, unfortunately I don't know what that would look like
the interface is fine, I am not saying there is anything wrong with it, I am saying take a step back from it, ask yourself how you would solve your problem with out any of that stuff, and the answer with all of that stuff is the same
so like, if you didn't have a deftype for SQSQueue, you might represent it as a hash map
and you might write a function that takes credentials and queue-name and returns your hash map
given that setup, it is fairly obvious the place to put the call to find-queue is in that first function
If you've no examples of clojure code to work from, run through one of the clojure books like Joy of clojure or clojure for the brave and true. Can also take a look at some github repos like CircleCI or Metosin, but those get fairly complex if you have no experience writing Clojure.
replace the hash-map with your deftype and the send-message function with the protocol function, done
it would make more sense if you had different types of queues you need to juggle in your code, like a rabbit queue and an sqs queue then maybe the polymorphism would clean up your code, but usually easier to start without using interfaces and move to them if you really need to
@jakob.durstberger I suggest you read this first. It was quite the eye opener for me. http://mishadoff.com/blog/clojure-design-patterns/
Thanks, that looks really interesting
If you read the official docs on http://clojure.org, defprotocol and family exist to take advantage of the very optimized type based dispatch from the JVM. The community generally discourages liberal use of types.
I am from an OOP background too, and even I too quickly associated defprotocol with interfaces.
Thank you that is all already helpful. > it would make more sense if you had different types of queues you need to juggle in your code, like a rabbit queue and an sqs queue I think I would have 2, one for testing and one SQS queue. So that's where I kinda started to think that using a protocol might be a good idea.
there are ways to mock functions like send-message
without using protocols
Like using with-redef
?
just redef find-queue
and send-message
?
I guess that would make it easier 😄
yup that would work
Thank you all. That was really helpful
@jakob.durstberger Although I agree that protocols are not easiest to start with, your idea is good! And I don't agree with what people are saying here about with-redef
. Having protocol abstractions is super useful, even if you only have one type of queue (doing it this way all the time). You probably do want to use defrecord
over deftype
for the implementation. deftype
is more optimized, but less user friendly
I just got around to replace amazonica with cognitects aws sdk so I haven't had time to play around with the protocol a bit more.
Thanks for telling me about defrecord
I've a spec question. I can't seem to get the function specs to exercise (or run with s/check) but I can get the spec def's to generate. When I run the fn spec I get back: storage-proxy.core=> (s/exercise-fn `q/read-lf-programs-by-ref!) Execution error at v2-storage-proxy.core/eval7802 (form-init12043777169450783562.clj:1). No :args spec found, can't generate ... am I doing something wrong in the fdef definition?
(s/get-spec `read-programs!) will return the fspec for read-programs!
that spec supports keyword lookup with :args
, :ret
do you a) see the function spec, b) see the args spec in that function spec, c) can you exercise the args spec, and d) up to 100s of samples
I see nil 🙂
...which is confusing lol.
well, then the spec is not in the registry
you may need to backtick the function name to fully qualify?
Definitely isn't if that's returning nil, which makes the problem easier to understand. Not sure how that is but that's likely it.
I don't have enough context here to really tell precisely
I am backticking - (s/get-spec `q/read-lf-programs-by-ref!) ... for example is returning nil. The def is in the snippet above.
q being an alias to the namespace.
that doesn't match your fdef for read-programs!, not sure if this is same example
trying to say read-lf-programs-by-ref! != read-programs! so I'm a little confused
Sorry, same codebase ...(s/get-spec `q/read-lf-programs!) is also nil.
It's a generalized problem for all s/fdefs right now.
if you (-> s/get-registry keys sort)
do you see stuff in your registry?
the registry is just a map, with qualified symbol keys for fdefs, not much magic here
No, get "no such var".
v2-storage-proxy.core=> (require `[clojure.spec.alpha :as s]) nil v2-storage-proxy.core=> v2-storage-proxy.core=> (-> s/get-registry keys sort) Syntax error compiling at (/private/var/folders/z2/q807rqzd2k5gr1hpywg3p49xw_x00z/T/form-init12043777169450783562.clj:1:1). No such var: s/get-registry
Sorry, should be parens around that :)
I let my dog type that part, not my fault
He sucks at Clojure
s/registry exists ... dumping that.
I do see them in the registy
For some reason, after calling (s/registry) to get the map ... now the lein repl (but not Calva's) attempts to exercise the function spec.
Not quite following, but if you think Calva should behave differently here, please file an issue. ❤️
...well, does exercise it. So that's working, by magic, from the lein repl now. lol.
is there a smart way to handle working on multiple projects at the same time, which sometimes can conflict on fighweel/shadow-cljs/ring ports?
I can try to have different ports in every projects but it's not always easy and a bit of a pain anyway
wdyt of (or (System/getProperty "my-proj.the-port") 8080)
?
jvm properties can be merged/activated at will which is cleaner than System/getenv
(which would also work)
ah cool, tbf almost all the projects use aero
I was thinking though about something more magical at a lower level, that just tries another port if the port it wants it's busy
Yeah I've wanted something like that sometimes. OTOH, sometimes multiple things need to be aware of the chosen port (e.g. server + asset pipeline), things could get unwieldy there
Also, it's annoying to remember as a user :) My thoughts when designing this for edge were: - cache the choice - use a special reader macro that chooses nice ports I ended up just generating nice ports randomly on project creation.
for socket repls of jvms i have something that can externally start a socket repl on your port of choice (or choose something available) -- after the jvm has started: https://github.com/sogaiu/alc.start-repl i use the following to attempt detection of socket repl ports (and other types) at runtime: https://github.com/sogaiu/alc.enum-repls -- i use this from tooling to guess ports so i don't have to look them up manually
these are both typically invoked not at the repl but at the command line or via external process invocation
Many of my users are reporting a problem in the latest version of Cursive, and I cannot figure it out. The error looks like this:
Error running REPL: Receiver class cursive.repl.toolwindow$repl_listener$reify__11845 does not define or inherit an implementation of the resolved method 'abstract void contentAdded(com.intellij.ui.content.ContentManagerEvent)' of interface com.intellij.ui.content.ContentManagerListener.
The reified object looks like this:
(reify
ContentManagerListener
(contentRemoveQuery [this event]
...)
ProjectManagerListener
(projectOpened [this project])
(canCloseProject [this closing-project]
...)
(projectClosed [this project])
(projectClosing [this project]
...)
(projectClosingBeforeSave [this project]))
and the interface looks like this:
public interface ContentManagerListener extends EventListener {
default void contentAdded(@NotNull ContentManagerEvent event) {
}
default void contentRemoved(@NotNull ContentManagerEvent event) {
}
default void contentRemoveQuery(@NotNull ContentManagerEvent event) {
}
default void selectionChanged(@NotNull ContentManagerEvent event) {
}
}
Since all the interface methods have default implementations, as far as I know this should be fine, and it always works for me locally - I’ve debugged through it etc.
Since this only happens in released builds and never locally, hopefully I can rule out AOT crud, because I do a clean build when releasing.
Are there any edge cases to using reify like this that I should be aware of? For the life of me I can’t see how this error could happen.
I haven't had to deal with default methods much so I can't say for sure, but from my understanding I would expect that to work. It does look like the defaults were added in 2018, could your users be running an old version or something?
No, they’re either running the 2019.3 (late last year) or 2020.1 (in beta now) versions.
oh my mistake, the defaults were added late last year https://github.com/JetBrains/intellij-community/commit/0a26756d32f010c3f637e836c6da97ad4c898d7e#diff-07555269ed50234de570ec57a2c3668d