This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-03-15
Channels
- # babashka (4)
- # beginners (136)
- # calva (63)
- # clerk (7)
- # clj-kondo (8)
- # clojure (43)
- # clojure-boston (1)
- # clojure-europe (37)
- # clojure-nl (1)
- # clojure-norway (11)
- # clojure-uk (3)
- # clojurescript (6)
- # clr (1)
- # code-reviews (16)
- # cursive (45)
- # datomic (2)
- # docker (32)
- # emacs (10)
- # events (2)
- # exercism (1)
- # fulcro (3)
- # hugsql (1)
- # hyperfiddle (47)
- # leiningen (3)
- # lsp (30)
- # malli (39)
- # missionary (1)
- # off-topic (24)
- # pathom (2)
- # portal (14)
- # practicalli (5)
- # rdf (13)
- # reagent (18)
- # reitit (18)
- # releases (7)
- # remote-jobs (1)
- # sci (2)
- # shadow-cljs (45)
- # sql (7)
- # tools-build (11)
- # xtdb (13)
Is there a way to tell from the fn which being executed inside a future that it was canceled? how the running code should be aware about need to stop?
Want to understand how handle cancelation within long running process
thanks!
main-thread
-> (future long-running-job)
what Iam looking for - how long-running-job
can get notified that it should stop?
future-cancel
interrupts the thread running the future. When a thread is interrupted, blocking calls are expected to throw. You can also poll interruption status with .isInterrupted
(future
(loop [i 0]
(when (.isInterrupted (Thread/currentThread))
(throw (InterruptedException.)))
(recur (inc i))))
ah, super thank you!
If I set the default uncaught exception handler to println or replace (throw (InterruptedException.))
with a println , nothing happens after running (future-cancel)
. What is supposed to happen when the future is cancelled? From what I've seen, nothing happens 😕
I checked the code example, .isInterrupted
doesnt work
but java.util.concurrent.CancellationException
is thrown (bubbles up on deref)
hope it helps
Just tried a try catch inside the function aiming to catch java.util.concurrent.CancellationException
s but that doesn't trigger when the future-cancel
is called. Your initial question was about the function itself knowing about being cancelled. Presumably that's still not resolved?
you need to deref
then the exception will convey up
A function can't deref itself though. I think what you're saying is outside the function?
tbh you didn't actually say anything about needing to be inside the future code. I guess dereffing and catching there is enough 🙂
(let [job-future (future (core/run executor job))]
(async/go-loop []
(if (realized? shutdown)
(future-cancel job-future)
(recur)))
(deref job-future)
(mark-completed db job)
::success)
(catch java.util.concurrent.CancellationException _
(log/info logger (str "WORKER INTERRUPTED" job))
(mark-interrupted db job)
::interrupted)
(catch Throwable t
(log/error logger t "JOB FAILED" {:type type
:exception (.getMessage t)}))
this is the code example which I think works for me (didnt test it yet)
rather than using thread interrupt, you can use an atomic boolean (or an atom containing a boolean)

(defn run-standard-consumer-loop-in-thread
"Runs a standard consumer loop in a single thread.
The arguments this accepts are the same as the arguments
accepted by `standard-consumer-loop`.
The return value of this call is a function that will interrupt
the consumer thread and block until the thread dies."
[message-consumer options]
(let [poison-pill (AtomicBoolean. false)
thread (Thread.
^Runnable
(fn []
(standard-consumer-loop
message-consumer
(assoc options
:poison-pill #(.get poison-pill))))
(str "standard-consumer-loop-"
(.getAndIncrement consumer-thread-counter)))]
(.start thread)
(fn shutdown-standard-consumer-loop
[]
(.set poison-pill true)
(.join thread))))
the only thing special about this versus thread interrupt is that you don't need to think about how other code might react to it
like if you are making an http request, the http client might just fail to function because it detects that the thread is interrupted
if you make your own flag it is a lot more predictable what will happen when you tell your thread to cancel
Is there a fn in core (or elsewhere) that given a keyword :my-ns/whatever
returns :my-ns
?
ive used (-> :foo/bar namespace keyword)
(comp keyword namespace)
Is there a simple way to write this
(let [foo (bar ,,,)] (when (pred? foo) foo))
That is, only return the value of (bar ,,,)
if it fulfills predicate pred?
Pretty sure there isn't. After all, we probably wouldn't have not-empty
otherwise. :)
That makes sense. I stumbled upon this and thought there must be an easier way. Then again, I don’t think I’ve encountered it before so it may not be a super common pattern.
I am a frequent user of not-empty
though
Right. Just superficially checked a project that has ~50kloc for \(when \([a-z0-9-]+\?
.
Only 2 instances where it's used in combination with let
, and both of those wouldn't benefit for an extra macro because the predicate depends on other data, so it would have to become a lambda.
Both cases are something like
(let [item (get-item)]
(when (contains? some-set item)
item))
when
is good. The alternative can be:
(?get-item ...)
which return item or nil depends on conditions inside the fn ?get-item
.
Then it is 1 line instead of 3, but this is much different fnand of course get-iteam
is poor name, it should be like ?get-availalbe-item
then or something like that
Wouldn’t have to be a macro though. Nevertheless, I agree that there is probably little need
Since foo
must be evaluated regardless, and (pred? foo)
must also be evaluated regardless, there is no reason this needs to be a macro.
It is trivial to capture the logic in a simple reusable function.
(defn when? [pred x]
(when (pred x) x))
(let [pred boolean
bar identity]
{:truthy (when? pred (bar :foo))
:falsey (when? pred (bar false))})
; =>
{:truthy :foo,
:falsey nil}