Comments (10)
Can we see the business situation you have, that has the unwanted side effects?
from missionary.
I can explain it simply: it's part of a spreadsheet app that evaluates code in cells. When a cell is still evaluating but the user has updated the underlying code, the current execution should be cancelled in favor of the next one.
Presently evaluation is cancelled but because the task calls success with the error, the error value becomes the cell value until the next evaluation is complete.
from missionary.
If you need the catch-all then maybe catch missionary.Cancelled before and rethrow it?
from missionary.
Thanks. I have it working now with a version of
(let [task (m/via m/blk
(try
(Thread/sleep 1000)
(catch Throwable t
:cancelled-and-should-not-succeed-or-fail)))
ignore-success? (volatile! false)
cancel (task #(when-not @ignore-success?
(println :success %))
#(println :fail %))]
(println :cancelling)
(vreset! ignore-success? true)
(cancel))
from missionary.
Not sure if this is a bug.
It is expected. The task protocol mandates calling either callback exactly once because the cancellation may not be immediate and the caller must be able to know when the process was completely shut down.
Is there a way to achieve this?
Sorry for this answer, but you should not do that. Calling tasks and flows directly is low-level and dangerous, it's OK at the app entrypoint but otherwise you should always prefer functional composition.
When a cell is still evaluating but the user has updated the underlying code, the current execution should be cancelled in favor of the next one.
Depending on the cell state you expect between the user update and the resolution of the next task, ?<
with ap
or cp
looks like a good fit, you would need to turn the task into a flow first (cf electric's offload
)
from missionary.
Interesting. This is starting to make sense. However, in my case evals are triggered on the backend as part of a transaction listener which means cells are always received as collections, e.g. similar to
(let [cells [{:cell/form-str ":foo"}
{:cell/form-str ":bar"}]]
(m/?
(->>
(m/ap
;; fork process for every cell
;; to exec in **parallel**
(let [cell (m/?> ##Inf (m/seed cells))
evaled-cell (m/? (m/timeout
(m/via m/blk
(let [{:cell/keys [cell/form-str]} cell]
(assoc cell :cell/ret (eval (read-string form-str)))))
1000
::timeout))]
(if (= evaled-cell ::timeout)
(-> cell
(dissoc :cell/ret-pending?)
(assoc :cell/exception? true
:cell/ret evaled-cell
:cell/ret-str (pr-str evaled-cell)))
evaled-cell)))
(m/reduce
(fn [out v]
(println v))
[]))))
; prints
{:cell/form-str :bar, :cell/ret :bar}
{:cell/form-str :foo, :cell/ret :foo}
But code would need to be aware of each cell's identity (by :db/id
s) so that only evaluations of the same cell cancels its previous evaluation if one exists. Any way to achieve this?
from missionary.
Electric for-by is m/group-by under the hood. Have you considered modeling the spreadsheet with Electric for loops? Each cell is a signal. e/offload
lets you call side effects (managing the task, the bridge to flow, the cancellation when something upstream changes).
from missionary.
from missionary.
So what would be an approach using functional composition that would allow cell evaluations while also cancelling evals of the same cells as new cell values transfer?
from missionary.
Got it!
(time
(let [delays [{:id 1
:delay 1000}
{:id 2
:delay 2000}
{:id 1
:delay 500}
{:id 1
:delay 200}]]
(m/?
(->>
(m/ap
(let [[k vs] (m/?> ##Inf (m/group-by :id (m/seed delays)))
m (m/?< vs)]
(try
(m/? (m/sleep (:delay m) (assoc m :slept true)))
(catch missionary.Cancelled c
(println :cancelled m)
(m/amb)))))
(m/reduce
(fn [out v]
(println v)
(conj out v))
[])))))
:cancelled {:id 1, :delay 1000}
:cancelled {:id 1, :delay 500}
{:id 1, :delay 200, :slept true}
{:id 2, :delay 2000, :slept true}
"Elapsed time: 2004.552279 msecs"
=> [{:id 1, :delay 200, :slept true} {:id 2, :delay 2000, :slept true}]
from missionary.
Related Issues (20)
- Doc strings with empty or malformed code blocks
- Consider fairness for `sem`, `dfv`, `mbx`, `rdv`
- discourage unbounded queues - `mbx`, `blk`
- ClojureDart and Flutter HOT 2
- Cannot set properties of undefined (setting 'parent') HOT 2
- Cannot read properties of null (reading 'parallelism')
- nullpointerexception with subscribe HOT 6
- `m/sleep` does not terminate after exception HOT 1
- missionary.Cancelled not thrown HOT 6
- `m/mbx` on post can return non-nil value, the docs say otherwise
- `ap` bug
- Cancel in example for basic walkthrough doesn't work HOT 3
- watch can discard latest value
- Hello task example prints only Hello with Clojure repl HOT 4
- generalize `signal` to any semigroup HOT 1
- `observe` - on JVM, consider parking the caller thread instead of throwing when pipeline is busy HOT 2
- make `ap` switch consistent with `cp` HOT 1
- `stream` double subscriptions - document correct pattern + investigate bug
- cycles in continuous time - distill the essence of problem, find correct patterns and provide helpers
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from missionary.