### Reduce flow with an initial value Source: https://context7.com/leonoel/missionary/llms.txt Demonstrates using `m/reduce` with an initial accumulator value. This example adds numbers from a flow to a starting value of 100. ```clojure ;; With initial value (m/? (m/reduce + 100 (m/seed (range 5)))) ;; => 110 ``` -------------------------------- ### Example Connection Attempt Source: https://github.com/leonoel/missionary/wiki/Happy-eyeballs Demonstrates how to use the `connect` function to establish a connection to 'clojure.org' on port 80 with a 300ms delay. ```clojure (m/? (connect "clojure.org" 80 300)) ``` -------------------------------- ### Start Clojure REPL with Missionary Dependency Source: https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows Starts a Clojure REPL session with the Missionary library added as a dependency. ```shell clj -Sdeps '{:deps {missionary/missionary {:mvn/version "b.31"}}}' ``` -------------------------------- ### Throttle Usage Example Source: https://github.com/leonoel/missionary/wiki/Debounce-and-Throttle Demonstrates the usage of the throttle function with the generated input. It collects all throttled events into a list. ```clojure (tests (m/? (->> input (throttle 50) (m/reduce conj))) := [0 4 5 9 10 14 15 19 20 24]) ``` -------------------------------- ### Start ClojureScript REPL with Missionary Dependency Source: https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows Starts a ClojureScript REPL session with ClojureScript and Missionary libraries added as dependencies. ```shell clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.11.60"} missionary/missionary {:mvn/version "b.31"}}}' -M -m cljs.main ``` -------------------------------- ### Connect Function and Example Usage Source: https://github.com/leonoel/missionary/blob/master/doc/guides/happy_eyeballs.md A convenience function to initiate a connection using Happy Eyeballs and an example demonstrating its usage with a specific host, port, and delay. ```clojure (defn connect [^String host port delay] (m/sp (m/? (happyeyeballs delay close! (m/? (connectors host port)))))) ``` ```clojure (m/? (connect "clojure.org" 80 300)) ``` -------------------------------- ### Hello World with Missionary and Drain Macro Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md A simplified 'Hello World' example using the `drain` macro to reduce the boilerplate for side-effecting flow consumption. ```clojure (drain (m/ap (println (m/?> (m/seed ["Hello" "World"]))))) ``` -------------------------------- ### Debounce Usage Example Source: https://github.com/leonoel/missionary/wiki/Debounce-and-Throttle Demonstrates the usage of the debounce function with the generated input. It collects all debounced events into a list. ```clojure (tests (m/? (->> input (debounce 50) (m/reduce conj))) := [4 9 14 19 24]) ``` -------------------------------- ### Executing and Reducing Iterative Query Results Source: https://github.com/leonoel/missionary/blob/master/doc/guides/iterative_queries.md Example of executing the iterative `pages` function and reducing the results using `m/eduction` and `m/reduce`. ```clojure (m/? (->> (pages) (m/eduction (map count)) (m/reduce +))) ``` -------------------------------- ### Sequentially Compose Tasks with `sp` and `?` Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/hello_task.md This example demonstrates sequential composition by using the `sp` macro to combine multiple actions, including printing messages and pausing with `m/? nap`. Note that `?` inside `sp` is handled asynchronously. ```clojure (def slowmo-hello-world (m/sp (println "Hello") (m/? nap) (println "World") (m/? nap) (println "!"))) ``` -------------------------------- ### Core.async Channel Flow Example Source: https://github.com/leonoel/missionary/wiki/Creating-flows Demonstrates creating a continuous flow from a core.async channel. Use this for processing an unbounded stream of data. The `take!` function handles channel closure by throwing an exception. ```clojure (defn print-drain [f] (m/reduce println f)) (defn print-call [t] (t println println)) (defn forever [task] (m/ap (m/? (m/?> (m/seed (repeat task)))))) (defn- take! [chan] (m/via m/blk (let [r (async/ (channel-flow ch)))))) (async/put! ch "new val 1") ;; prints "nil new val 1" (async/put! ch "new val 2") ;; prints "nil new val 2" (async/close! ch) ;; exception - take cancelled, channel closed ;; OR (cancel) ;; java.lang.InterruptedException ) ``` -------------------------------- ### Apply transducers to a flow with `eduction` Source: https://context7.com/leonoel/missionary/llms.txt Applies standard Clojure transducers to a discrete flow. This example uses `filter`, `mapcat`, and `partition-all` to transform the data stream before reducing it. ```clojure (m/? (->> (m/seed (range 10)) (m/eduction (filter odd?) (mapcat range) (partition-all 4)) (m/reduce conj))) ``` -------------------------------- ### Hello World with Missionary Flow Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Uses Missionary's `seed`, `?>`, `ap`, and `reduce` to achieve the same 'Hello World' output as the RxJava example. The `?>` operator forks execution for each item. ```clojure (m/? (m/reduce (constantly nil) (m/ap (println (m/?> (m/seed ["Hello" "World"])))))) ``` -------------------------------- ### Concurrent Task Execution with `m/join` Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/hello_task.md Use `m/join` to run multiple tasks concurrently and combine their results. This example demonstrates running two 'slowmo-hello-world' tasks. ```clojure (def chatty-hello-world (m/join vector slowmo-hello-world slowmo-hello-world)) (m/? chatty-hello-world) ``` -------------------------------- ### Run a Task and Get its Result Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/hello_task.md The `?` function executes a given task and returns its result. This is used to trigger the action defined by a task. ```clojure (m/? hello-world) ``` -------------------------------- ### Filter and take elements using `eduction` Source: https://context7.com/leonoel/missionary/llms.txt Combines transducers with `m/eduction` to process a flow. This example filters for even numbers and then takes the first five, demonstrating how transducers can enable early termination and efficient processing. ```clojure ;; Take first 5 even numbers (m/? (m/reduce conj (m/eduction (filter even?) (take 5) (m/seed (range 100))))) ``` -------------------------------- ### RxJava Atomic Counter Example Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Demonstrates using RxJava to count elements processed in a stream before proceeding. Requires RxJava and AtomicInteger. ```java AtomicInteger count = new AtomicInteger(); Observable.range(1, 10) .doOnNext(ignored -> count.incrementAndGet()) .ignoreElements() .andThen(Single.fromCallable(() -> count.get())) .subscribe(System.out::println); ``` -------------------------------- ### Reactive Computation with Signals and Effects in Clojure Source: https://github.com/leonoel/missionary/blob/master/README.md Demonstrates setting up a reactive computation using Missionary signals. It involves watching an atom, deriving a signal from it, and performing a discrete effect (printing) on successive values. The setup includes defining a cleanup function. ```clojure (require '[missionary.core :as m]) (def !input (atom 1)) (def main ; this is a reactive computation, the println reacts to input changes (let [ 45 ``` -------------------------------- ### RxJava: Sorted distinct characters Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Adds `sorted()` to the distinct characters example to output them in alphabetical order. Requires RxJava library. ```java .flatMap(word -> Observable.from(word.split(""))) .distinct() .sorted() .zipWith(Observable.range(1, Integer.MAX_VALUE), (string, count) -> String.format("%2d. %s", count, string)) .subscribe(System.out::println); ``` -------------------------------- ### Asynchronous Flow Processing in Clojure Source: https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows Generates 1000 values asynchronously and consumes them as they become available. This example demonstrates parallel task execution and flow reduction. ```clj (let [begin (System/currentTimeMillis) ;; create a flow of values generated by asynchronous tasks inputs (repeat 1000 (m/via m/cpu "hi")) ;; a task has no identity, it can be reused values (m/ap (let [flow (m/seed inputs) ;; create a flow of tasks to execute task (m/?> ##Inf flow)] ;; from here, fork on every task in **parallel** (m/? task))) ;; get a forked task value when available ;; drain the flow of values and count them n (m/? ;; tasks are executed, and flow is consume here! (m/reduce (fn [acc v] (assert (= "hi" v)) (inc acc)) 0 values))] (println "Read" n "msgs in" (- (System/currentTimeMillis) begin) "ms")) ``` -------------------------------- ### Emit items from a collection with delays using `ap` Source: https://context7.com/leonoel/missionary/llms.txt Constructs a discrete flow that processes each item from a collection asynchronously. This example emits the square of each number from a seed collection after a delay, demonstrating `ap` and `?>` for forking. ```clojure ;; Emit each item from a collection with a 100ms delay (m/? (m/reduce conj (m/ap (let [x (m/?> (m/seed [1 2 3]))] (m/? (m/sleep 100 (* x x))))))) ;; => [1 4 9] (after 300ms) ``` -------------------------------- ### `signal` — Hot Continuous Publisher Source: https://context7.com/leonoel/missionary/llms.txt Creates a publisher that shares a single continuous flow process among all subscribers. Subscribers sample the latest value; intermediate values not consumed by slow subscribers are merged. The underlying flow starts on the first subscriber connection and stops when the last unsubscribes. ```APIDOC ## `signal` — Hot Continuous Publisher Creates a **publisher** that shares a single continuous flow process among all subscribers. Subscribers sample the latest value; intermediate values not consumed by slow subscribers are merged via `sg` (default: discard all but latest). The underlying flow starts when the first subscriber connects and stops when the last unsubscribes. ```clojure (def !input (atom 1)) ;; signal publishes across subscribers, glitch-free diamond graph (def Observable.from(word.split(""))) .distinct() .zipWith(Observable.range(1, Integer.MAX_VALUE), (string, count) -> String.format("%2d. %s", count, string)) .subscribe(System.out::println); ``` -------------------------------- ### Get successive changes from a flow Source: https://github.com/leonoel/missionary/wiki/Continuous-flows Pass a flow to an operator expecting a discrete flow, such as `reduce`, to process successive changes. ```clojure (m/reduce (fn [_ c] (println (str "clicked " c " times."))) nil click-count) ``` -------------------------------- ### Define Exponential Backoff Delays Source: https://github.com/leonoel/missionary/blob/master/doc/guides/retry_backoff.md Create a sequence of retry delays that starts at 1000ms and doubles with each subsequent retry, for a total of 5 retries. ```clojure (def delays ;; Our backoff strategy : (->> 1000 ;; first retry is delayed by 1 second (iterate (partial * 2)) ;; exponentially grow delay (take 5))) ;; give up after 5 retries ``` -------------------------------- ### Define Drain Macro for Missionary Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md A helper macro to reduce boilerplate when draining a Missionary flow for side effects, simplifying subsequent examples. ```clojure (defmacro drain [flow] `(m/? (m/reduce (constantly nil) ~flow))) ``` -------------------------------- ### Preemptive Fork in `ap` with `?<` for Debounce Source: https://context7.com/leonoel/missionary/llms.txt Used for switch/debounce patterns. When upstream produces a new value, the current branch is cancelled before starting the new one. ```clojure (import 'missionary.Cancelled) ;; Debounce: emit only values not followed by another within `delay` ms (defn debounce [delay flow] (m/ap (let [x (m/?< flow)] (try (m/? (m/sleep delay x)) (catch Cancelled _ (m/amb)))))) (m/? (->> (m/ap (let [n (m/amb 24 79 67 34 18 9 99 37)] (m/? (m/sleep n n)))) (debounce 50) (m/reduce conj))) ;; => [24 79 9 37] ``` -------------------------------- ### Define Exponential Backoff Delays Source: https://github.com/leonoel/missionary/wiki/Retry-with-backoff Create a sequence of retry delays that starts at 1 second and doubles with each subsequent retry, giving up after 5 retries. ```clojure (def delays (->> 1000 (iterate (partial * 2)) (take 5))) ``` -------------------------------- ### Create Basic Missionary Tasks Source: https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows Demonstrates the creation of a simple sleep task and a timeout task. ```clojure (m/sleep 800) ; a sleep task ``` ```clojure (m/timeout (m/sleep 1000) 800) ; a timeout task ``` -------------------------------- ### Zip Missionary Flows Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Achieves the same result as the RxJava zip example by using Missionary's `zip` function with `seed` for both the words and the range of numbers. ```clojure (let [words ["the" "quick" "brown" "fox" "jumped" "over" "the" "lazy" "dog"]] (drain (m/ap (println (m/?> (m/zip (partial format "%2d. %s") (m/seed (range 1 100)) (m/seed words))))))) ``` -------------------------------- ### Solution: Iterative Page Fetching with Loop Source: https://github.com/leonoel/missionary/wiki/Iterative-queries This solution uses an explicit loop to manage iteration, keeping stack frames under control. It emits pages iteratively and stops when the end of the stream is detected. ```clojure (defn pages ([] (pages :start)) ([id] (m/ap (loop [id id] (let [{:keys [page next]} (m/? (api id))] ;; fetch current page and next id (if next ;; detect end of stream (m/amb> page (recur next)) ;; if not over, emit the page and continue page)))))) ;; otherwise, emit the page and stop ``` -------------------------------- ### Take a snapshot of a flow Source: https://github.com/leonoel/missionary/wiki/Continuous-flows Derive a flow using `eduction` and `take 1` to extract the value at subscription time, as flows do not implement `deref`. ```clojure (def current-click-count (m/eduction (take 1) click-count)) ``` -------------------------------- ### Handling Unreliable Tasks with `m/join` Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/hello_task.md Demonstrates how `m/join` propagates errors from concurrent tasks. The `unreliable-hello-world` task is designed to fail. ```clojure (def unreliable-hello-world (m/sp (println "Hello") (m/? (m/sleep 500)) (throw (ex-info "Something went wrong." {})))) (m/? unreliable-hello-world) ``` ```clojure (def unreliable-chatty-hello-world (m/join vector slowmo-hello-world unreliable-hello-world)) (m/? unreliable-chatty-hello-world) ``` -------------------------------- ### `?<` — Preemptive (Switching) Fork in `ap` Source: https://context7.com/leonoel/missionary/llms.txt Similar to `?>` but preemptive. When the upstream produces a new value, the current branch is cancelled before starting the new one. Useful for switch/debounce patterns. ```APIDOC ## `?<` — Preemptive (Switching) Fork in `ap` Like `?>` but **preemptive**: when the upstream produces a new value, the current branch is cancelled before starting the new one. Used for switch/debounce patterns. ```clojure (import 'missionary.Cancelled) ;; Debounce: emit only values not followed by another within `delay` ms (defn debounce [delay flow] (m/ap (let [x (m/?< flow)] (try (m/? (m/sleep delay x)) (catch Cancelled _ (m/amb)))))) (m/? (m/reduce conj (m/ap (let [n (m/amb 24 79 67 34 18 9 99 37)] (m/? (m/sleep n n)))) (debounce 50))) ;; => [24 79 9 37] ;; Throttle: emit first of each burst, discard rest until delay elapses (defn throttle [dur >in] (m/ap (let [x (m/?> (m/relieve {} >in))] (m/amb x (do (m/? (m/sleep dur)) (m/amb)))))) ``` ``` -------------------------------- ### sp — Sequential Process (task constructor macro) Source: https://context7.com/leonoel/missionary/llms.txt `sp` wraps Clojure forms into a task, a deferred, cancellable, asynchronous computation. Use `?` within `sp` to park on other tasks. The macro rewrites the body into continuation-passing style, preventing thread blocking. ```APIDOC ## sp — Sequential Process (task constructor macro) ### Description Wraps a body of Clojure forms into a **task**: a value representing a deferred, cancellable, asynchronous computation that eventually completes with a result or fails with an exception. Inside `sp`, use `?` to park on other tasks. The macro rewrites the body into continuation-passing style, so no thread is blocked. ### Usage ```clojure (require '[missionary.core :as m]) ;; A simple sequential task (def greet (m/sp (println "Hello") (m/? (m/sleep 1000)) ; park for 1 second, no thread blocked (println "World") 42)) ;; Run it: pass success and failure callbacks (def cancel! (greet #(prn :result %) #(prn :error %))) ;; Hello ;; (1 second later) ;; World ;; :result 42 ;; Or block calling thread (Clojure only, not ClojureScript) (m/? greet) ;; => 42 ;; Error handling with try/finally (works across park points) (def safe-task (m/sp (try (m/? (m/via m/blk (slurp "data.txt"))) ; blocking IO on blk executor (catch Exception e (prn :error (ex-message e)) "default") (finally (prn :cleanup))))) ; runs even on cancellation (m/? safe-task) ;; :cleanup ;; => "default" ``` ``` -------------------------------- ### Hot Discrete Publisher with `stream` Source: https://context7.com/leonoel/missionary/llms.txt Creates a publisher that shares a single discrete flow process, distributing each item to all current subscribers while collecting backpressure. ```clojure ;; Shared clock emitting nil every second (def >clock (m/stream (m/ap (loop [] (m/amb (m/? (m/sleep 1000)) (recur)))))) ;; Two independent subscribers, both receive all ticks ((m/join vector (m/reduce (fn [r _] (inc r)) 0 (m/eduction (take 3) >clock)) (m/reduce (fn [r _] (inc r)) 0 (m/eduction (take 4) >clock))) prn prn) ;; After 4 seconds → [3 4] ``` -------------------------------- ### Async data fetching with `ap` and `via` Source: https://context7.com/leonoel/missionary/llms.txt Uses the `ap` macro to construct a flow that fetches data asynchronously for each item in a collection. `?>` forks the process for each ID, and `m/via` offloads the database fetch to the `m/blk` executor. ```clojure ;; FlatMap pattern: for each item fetch async data (def results (m/ap (let [id (m/?> (m/seed [10 20 30])) data (m/? (m/via m/blk (fetch-by-id db id)))] {:id id :data data}))) (m/? (m/reduce conj results)) ``` -------------------------------- ### Blocking Operations in Parallel Execution Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/hello_task.md Shows the issue of blocking threads when running multiple blocking tasks concurrently without proper executor management. This example uses `Thread/sleep`. ```clojure (defn blocking-hello-world [] (println "Hello") (Thread/sleep 500) (println "World")) (time (m/? (m/join vector (m/sp (blocking-hello-world)) (m/sp (blocking-hello-world))))) ``` -------------------------------- ### Apply Transducer to a Flow Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/hello_flow.md Use `eduction` to apply a transducer, such as `partition-all`, to a flow. This processes the flow's elements in batches. ```clojure (m/? (m/reduce conj (m/eduction (partition-all 4) input))) #_=> [[0 1 2 3] [4 5 6 7] [8 9]] ``` -------------------------------- ### Observe discrete events Source: https://github.com/leonoel/missionary/wiki/Continuous-flows Use `observe`, `reductions`, and `relieve` to process discrete events like clicks. `relieve` with `{}` discards the oldest values. ```clojure (def click-events (m/observe (fn [!] (.addEventListener js/window "click" !) #(.removeEventListener js/window "click" !)))) (def click-count (->> click-events (m/reductions (fn [r _] (inc r)) 0) (m/relieve {}))) ``` -------------------------------- ### Run Reductions on a Flow Source: https://context7.com/leonoel/missionary/llms.txt Emits the initial value followed by each successive reduction. Use when you need to see intermediate reduction results. ```clojure (m/? (->> (m/seed [1 2 3 4 5]) (m/reductions +) (m/reduce conj))) ;; => [0 1 3 6 10 15] ``` ```clojure ;; Running count of events (def event-count (->> event-flow (m/reductions (fn [n _] (inc n)) 0))) ``` -------------------------------- ### Compose Tasks Sequentially with `m/?` Source: https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows Composes multiple tasks within a sequential process block, executing them and waiting for their results using `m/?`. ```clojure (m/sp (println "Let's take a nap...") (str (m/? (m/sleep 900 "Hi ")) (m/? (m/sleep 100 "there!")))) ``` -------------------------------- ### Memoized Task Publisher with `memo` Source: https://context7.com/leonoel/missionary/llms.txt Runs a task exactly once; all subscribers share the single result. Subsequent subscriptions complete immediately with the cached result. ```clojure (def expensive-result (m/memo (m/via m/cpu (println "computing...") (reduce + (range 1e8))))) (expensive-result prn prn) ;; prints "computing..." then result (expensive-result prn prn) ;; result returned immediately, no recompute ``` -------------------------------- ### Ensuring Actions with `finally` in Missionary Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/hello_task.md Illustrates using `try`/`finally` within a sequential task to guarantee execution of cleanup actions, even when other concurrent tasks fail. ```clojure (def finally-hello-world (m/sp (try (println "Hello") (m/? nap) (println "World") (m/? nap) (finally (println "!"))))) (m/? (m/join vector unreliable-hello-world finally-hello-world)) ``` -------------------------------- ### Concurrent forking with limited parallelism using `ap` Source: https://context7.com/leonoel/missionary/llms.txt Demonstrates concurrent execution of tasks within an `ap` flow, limited by the number of available seeds. The results are collected in completion order, showcasing how `ap` manages parallel processing. ```clojure ;; Concurrent forking with parallelism limit (m/? (m/reduce conj (m/ap (let [ms (m/?> 3 (m/seed [300 100 400 200]))] (m/? (m/sleep ms ms)))))) ``` -------------------------------- ### Input Data Generation Source: https://github.com/leonoel/missionary/wiki/Debounce-and-Throttle Generates a sequence of 25 integers, divided into 5 bursts of 5, with simulated delays. ```clojure (def input (->> (m/ap (m/? (m/sleep (m/?> (m/seed (cycle [100 10 10 10 10])))))) (m/eduction (take 25) (map-indexed (fn [i _] i))))) ``` -------------------------------- ### ? — Park / Run a Task Source: https://context7.com/leonoel/missionary/llms.txt `?` runs a task inside an `sp` (or `ap`) block, suspending the current process until the task completes. At the top level (Clojure only), `?` blocks the calling thread and returns the result or rethrows the exception. ```APIDOC ## ? — Park / Run a Task ### Description Runs a task inside an `sp` (or `ap`) block, suspending the current process until the task completes. At the top level (Clojure only), `?` blocks the calling thread and returns the result or rethrows the exception. ### Usage ```clojure ;; Top-level: block and return result (m/? (m/sleep 500 :done)) ;; => :done (after 500ms) ;; Inside sp: park without blocking a thread (m/? (m/sp (let [a (m/? (m/sleep 100 :a)) b (m/? (m/sleep 100 :b))] [a b]))) ;; => [:a :b] (after 200ms, sequentially) ``` ``` -------------------------------- ### First-completes task with `any` Source: https://context7.com/leonoel/missionary/llms.txt Runs multiple tasks concurrently and completes as soon as the first task finishes, regardless of whether it succeeds or fails. The result is either the successful value or the exception from the first completed task. ```clojure ;; any: first to complete wins (success or failure) ((m/any (m/sp (m/? (m/sleep 2000)) :foo) (m/sp (m/? (m/sleep 1000)) (throw (ex-info "Error" {})))) prn #(prn :failure)) ``` -------------------------------- ### Network Connection Helper Functions Source: https://github.com/leonoel/missionary/wiki/Happy-eyeballs Provides utility functions for network operations, including creating a socket connector, resolving endpoints, generating a sequence of connectors for a host, and closing a socket. ```clojure (defn connector [^java.net.InetAddress addr port] (m/via m/blk (java.net.Socket. addr (int port)))) ``` ```clojure (defn endpoints [^String host] (m/via m/blk (java.net.InetAddress/getAllByName host))) ``` ```clojure (defn connectors [^String host port] (m/sp (map #(connector % port) (m/? (endpoints host))))) ``` ```clojure (defn close! [^java.net.Socket socket] (.close socket)) ``` -------------------------------- ### Create Task from Sequential Forms Source: https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows Creates a task from a body of sequential forms using `m/sp`. ```clojure (m/sp (println "one") :two) ``` -------------------------------- ### Group Flow by Key with `group-by` Source: https://context7.com/leonoel/missionary/llms.txt Partitions values of a discrete flow by a key, creating a new flow for each group. Groups are dispatched in constant time. ```clojure (def words ["Air" "Bud" "Cup" "Awake" "Break" "Chunk" "Ant" "Big" "Check"]) (def grouped (m/ap (let [[k >x] (m/?> (m/group-by (juxt first count) (m/seed words)))] [k (m/? (m/reduce conj >x))])))) (m/? (m/reduce conj {} grouped)) ;; => {["C" 3] ["Cup"], ["B" 5] ["Break"], ["A" 5] ["Awake"], ;; ["B" 3] ["Bud" "Big"], ["A" 3] ["Air" "Ant"], ["C" 5] ["Chunk" "Check"]} ``` -------------------------------- ### Ignore Source and Run Next (RxJava) Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Ignores all elements from an observable and then proceeds with another source using `ignoreElements` and `andThen`. Returns a `Completable`. ```java sourceObservable .ignoreElements() // returns Completable .andThen(someSingleSource) .map(v -> v.toString()) ``` -------------------------------- ### Process Numbers in Parallel (RxJava - flatMap) Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Processes numbers from 1 to 10, squaring each in parallel using `flatMap` and `subscribeOn(Schedulers.computation())`. Results are printed sequentially. ```java Flowable.range(1, 10) .flatMap(v -> Flowable.just(v) .subscribeOn(Schedulers.computation()) .map(w -> w * w) ) .blockingSubscribe(System.out::println); ``` -------------------------------- ### Missionary Project Dependency in Clojure Source: https://github.com/leonoel/missionary/blob/master/README.md Shows how to add the Missionary library as a dependency in a Clojure project using the deps.edn format. ```clojure {:deps {missionary/missionary {:mvn/version "b.47"}}} ``` -------------------------------- ### Create and Reduce a Flow Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/hello_flow.md Build a flow from a range of numbers and reduce it to a single sum. The `m/?` function is used to execute the task and retrieve its result. ```clojure ;; A flow producing the 10 first integers (def input (m/seed (range 10))) ;; A task producing the sum of the 10 first integers (def sum (m/reduce + input)) (m/? sum) #_=> 45 ``` -------------------------------- ### Process Numbers in Parallel (Missionary - ordered) Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Processes numbers from 1 to 10, squaring each in parallel on the CPU executor. Results are collected and joined in order. ```clojure (apply m/join vector (m/? (m/reduce conj (m/eduction (map #(m/via m/cpu (* % %))) (m/seed (range 1 11)))))) ``` -------------------------------- ### Backpressured Flow with rdv Source: https://github.com/leonoel/missionary/wiki/Creating-flows Illustrates creating a backpressured flow using a rendezvous (rdv) mechanism. This is useful when the producer needs to wait for the consumer to be ready. The `m/?` call blocks until the flow is ready. ```clojure (defn rdv-flow [rdv] (forever rdv)) (comment (def rdv (m/rdv)) (def cancel (print-call (print-drain (rdv-flow rdv)))) (m/? (rdv "val 1")) ;; prints nil val 1, blocks until flow is ready to accept new value (cancel)) ``` -------------------------------- ### `group-by` — Partition Flow by Key Source: https://context7.com/leonoel/missionary/llms.txt Groups values of a discrete flow by a key, producing `[key group-flow]` pairs. Each group is a discrete flow consuming matching values and are dispatched in constant time. ```APIDOC ## `group-by` — Partition Flow by Key Groups values of a discrete flow by key, producing `[key group-flow]` pairs. Each group is itself a discrete flow consuming matching values. Groups are dispatched in constant time. ```clojure (def words ["Air" "Bud" "Cup" "Awake" "Break" "Chunk" "Ant" "Big" "Check"]) (def grouped (m/ap (let [[k >x] (m/?> (m/group-by (juxt first count) (m/seed words)))] [k (m/? (m/reduce conj >x))]))) (m/? (m/reduce conj {} grouped)) ;; => {["C" 3] ["Cup"], ["B" 5] ["Break"], ["A" 5] ["Awake"], ;; ["B" 3] ["Bud" "Big"], ["A" 3] ["Air" "Ant"], ["C" 5] ["Chunk" "Check"]} ``` ``` -------------------------------- ### Execute Task with Continuations Source: https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows Asynchronously runs a task by invoking it and processing the result using success and error continuation functions. ```clojure ((m/sp "world") #(println "Hello" %) #(println :KO %)) ; (on stdout) Hello world ``` -------------------------------- ### Execute Task on OS Thread or CPU Source: https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows Creates tasks that are executed on a specified thread pool (OS thread or CPU-bound) using `m/via`. ```clojure (m/via m/blk (Thread/sleep 5000) :done) ``` ```clojure (m/via m/cpu (+ 1 1)) ``` -------------------------------- ### Require Missionary Core Library Source: https://github.com/leonoel/missionary/wiki/Retry-with-backoff Import the necessary core functions from the missionary library. ```clojure (require '[missionary.core :as m]) ``` -------------------------------- ### Antipattern: Recursive Iterative Query Source: https://github.com/leonoel/missionary/blob/master/doc/guides/iterative_queries.md Demonstrates a recursive approach to fetching paginated data. This method can lead to stack overflows due to unbounded process hierarchy. ```clojure (defn pages ([] (pages :start)) ([id] (m/ap (let [{:keys [page next]} (m/? (api id)) ;; fetch current page and next id rest (if (some? next) (pages next) m/none)] ;; recursively build the rest of the flow (m/?> (m/reductions {} page rest)))))) ;; prepend the page and emit the result ``` -------------------------------- ### Read Task Values Sequentially in Clojure Source: https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows Creates two tasks and reads their values sequentially using `m/?` within a `let` binding. ```clojure (let [v1 (m/? (m/sp "hi")) v2 (m/? (m/sp "there"))] (printf "Read %s from %s%n" v1 v2)) ``` -------------------------------- ### Throttle Implementation Source: https://github.com/leonoel/missionary/wiki/Debounce-and-Throttle Implements throttle using 'relieve' to discard older values and 'ap' with 'sleep' to enforce a minimum delay between events. The first event of a burst is emitted immediately. ```clojure (defn throttle [dur >in] (m/ap (let [x (m/?> (m/relieve {} >in))] (m/amb x (do (m/? (m/sleep dur)) (m/amb)))))) ``` -------------------------------- ### RxJava: Split words into characters Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Uses `flatMap` to emit each character of each word on a new line. Requires RxJava library. ```java Observable.from(words) .flatMap(word -> Observable.from(word.split(""))) .zipWith(Observable.range(1, Integer.MAX_VALUE), (string, count) -> String.format("%2d. %s", count, string)) .subscribe(System.out::println); ``` -------------------------------- ### Run Computation on Background Thread (RxJava) Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Executes a computation on an IO-bound background thread and observes the result on a single (UI) thread. Requires RxJava3. ```java import io.reactivex.rxjava3.schedulers.Schedulers; Flowable.fromCallable(() -> { Thread.sleep(1000); // imitate expensive computation return "Done"; }) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.single()) .subscribe(System.out::println, Throwable::printStackTrace); Thread.sleep(2000); // <--- wait for the flow to finish ``` -------------------------------- ### Process Numbers in Parallel (Missionary - unordered) Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Processes numbers from 1 to 10, squaring each in parallel on the CPU executor. Results are collected without guaranteed order. ```clojure (m/? (m/reduce conj (m/ap (let [v (m/?= (m/seed (range 1 11)))] (m/? (m/via m/cpu (* v v))))))) ``` -------------------------------- ### Create Flow from Ambiguous Process Block Source: https://github.com/leonoel/missionary/wiki/Basic-Walkthrough:-Tasks-&-Flows Creates a flow from an ambiguous process block, demonstrating the use of `m/?>` to process values from a seeded flow. ```clojure (m/ap (println (m/?> (m/seed [1 2])))) ``` -------------------------------- ### Convert Task to JavaScript Promise Source: https://github.com/leonoel/missionary/wiki/Task-interop Creates a JavaScript `Promise` that resolves with the result of the given task. The task will run and resolve the promise upon completion. ```clojure (defn promise! "Runs given task and returns a promise completing with the result of this task" [t] (js/Promise. t)) ``` -------------------------------- ### Ambiguous Process with `ap` and `?>` Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/hello_flow.md Demonstrates the `ap` macro and `?>` operator for handling flows within an ambiguous process. `?>` pulls values sequentially, and `reduce` collects results. Note the side effect of `println`. ```clojure (def hello-world (m/ap (println (m/?> (m/seed ["Hello" "World" "!"]))) (m/? (m/sleep 1000)))) (m/? (m/reduce conj hello-world)) Hello World ! #_=> [nil nil nil] ``` -------------------------------- ### Convert Task to Java CompletableFuture Source: https://github.com/leonoel/missionary/wiki/Task-interop Creates a Java `CompletableFuture` that completes with the result of the given task. Requires a bit more glue code for interop. ```clojure (defn cf! "Runs given task and returns a CompletableFuture completing with the result of this task." [t] (let [cf (java.util.concurrent.CompletableFuture.)] (t #(.complete cf %) #(.completeExceptionally cf %)) cf)) ``` -------------------------------- ### Sequential API Calls (Missionary - tasks) Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Executes a sequence of tasks where each subsequent task depends on the result of the previous one, using `m/sp` (sequential processing). ```clojure (m/? (m/sp (->> (api-call service) m/? (another-api-call service) m/? (final-call service) m/?))) ``` -------------------------------- ### Concurrent Flow Execution with `?>` and `par` Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/hello_flow.md Demonstrates concurrent execution of flow elements using the `?>` operator with the `par` argument set to `##Inf`. Results are collected in the order they finish. ```clojure (m/? (m/reduce conj (m/ap (let [ms (m/?> ##Inf (m/seed [300 100 400 200]))] (m/? (m/sleep ms ms)))))) #_=> [100 200 300 400] ``` -------------------------------- ### `memo` — Memoized Task Publisher Source: https://context7.com/leonoel/missionary/llms.txt Runs a task exactly once; all subscribers share the single result. Subsequent subscriptions complete immediately with the cached result. ```APIDOC ## `memo` — Memoized Task Publisher Runs a task exactly once; all subscribers share the single result. Subsequent subscriptions complete immediately with the cached result. ```clojure (def expensive-result (m/memo (m/via m/cpu (println "computing...") (reduce + (range 1e8))))) (expensive-result prn prn) ;; prints "computing..." then result (expensive-result prn prn) ;; result returned immediately, no recompute ``` ``` -------------------------------- ### Turn Blocking Call into Task with Executor Source: https://github.com/leonoel/missionary/wiki/Task-interop Use `m/via` to assign an executor to a blocking call, turning it into a task. Use `m/blk` for I/O-bound and `m/cpu` for CPU-bound operations. ```clojure (m/via m/blk (slurp "https://clojure.org")) ``` ```clojure (m/via m/cpu (mine-crypto)) ``` -------------------------------- ### Process Numbers in Parallel (RxJava - parallel) Source: https://github.com/leonoel/missionary/blob/master/doc/tutorials/rx_comparison.md Processes numbers from 1 to 10, squaring each in parallel using the `parallel()` operator and `runOn(Schedulers.computation())`. Results are collected sequentially. ```java Flowable.range(1, 10) .parallel() .runOn(Schedulers.computation()) .map(v -> v * v) .sequential() .blockingSubscribe(System.out::println); ``` -------------------------------- ### Throttle Pattern with `?<` and `sleep` Source: https://context7.com/leonoel/missionary/llms.txt A throttle implementation that emits the first value of each burst and discards the rest until the delay elapses. ```clojure ;; Throttle: emit first of each burst, discard rest until delay elapses (defn throttle [dur >in] (m/ap (let [x (m/?> (m/relieve {} >in))] (m/amb x (do (m/? (m/sleep dur)) (m/amb)))))) ``` -------------------------------- ### Drive side effects with `reduce` Source: https://context7.com/leonoel/missionary/llms.txt Uses `m/reduce` to process each element of a flow and trigger a side effect, in this case, printing each element. The accumulator is `nil` as the primary purpose is the side effect. ```clojure ;; Drive a side effect (print each value) (m/? (m/reduce (fn [_ x] (prn x)) nil (m/seed [:a :b :c]))) ``` -------------------------------- ### Solution: Iterative Query with Explicit Loop Source: https://github.com/leonoel/missionary/blob/master/doc/guides/iterative_queries.md An iterative solution using `loop` to manage state and avoid stack overflows. This approach creates a single process that manages the iteration explicitly. ```clojure (defn pages ([] (pages :start)) ([id] (m/ap (loop [id id] (let [x (->> [:page :next] (map (m/? (api id))) ;; fetch current page and next id (remove nil?) (m/seed) (m/?>))] (if (uuid? x) (recur x) x)))))) ``` -------------------------------- ### Put Value on core.async Channel as Task Source: https://github.com/leonoel/missionary/wiki/Task-interop Puts a value onto a `core.async` channel and returns a task that completes with `true` if the put was accepted, or `false` if the channel was closed. ```clojure (require '[clojure.core.async :as a]) (defn >! "Puts given value on given channel, returns a task completing with true when put is accepted, of false if port was closed." [c x] (doto (m/dfv) (->> (a/put! c x)))) ```