Fork me on GitHub
#clojure
<
2024-08-06
>
tgg15:08:10

What’s the best clojure retry library?

dharrigan15:08:03

Not sure which is the best, but I've had very good success with .

2
Felipe16:08:21

I evaluated a bunch recently and liked diehard the most

Drew Verlee16:08:31

What are we retrying?

tgg16:08:53

File system reads that might throw FileSystemException s

Drew Verlee16:08:38

Interesting. I'm curious, why do you think calling the same function more than once might have a different result? Im just asking the first thing that comes to mind, so feel free to ignore me. 😜

tgg16:08:25

We’re assuming that there’s transient issues with a file system mount

igrishaev16:08:08

TL;DR: by retrying, you're just closing your eyes to the real problem

🙈 1
Drew Verlee16:08:52

Hmmm, yeah. I don't have good ideas given what i know. GL.

🙏 1
vemv17:08:53

huh ngl, the article seems to lack nuance. The vast majority of times what's being retried is network issues or the given remote api having some sort of hiccup. A good retry impl with specifically observe 5XX status codes or timeout exceptions. If peers didn't observe that, it has nothing to do with retrying or clojure 🤷

3
vemv17:08:45

I don't have a particular opinion about file systems, although it's not rare to find articles explaining how they're quite the rabbit hole, a leaky abstraction, etc etc. I'd log the error for future examination but also retry if that happens to fix things. Most devs aren't going to casually become fs experts overnight.

potetm19:08:16

funny, I'm currently working on a resilience lib that more or less solve the issues in that article

potetm19:08:36

tl;dr have users specify a retry? fn

respatialized20:08:06

safely, linked above, has a parameter - :retryable-error? - that gives users control over when it actually makes sense to retry versus when it doesn't, by allowing them to pass a predicate function to match on the exception type. it also logs using the excellent mulog library by default, so it's not throwing information away. it makes it pretty easy to "do the right thing" and gradually incorporate more error handling into the retry loop with the benefit of detailed logs, just as the article recommends.

👍 1
Steven Lombardi22:08:59

If by "Clojure" library you mean "JVM" library, then I highly recommend failsafe. https://github.com/failsafe-lib/failsafe You might be after something written in Clojure and that's totally fair but when it comes to retry and fault tolerance, failsafe really does deserve a mention.

🙌 2
didibus04:08:14

You actually don't need a library for retries. Here's exponential backoff with 4 attempts max:

(loop [retries [100 200 400 800]]
  (let [res
        (try :...
             (catch Exception e
               (if retries
                 (do (Thread/sleep (first retries))
                     :retry)
                 (throw e))))]
    (if (= :retry res)
      (recur (next retries))
      res)))
Very annoyingly, you can't recur inside a catch, that's why it looks a bit more weird than it should.

hiredman16:08:08

that's why you use trampoline

hiredman16:08:49

(trampoline ((fn f [tries] (try ... (catch ... f))) 0))

didibus04:08:55

I always forget about trampoline

emccue20:08:41

QQ - does anyone have or know of code live in the wild that synchronizes on keywords?

p-himik20:08:59

I'm probably not the right audience for the question since I don't know what it means. But out of curiosity - what does the question mean?

oyakushev20:08:13

(locking :synchronization-from-hell
  ...)

p-himik20:08:12

Ah, huh. That's... interesting.

oyakushev21:08:53

You can beat that with

(locking false (+ 1 2))

🚀 1
😑 1
phronmophobic21:08:33

yup, it should almost certainly be locking on draw-lock. I think that namespace was just for a proof of concept that I never finished.

Noah Bogart22:08:12

is there a reason for the question?

jpmonettas22:08:26

I guess it has to do with the fact that keywords are interned. If you do it at least on namespaced keywords then you have global monitors usable from everywhere that don't even need to require? 😛 And then grep to understand what is going on

jpmonettas22:08:22

although they are interned with WeakReferences, so no idea what happens when you are locking against an object that can be collected?

Alex Miller (Clojure team)01:08:08

Locking on interned things is deeply bad (this is a known bad pattern for Strings in Java for example). Please don’t do that :)

Alex Miller (Clojure team)01:08:48

We were musing about if keywords could become value classes in Java 24 or whenever they land. If so, they would not have identity (so also don’t do identity checks) or be lockable.

😍 1
👀 1
Alex Miller (Clojure team)01:08:53

Will get back to you in 5 yrs :)

phronmophobic20:08:14

> We were musing about if keywords could become value classes in Java 24 or whenever they land. If so, they would not have identity (so also don’t do identity checks) or be lockable. Would that be backwards incompatible with the edn spec? > If the target platform supports some notion of interning, it is a further semantic of keywords that all instances of the same keyword yield the identical object. > -- https://github.com/edn-format/edn