Fork me on GitHub
#clojure-uk
<
2017-02-06
>
agile_geek07:02:42

@gjnoonan You'll be at ClojureX this year! W00t! I'm usually running around in a panic but come and find me.

agile_geek08:02:13

@otfrom not a direct Clojure question but more about architectural decisions. I've used Kafka and I'm a bit of a fan but I've got a problem that needs a messaging infrastructure that has fairly low volume, low rates per second i.e. < 1000 messaages per second (small messages). I think Kafka is probably not required and RabbitMQ is already in place so thinking to use that as it saves us setting up and maintaining new/different infrastructure and don't have to write our own mechanism for delivery guarantees. Does that sound sensible? I guess the real question is what advantages do I get with Kafka and what trade off's and when do you think the additional work of implementing delivery guarantees using Zookeeper are worth the advantages (i.e. high volume/performance)?

agile_geek08:02:34

@otfrom follow up question: Is there a good Clojure library out there that helps with the consumer delivery guarantees (I know about https://github.com/yieldbot/marceline for Storm but what's good for just a simple Clojure consumer? I can see options like: https://github.com/pingles/clj-kafka and https://github.com/ymilky/franzy but not sure what trade off's are?

tcoupland08:02:52

@agile_geek it sounds like you've pretty much made your decision and it's always easier to make use of what you've got, especially if there's operational experience with Rabbit.

tcoupland08:02:48

not that familiar with rabbit, but kafka get's you at least once delivery, easy scaling, and persistency

tcoupland08:02:14

we're using franzy, but it's a bit dead in the water at the minute, making in enquires about resurrecting it

agile_geek08:02:17

@tcoupland yeah. Not fully my decision (I'm just advising based on fact I'm only person whose used Kafka). I've not used Kafka from Clojure or used it for over 12 months so I wasn't sure what was available now around libraries to implement message consumer semantics.

tcoupland08:02:38

it has changed quite a bit recently. consumer offsets are not longer in ZK by default and the client has completely changed (see our kixi.comms project for some insight)

agile_geek09:02:27

OK. I'll take a look. What are the other (sensible options) for offsets in a Kafka cluster apart from ZK?

tcoupland09:02:14

it now stores them in itself. The consumer offsets are transmitted around on a special topic within the cluster

tcoupland09:02:27

which i find a bit weird 🙂

tcoupland09:02:19

the client is in some ways simpler, it just comes down to one function 'poll', but it's borked a bit because 'poll' is also the mechanism for clients sending keep-alive to the cluster. so if you have a long process time on messages, it gets a bit painful

agile_geek09:02:43

Hmm. I know having ZK was another 'moving part' to manage but not sure I like the idea of Kafka relying on itself for this. I liked the fact that Kafka did one thing and did it well. However, it's just my initial gut feeling and I guess you can still use ZK if you want but it adds work.

tcoupland09:02:27

o you still have ZK there, it handles the partition assignment. no reduction in parts

tcoupland09:02:52

and some broker bits and bobs, now i'm looking at it

agile_geek09:02:30

OK so I guess the reason offsets are in Kafka is to simplify code in consumers?

tcoupland09:02:07

well, not really. As you still end up managing your offset as much as you every did.

tcoupland09:02:14

the main justification seems to be performance

tcoupland09:02:46

o, if your a fan of core.async (like me), it's worth knowing about this multi-year old bug that's still rolling on: http://dev.clojure.org/jira/browse/ASYNC-100. hopefully save someone else having a seriously bad day 🙂

benedek09:02:51

re. clojure kafka libraries. clj-kafka does not support newer kafka versions afaik: https://github.com/pingles/clj-kafka/issues/87

agile_geek09:02:43

@tcoupland not sure I'm a 'fan' (as it sometimes makes my head hurt, I'm a simple soul and extracting values from non blocking go blocks always trips me up) but I certainly use it a fair bit. So the workaround is one 'catch' and check the exception manually? Not hard but a bit annoying.

tcoupland09:02:38

one catch, must be Throwable it looks like now. Yeah, not hard, but a mega pain in the bum if you do anything else!

agile_geek09:02:51

Yeah I saw that. The worry is more that ppl don't know this and naively implement an exception specific catch, don't test it thoroughly and get caught out. It should be documented in big red letters in the core.async docs!

tcoupland09:02:48

it's how old the bug is that is becoming my main concern. Opened it on 27/Oct/14 and I think it's fair to say it is a major bug that can cause people serious harm

agile_geek09:02:59

@tcoupland I assume it's a pretty tough one to fix? Otherwise someone would have submitted a PR?

tcoupland09:02:34

well they seemed to think it wasn't that hard to fix and patches have been submitted to this dupe: http://dev.clojure.org/jira/browse/ASYNC-169. Patched since may, although it looks like the tests just got tests added in september

tcoupland09:02:56

i think this comment sums it up nicely: "are there any plans/estimations regarding this bug? we were recently hit by it, and was a very special pleasure to analyze the issue."

glenjamin09:02:01

I’ve used Rabbit pretty heavily, and it’s performed well for me

glenjamin09:02:25

kafka’s persistence/replay stuff always sounds good, but it just seems more fiddly to use when i’ve tried it (in small scenarios)

Rachel Westmacott09:02:48

and I’m just off to check my use of catch blocks...

agile_geek09:02:27

@tcoupland So this raises a bigger question. What happens to the stewardship of Clojure if Cognitect go under? I'm never too sure who has rights to do what, other than Rich holds copyright for language.

maleghast10:02:55

@agile_geek - There's a scary thought...

maleghast10:02:34

I might finally be in a position to use Clojure for more than "a little tiny bit of the stack" and you're talking about stuff like this..? Argh! *hair turns white*

tcoupland10:02:59

that is a scary thought. I dread to think what would happen.

Rachel Westmacott10:02:31

looks like my catch blocks are broken 😞

Rachel Westmacott10:02:32

@agile_geek guess we’d better give them lots of money for consultancy so that they don’t go under!

benedek10:02:55

what if some big fish buys them? <evil grin>

tcoupland10:02:35

maybe some more bugs will get fixed 😛

thomas10:02:44

worth mentioning what David Polak(?) said a few years ago about this.. Cognitect doesn't depend on the success of Clojure.

otfrom10:02:49

agile_geek as it is licensed under eclipse we could carry on from the last changes under that license under a fork. We might have to change the name for trademark reasons though

agile_geek10:02:06

@otfrom who's this 'we' you speak of?

otfrom10:02:14

we the community

otfrom10:02:35

obviously we'd really miss Rich's stewardship, but emacs survived RMS handing it over

otfrom10:02:41

sorry, rms

otfrom10:02:07

well, luckily the community is larger than just you or me

otfrom10:02:26

we could always move over to lisp flavoured erlang. That might be better way of handling core.async things anyway. 😉

agile_geek10:02:44

I've watched a bit of a talk by Richard on LFE but it didn't go into any code just the language architecture so I have little opinion. I am a bit of a JVM fan boy tho

tcoupland10:02:16

@mccraigmccraig what's ticking all those boxes for you at the mo?

mccraigmccraig10:02:55

@tcoupland i have been following the development of https://github.com/LuxLang/lux - it's always looked conceptually awesome, and it's getting close to being usably awesome

mccraigmccraig11:02:04

other than that there is shen, but that's not properly open-source which very much puts me off

minimal11:02:21

there is a new racket based one as well

tcoupland11:02:50

Lux does sound interesting, i to am pretty bound to the jvm

mccraigmccraig11:02:21

scan the book @agile_geek - it's a very easy read, at least until you hit the monadic macros stuff https://www.gitbook.com/book/luxlang/the-lux-programming-language/details

agile_geek11:02:29

@mccraigmccraig now, now... you should know 'ease' is a relative term based on your formative experiences therefore what's easy to you may not be to me. 😈

mccraigmccraig11:02:26

true @agile_geek , though i remain unconvinced by your self-deprecation !

agile_geek11:02:02

Ask @otfrom...he knows how slow I can be 😉

mccraigmccraig11:02:56

ha, you broke the slack @mention regex

agile_geek11:02:25

I'm good at breaking stuff

gjnoonan11:02:34

I just like breaking shit troll

agile_geek12:02:32

I usually break my own sh*t tho.

thomas13:02:16

I don't need to break things... it never works in the first place... :thinking_face:

agile_geek13:02:14

@mccraigmccraig your self-deprecation comment has made me think...maybe I need to mark myself with '@deprecated @see daughters for currently supported implementation'

mccraigmccraig13:02:10

@agile_geek i shall read your nametag carefully next time i see you at a clojurey thing !

mattford14:02:29

I'm trying to write a macro generating macro.

mattford14:02:43

Struggling with the quoting

mattford14:02:51

(defmacro build-macro
  [n]
  `(defmacro ~(symbol n)
     [env]
      (print ~'~env)
      ))

mattford14:02:49

It's the 'env bit that's causing issues.

mattford15:02:40

ah sorted it 🙂

mattford15:02:21

(defmacro build-macro
  [n]
  `(defmacro ~(symbol n)
     [~'env]
      (print ~'env)
      ))

mattford15:02:00

I can't say I find the quoting/unquoting particularly friendly.

mccraigmccraig15:02:51

@mattford did you try using an auto-gensym (e.g. env# ) instead of quoting ? it makes bindings easier to read and avoids the capture pitfall (find "auto-gensym" here http://www.braveclojure.com/writing-macros/ for details)

mattford15:02:17

ah yes that works much more nicely.

mattford16:02:08

I have these macros

(defmacro with-env
  [env & body]
  `(dopartial [~env] ~@body))

(defmacro with-service-tags
    [env & body]
  `(dopartial [~env] ~@body))

(defmacro with-user
   [env & body]
  `(dopartial [~env] ~@body))

mattford16:02:24

I was trying to write a macro to generate them but failing miserably.

mattford16:02:11

Something like this

mattford16:02:15

(defmacro defwith
  [n]
  `(defmacro ~(symbol (str "with-" n))
     [env# ~'& body#]
       `(dopartial [~'~env#] ~'~@body#)
     ))

mccraigmccraig16:02:26

what's the expected output from those macros @mattford ? they all look identical from here...

mattford16:02:01

They are identical excepting the names.

mccraigmccraig16:02:31

and what does dopartial do ?

mattford16:02:32

I can write

(with-env "sit" 
  (with-user "stg" 
    (println "matt"))
and see
"sit stg matt"

mattford16:02:03

dopartial is more general form of doto.

mattford16:02:44

(defmacro dopartial
  [ x & forms ]
  `[~@(map (fn [f]
             (if (seq? f)
               (if (= 'dopartial (first f))
                 `(dopartial ~(into x (second f)) ~@(next (next f)))
                 `((partial ~(first f) ~@x) ~@(next f)))
               `(partial ~f ~@x)))
           forms)])

mattford16:02:28

I also wrote that. This really isn't the right approach for what I want. But I've a need to get the broken design working to satisfy my ocd 🙂

mattford16:02:46

There's a problem with arrays vs strings in the macro aliases (for want of a better term).

mattford16:02:02

But I just want my macro generating macro to work as I'd expect it to.

mccraigmccraig16:02:22

have you discovered macroexpand-1 @mattford ?

mattford16:02:47

it's sensible output for a whilst

mattford16:02:00

then just explodes with seqs and concats

mccraigmccraig16:02:15

yeah, writing macros is often a pita

mccraigmccraig16:02:29

i can see a possible problem with your dopartial macro too

mccraigmccraig16:02:03

in that it's matching against a naked 'dopartial symbol, but probably wants to work with a namespace qualified symbol too

Rachel Westmacott16:02:24

if the macros all do the same thing, can you just write one macro and then alias it under different names?

mattford16:02:54

Could do 🙂

mattford16:02:37

What's that called then?

Rachel Westmacott16:02:00

eg. (defmacro my-macro …)

Rachel Westmacott16:02:10

(def some-alias my-macro)

Rachel Westmacott16:02:21

(def another-alias my-macro)

mattford16:02:24

ah right easy peasy

Rachel Westmacott16:02:40

easier than learning how macro syntax works!

Rachel Westmacott16:02:49

not that you shouldn’t do that, but....

mattford16:02:08

Can I conquer the OCD and walk away from my macro generating macro.....

mattford16:02:26

Sadly I suspect not 🙂

mattford16:02:06

So I should use name for the if check matching?

Rachel Westmacott16:02:09

actually, apparently you can’t def like that on a macro 😞

Rachel Westmacott16:02:21

but apparently you can do this: (def #^{:macro true} my-or #‘or)

jonpither17:02:24

anyone booked accomodation for EuroClojure yet?

jonpither17:02:37

@benedek are the uswitch gang going out?

benedek17:02:50

to EuroClojure you mean @jonpither ?

mattford18:02:22

Is there a way in clojure to specify a function body based on the form/type of the arguments?

mattford18:02:17

eg. different bodies for string and arrays?

paulspencerwilliams18:02:51

Would detail further but 🍕

mattford18:02:07

But I really want multimethod macros

mattford18:02:36

hmm can a function know it's own name?

practicalli-johnny18:02:26

Great to see we have ~50 people coming to the London Clojurians talk on Tuesday night at SkillsMatter (so we should get a decent sized room) https://skillsmatter.com/meetups/8885-yada-2-0-and-clojure-efficiency-pitfalls

mccraigmccraig18:02:51

there is nothing stopping you calling a function from a macro @mattford ... you can also use the syntax-quote from regular functions

gjnoonan18:02:14

@jonpither: not yet, any hotel recommendations?

jonpither18:02:11

we are thinking staying south of the river. Local sources tells me it's a bit quiet close to the venue

gjnoonan19:02:52

great stuff @jr0cket I need to come down to one.. one of these days! Unless anyone has a spare time machine?

mattford19:02:55

I've come to the end of my great macro experiment 🙂 Many thanks to all for the help and for putting up with my spam. The final working version looks like this:

(defmacro defwith
  [n]
  `(defmacro ~(symbol (str "with-" n))
     [ x# ~'& forms# ]
     `[~@(map (fn [f#]
                (if (seq? f#)
                  (if (re-find #"^with-" (name (first f#)))
                    `(~(first f#) ~(into x# (second f#)) ~@(next (next f#)))
                    `((partial ~(first f#) ~@x#) ~@(next f#)))
                  `(partial ~f# ~@x#)))
              forms#)]))

(defwith profile)
(defwith env)
(defwith user)
(defwith tags)

(with-profile ["non-prod"]
  (with-env ["sit"]
    (println ": parameters are prepended")
    (println ": println will be swapped out to an `ssh` command"))
  (with-env ["stg"]
    (println ": different env")
    (with-tags ["bastions"]
      (with-user ["matt"]
        (println ": use params to discover/login and then do some stuff on a box")))))
and gives this
non-prod sit : parameters are prepended
non-prod sit : println will be swapped out to an `ssh` command
non-prod stg : different env
non-prod stg bastions matt : use params to discover/login and thendo some stuff on a box
It's succinct but impenetrable. Of to investigate other ways of doing similar.

benedek21:02:03

@jonpither i guess so but don’t know anything specific yet. apart from some really nice looking tshirt designs 😉

benedek21:02:12

will ask around tmrw