Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

immediate switch #68

Closed
leonoel opened this issue Jul 7, 2022 · 3 comments
Closed

immediate switch #68

leonoel opened this issue Jul 7, 2022 · 3 comments

Comments

@leonoel
Copy link
Owner

leonoel commented Jul 7, 2022

The current behavior of ?< is to cancel the current subprocess when the input flow is ready to transfer, then wait for the subprocess to terminate, then transfer value from input flow and create a new subprocess. Consequently :

  • any value produced by the subprocess after cancellation is passed to the main process. Especially, if the subprocess crashes on cancellation, the exception must be caught by the user otherwise the whole process crashes, and a meaningful value has to be produced instead which is not always possible (this problem can be mitigated with amb in ap but not in cp)
  • the actual switch should be expected to be delayed if the subprocess doesn't terminate immediately.

Alternative design : ?< spawns a new subprocess immediately when the input flow is ready to transfer. The previous subprocess is detached from the main process, it is cancelled and flushed (ie consumed as fast as possible, values are discarded and exceptions ignored). This implies the switch parent process must keep track of all of its concurrent stale subprocesses and wait for all of them to terminate before terminating itself.

Prior art : unknown. Rx has switchmap, but this subtlety is irrelevant here due to lack of graceful shutdown - each process is considered terminated immediately after cancellation.

@dustingetz
Copy link
Collaborator

(ns dustin.y2022.missionary-switch
  (:require [missionary.core :as m]
            [hyperfiddle.rcf :as rcf :refer [tests ! %]])
  (:import [missionary Cancelled]))

(hyperfiddle.rcf/enable!)

(tests

  (def >x (m/ap
            (let [>a (m/?> (m/seed (range 5)))]
              (m/?> (m/seed (range >a))))))

  (def cancel ((m/reduce conj >x) ! !))
  % := [0
        0 1
        0 1 2
        0 1 2 3])

(tests

  (def >x (m/ap
            (try
              (let [>a (m/?< (m/seed (range 5)))]
                (m/?< (m/seed (range >a))))
              (catch Cancelled _))))

  (def cancel ((m/reduce conj >x) ! !))
  ; in current design of switch, we can see the terminal emission during cancellation
  % := [nil 
        nil 
        nil
        0
        1
        2
        3])

@dustingetz
Copy link
Collaborator

TLDR: two problems with current design:

  • userland has to handle the terminal emission during cancellation
  • if the cancellation is not immediate, the switch is delayed

@leonoel
Copy link
Owner Author

leonoel commented Feb 13, 2023

Released in b.27

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants