Fork me on GitHub
#beginners
<
2020-10-22
>
Mohamed Aziz Knani03:10:01

Hello, I use immutant with ring. I want to write something like "tail -f" with websockets. I pass an InputStream to send! but it doesn't do what I want. Does anyone have an idea of how to do this ?

sova-soars-the-sora03:10:43

What does tail -f do?

sova-soars-the-sora03:10:32

It means tail -f command will wait for new strings in the file and show these strings dynamically. This command useful for observing log files .

For example try, tail -f /var/log/messages.

sova-soars-the-sora03:10:42

alright... that might help get the ball rolling on that question

sova-soars-the-sora03:10:24

Hmmm... you will probably have to send discrete packets through websockets... rather than a stream, but my confidence is only 55% on that statement

Mohamed Aziz Knani03:10:32

> discrete packets Can you explain what this means ?

sova-soars-the-sora03:10:43

send one drop at a time instead of a river

Mohamed Aziz Knani03:10:34

wait I will read more about inputstream, the stream part is confusing

noisesmith03:10:38

I don't know immutant's websocket abstraction specifically, but the APIs I've seen expect to take objects that they then write to the socket

noisesmith03:10:21

in theory, just writing an inputstream to a socket should be possible with

sova-soars-the-sora03:10:44

oh neat.. yeah hopefully you get it resolved, 😃

Mohamed Aziz Knani03:10:59

ah thanks let me try this

noisesmith03:10:09

and I'd expect send! to be something more abstract, that tries to serialize the objects and do the writing for you - it's higher level than what you probably want if it's anything like the send! from sente for example

Mohamed Aziz Knani03:10:53

wait you mean like do (io/copy inputstream channel) instead of (send! inputstream channel) ?

noisesmith03:10:15

this really depends on what "channel" even is

noisesmith03:10:28

sorry, I don't know immutant, but I've done this with other libs

Mohamed Aziz Knani03:10:06

it's a org.projectodd.wunderboss.web.async.Channel

noisesmith03:10:58

yeah, that's not an OutputStream, so you can't use io/copy

noisesmith03:10:18

it wants to take an Object, which it then wraps up and puts on the socket

Mohamed Aziz Knani03:10:56

okay so I think the easiest solution for me is to do what @sova said

Mohamed Aziz Knani03:10:26

so like I open a file, and then how do I know that it changed? is there like a callback to see if it changed?

Mohamed Aziz Knani03:10:44

or should I just do a loop and check if it changed?

noisesmith03:10:06

you can use a WatchService, I assume some clojure library is available to wrap it if you aren't comfortable using it directly

Mohamed Aziz Knani03:10:34

I will look this up, Thanks 🙏

Mohamed Aziz Knani03:10:33

I just straced this On linux "tail -f" uses the select syscall.

Mohamed Aziz Knani03:10:47

I mean read should be blocking right? Until data is written?

Mohamed Aziz Knani03:10:17

Oh or that's only in a fifo

Mohamed Aziz Knani03:10:27

Yes I think watchservice would work @noisesmith thanks

Eugene Kiba08:10:42

Is there a good comparison regarding modern IDE support of Clojure/ClojureScript ? Any default preferable options for commercial development?

practicalli-johnny09:10:11

Not specifically created to be a comparison, but this may help you understand the basic differences. http://practicalli.github.io/clojure/clojure-editors/ They all provide excellent support for Clojure and are free for commercial and non-commercial work (although sponsorship to the project maintainers is always appreciated) IntelliJ and Cursive requires a license. It also requires an annual fee for commercial work. Recommendation is to use the editor you prefer, to reduce the learning curve.

Eugene Kiba07:10:20

thanks everyone )

Dave Russell10:10:28

Is there a more idiomatic way of writing if x x y?

ep10:10:44

(or x y) ?

Dave Russell10:10:54

I must have had a weak cup of coffee this morning 😛

😜 3
👍 3
phrimm13610:10:32

Anyone beginned clojure without any knowledge of java/javascript? What did you do to use clojure interop well?

practicalli-johnny12:10:30

I mainly use reagent, so no need for much JavaScript interop unless you really want to. For more complex UI, then there is re-frame There are excellent courses on reagent and re-frame here: https://www.jacekschae.com/ To use npm packages, many use http://shadow-cljs.org/

Jim Newton12:10:14

is there something special I have to do in a macro to inject meta data into the macro expansion? for example, I would like this macro to define a dynamic variable whose name is given by public-name .

(defmacro defn-memoized
  [[public-name internal-name] docstring & body]
  (assert (string? docstring))
  `(let []
     (defn ~internal-name ~@body)
     (def ^:dynamic ~public-name ~docstring (memoize ~internal-name))
     )) 

Jim Newton12:10:19

this is supposed to define a function which is memoized, but which I can rebind using binding to limit the dynamic extend of the memoization

Jim Newton13:10:07

but at the binding-site, clojure complains the variable is not dynamic. not sure if this is a loading order problem, or a problem with my macro not injecting meta data correctly

Alex Miller (Clojure team)13:10:59

In a macro the metadata is being applied at the wrong time - instead use with-meta to apply the metadata in the expansion

Jim Newton13:10:50

@alexmiller can you give me an example? I looked at the doc for with-meta but it's not clear to me how the macro interaction is working with metadata. It would be nice if there were an example either in the defmacro docs or the with-meta docs. I can create such an example, once I understand it.

Jim Newton13:10:32

I.e. do I need with-meta to be called a macro expansion time, or do I want the expanded code to contain with-meta ?

Jim Newton13:10:09

that doesn't work, at least as I understand your suggestion.

(defmacro defn-memoized
  [[public-name internal-name] docstring & body]
  (assert (string? docstring))
  `(let []
     (defn ~internal-name ~@body)
     (def (with-meta  ~public-name {:dynamic true}) ~docstring (memoize ~internal-name))
     ))
This gives an error at the macro call-site that the first argument of def must be a symbol.

Alex Miller (Clojure team)13:10:31

sorry, probably need to evaluate the outer expr ~(with-meta public-name {:dynamic true})

Jim Newton14:10:51

seems the compiler is much happier with that.

Jim Newton14:10:26

(defmacro defn-memoized
  [[public-name internal-name] docstring & body]
  (assert (string? docstring))
  `(let []
     (defn ~internal-name ~@body)
     (def ~(with-meta public-name {:dynamic true}) ~docstring (memoize ~internal-name))
     ))

Jim Newton09:10:05

I've added a https://clojuredocs.org/clojure.core/with-meta#example-5f92a7f6e4b0b1e3652d73e7 of with-meta. However, not sure this is the correct place for the example. Perhaps it is more appropriate as an example with defmacro ?

Alex Miller (Clojure team)13:10:35

you'll want something like (with-meta ~public-name {:dynamic true}) here

0xclj15:10:10

What’s the Clojure equivalent for https://github.com/mperham/sidekiq or https://github.com/contribsys/faktory for background processing? There’s a 4 year old https://www.reddit.com/r/Clojure/comments/48ur9m/distributed_workers_with_retry_backoff_looking/ with some comments, looks like https://github.com/ptaoussanis/carmine is the only one under active development.

Zor15:10:19

I've never found a convincing one based on Redis. Or on anything. I'm not aware of any Clojure dep that would come with a web-ui and a deployment cookbook. Because Clojure (and really, the JVM) has solid multi threading support, lots of the things you would defer out of process in a GIL-VM like Ruby's or Python's can be done in-process instead. (future (sendmail ...)) In-process retry/backoff you'll have to deal with yourself, I'm pretty sure I've seen a nice library for this recently but I can't recall the name .. This being said, there are many good reasons to distribute tasks on several processes. For such cases, I use RabbitMQ (with http://clojurerabbitmq.info/articles/guides.html). It provides the retry feature, and better (ACK, NACK) semantics than Sidekiq, imo - if a worker disappears without terminating message processing, message will be made available again, no need to requeue on exceptions. Setting up RabbitMQ for a Sidekiq-like queue processing is probably the simplest RMQ use case - don't let the documentation confuse you 🙂 The backoff thing is however https://www.brianstorti.com/rabbitmq-exponential-backoff/. Apache Kafka seems to be the rock solid, all powerful solution for this. It might be worth starting with Kafka right away and spare yourself some of the Rabbit nonsense. I have yet to try it. I've chosen RabbitMQ because it looked simpler to operate and develop with and my needs are modest (no HA, no high throughput).

0xclj15:10:39

@U716Q56R2, Thanks for the detailed response. I’m merely looking for a background processing lib. Using RabbitMQ for this could be something I’d explore if there’s no reliable library to handle background jobs. Will also read upon (future (,,,)) to see if that suits my need. The use-case is indeed to send emails as notifications upon an update.

☺️ 3
Zor15:10:47

There is also https://clojure.org/reference/agents, which comes with a pre-made Thread pool, clearer semantics, and more pre-made useful things for you to build on.

0xclj15:10:26

Thanks, will read up on it too.

Zor16:10:58

And ... finally the "Message Queues" bits of https://www.clojure-toolbox.com/ 🙂 Notably https://github.com/Factual/durable-queue seems a nice in-between agents and rabbit. My gut feeling is that you can get stuff done with Agents today, and move to something more robust if you need to.

0xclj16:10:30

Noted this as well. https://www.clojure-toolbox.com/ is awesome! Thanks again! 😄

3
0xclj16:10:08

Also, is there any relevant channel here that you’re aware of for discussion of system designs by any chance?

Day Bobby17:10:08

What is the limitation of carmine as a messages queue I might ask? I'm looking for something similar myself. I also found clj-faktory (https://github.com/apa512/clj-faktory) but carmine is under more active development. I know it doesn't have a web ui but I can do without one.

Day Bobby17:10:34

for system designs I think there is #architecture

👍 3
Zor18:10:42

One limitation of the Carmine's Message-Queue is that it doesn't seem easy to interop with non-Clojure workers - something that would be doable with RabbitMQ or Kafka. No CLJS support either, so even if you're interop needs are with Node.js processes, you seem to be out of luck. clj-faktory - as part of a faktory system, is inherently polyglot, so this solves that. And you get the nice faktory UI and scheduler, and commercial support options. I wouldn't be worried about active or inactive development. It's rather common in Clojure to have stuff that works and is in a finished state 🙂

👍 3
Day Bobby20:10:17

Useful stuff, thank you! Gonna check out clj-faktory more to see if it implements all the stuff I need from faktory

olttwa04:08:59

@U019M13JFAQ @U716Q56R2 @U01BMAKUNEP we've recently released a background job processing library similar to Sidekiq for Clojure. It has reliability & feature parity with Sidekiq Pro. Do check it out: https://github.com/nilenso/goose

1
olttwa04:08:14

@U019M13JFAQ RabbitMQ support in Goose is planned for 0.3

dharrigan15:10:01

I use as my Redis client

0xclj15:10:10

Can’t really tell if it supports background processing looking at the README, does it?

haywood17:10:26

potentially dumb question, I need to pretty-print an edn map to a file, including any meta-data, basically doing what (binding [*print-meta* true] (pr my-cool-map)) would do

Alex Miller (Clojure team)17:10:13

(spit "foo.edn" (with-out-str (binding [*print-meta* true] (pr my-cool-map)))) is one way

Alex Miller (Clojure team)17:10:29

there are more cumbersome ways if you need better performance (open a stream to a file and bind out to that)

haywood17:10:50

Performance isn’t an issue, but when I open the file it’s not pretty printed

haywood18:10:24

pprint doesn’t seem to abide by the *print-meta* binding

haywood18:10:05

perhaps I need to look into creating a custom writer

Alex Miller (Clojure team)18:10:29

interesting. there is actually an old ticket for this https://clojure.atlassian.net/browse/CLJ-1445

Alex Miller (Clojure team)18:10:01

the attached patch there seems to work

Alex Miller (Clojure team)18:10:18

can't say I've ever noticed this before

haywood18:10:24

Oh nice, thanks for finding that, voted! Also, maybe I’m just missing it, but where can I find the attached clj-1445-workaround-v1.clj file?

Alex Miller (Clojure team)19:10:03

I dropped an actual patch on the clj ticket too to actually fix this

thumbsup_all 3
haywood18:10:19

ah, derp, cheers Alex 🙂

dharrigan19:10:13

I'm seeing this when I turn on (set! *warn-on-reflection* true) : Reflection warning, foo/bar/policy.clj:0:0 - call to java.lang.IllegalArgumentException ctor can't be resolved. Yet, nowhere in my codebase do I use IllegalArgumentException. Would it be a 3rd party dependency issue?

seancorfield19:10:10

It could be something that foo.bar.policy is requiring, but normally reflection reports the correct filename. Maybe a macro expansion (but, again, I'd expect the filename/line number to be a bit more meaningful).

dharrigan19:10:42

It's a puzzler

seancorfield19:10:10

I guess: comment out everything in policy.clj except the ns form and if you still get the warning, start commenting out required nses?

dharrigan19:10:07

Worth a shot, will give it a whirl 🙂

Александр Стоянов22:10:03

Hello! I have problem. Can run frontend but can't run backend cause "project/server.clj couldnt locate on classpath"

andy.fingerhut23:10:31

You are using a shadow-cljs template? I know someone recommended you ask in #beginners, but I just wanted to point out that there is also a #shadow-cljs channel where a larger fraction of people might be familiar with that template.

andy.fingerhut23:10:45

Sorry, I misled you again 🙂

andy.fingerhut23:10:54

but you should be getting closer