### Semaphore Example Usage Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/quick-reference.md Demonstrates the basic usage of a semaphore: creation, acquisition, performing work, and release. ```clojure (def sem (psm/create :permits 5)) (psm/acquire sem) (do-work) (psm/release sem) ``` -------------------------------- ### Sequential Map Comparison Source: https://github.com/funcool/promesa/blob/master/doc/executors.md This example demonstrates the performance difference between sequential `map` and parallel `px/pmap` for a slow function. ```clojure (time (doall (map slow-inc (range 10)))) ``` -------------------------------- ### Create and Start a Thread with fn->thread Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Use `fn->thread` to create and optionally start a new unpooled thread executing a given function. You can specify thread options like name, priority, and whether it's a daemon or virtual thread. ```clojure (fn->thread f & {:keys [start] :or {start true} :as options}) ``` ```clojure (px/fn->thread (fn [] (println "running")) :name "worker") ;; => Thread instance (already started) ``` ```clojure (px/fn->thread (fn [] 42) :start false) ;; => Thread instance (not started) ``` -------------------------------- ### Run ClojureScript Tests Source: https://github.com/funcool/promesa/blob/master/README.md Setup and run the ClojureScript tests using yarn. ```shell corepack enable corepack install yarn install yarn run test ``` -------------------------------- ### Run Tests on JS Platform Source: https://github.com/funcool/promesa/blob/master/doc/contributing.md Install Node.js dependencies and run tests for the Promesa project on the JavaScript platform. ```bash npm install npm test ``` -------------------------------- ### Basic Promise Usage in REPL Source: https://github.com/funcool/promesa/blob/master/README.md Demonstrates creating a promise, mapping a function over it, and dereferencing the result. Note: This example works on JVM due to blocking primitives. ```clojure (require '[promesa.core :as p]) (->> (p/promise 1) (p/map inc) (deref) ;; => 2 ``` -------------------------------- ### Create and Start a Thread with thread Macro Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md The `thread` macro creates and starts an unpooled thread to run a body of code. It supports optional parameters for thread naming, priority, daemon status, and virtual threads. ```clojure (thread & body) ``` ```clojure (thread {:keys [name priority daemon virtual]} & body) ``` ```clojure (px/thread (println "hello from thread")) ;; => Thread instance ``` ```clojure (px/thread {:name "worker" :daemon false} (Thread/sleep 1000) (println "done")) ``` -------------------------------- ### Database Connection Pool Management Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/semaphore.md Example of using a semaphore to limit the number of concurrent database connections, ensuring efficient resource utilization. ```clojure (def max-connections 20) (def connection-sem (psm/create :permits max-connections)) (defn with-connection [f] (psm/acquire connection-sem) (try (let [conn (get-connection)] (try (f conn) (finally (return-connection conn)))) (finally (psm/release connection-sem)))) (with-connection (fn [conn] (execute conn "SELECT * FROM users"))) ``` -------------------------------- ### Handle Bulkhead Capacity Errors with Fallback Source: https://github.com/funcool/promesa/blob/master/_autodocs/errors.md Implement a strategy to handle `capacity-limit-reached` errors from a bulkhead executor. This example submits the task to a cached executor as a fallback. ```clojure (require '[promesa.exec.bulkhead :as pxb] '[promesa.exec :as px]) (def bh (pxb/create :type :async :permits 1 :queue 5)) (defn submit-with-fallback [f] (try (px/submit bh f) (catch clojure.lang.ExceptionInfo e (if (= (:code (ex-data e)) :capacity-limit-reached) (px/submit :cached f) ;; Use cached executor as fallback (throw e))))) ``` -------------------------------- ### thread Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Macro that creates and starts an unpooled thread running the provided body. Allows configuration of thread name, priority, daemon status, and virtual threads. ```APIDOC ## thread ### Description Macro that creates and starts an unpooled thread running the provided body. Allows configuration of thread name, priority, daemon status, and virtual threads. ### Signatures ```clojure (thread & body) (thread {:keys [name priority daemon virtual]} & body) ``` ### Parameters #### Options - **name** (string) - Optional - Optional thread name - **priority** (int) - Optional - Optional thread priority - **daemon** (boolean) - Optional - Optional daemon flag - **virtual** (boolean) - Optional - Use virtual threads ### Returns Started Thread instance. ### Example ```clojure (px/thread (println "hello from thread")) ;; => Thread instance (px/thread {:name "worker" :daemon false} (Thread/sleep 1000) (println "done")) ``` ``` -------------------------------- ### Create a Resolved Promise Source: https://github.com/funcool/promesa/blob/master/_autodocs/INDEX.md Use `p/resolved` to create a promise that is immediately resolved with a value. The `@` reader macro dereferences the promise to get its value. ```clojure (require '[promesa.core :as p]) @(p/resolved 42) ;; => 42 ``` -------------------------------- ### Get Bulkhead Statistics Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Retrieves current statistics for a bulkhead, including available permits, queued tasks, and maximum limits. This is useful for monitoring the bulkhead's state. ```clojure (def bh (pxb/create :type :async :permits 5)) (px/submit bh (fn [] (Thread/sleep 1000))) (px/submit bh (fn [] (Thread/sleep 1000))) (pxb/get-stats bh) ``` -------------------------------- ### fn->thread Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Creates and optionally starts a new unpooled thread executing a given function. Supports configuration of thread name, priority, daemon status, and virtual threads. ```APIDOC ## fn->thread ### Description Creates and optionally starts a new unpooled thread executing the function `f`. Supports configuration of thread name, priority, daemon status, and virtual threads. ### Signature ```clojure (fn->thread f & {:keys [start] :or {start true} :as options}) ``` ### Parameters #### Options - **f** (fn) - Required - Function to execute - **start** (boolean) - Optional - Default: `true` - Whether to start the thread immediately - **name** (string) - Optional - Thread name - **priority** (int) - Optional - Thread priority - **daemon** (boolean) - Optional - Whether thread is a daemon - **virtual** (boolean) - Optional - Default: `false` - Use virtual thread (Java 19+) ### Returns Started Thread instance. ### Example ```clojure (px/fn->thread (fn [] (println "running")) :name "worker") ;; => Thread instance (already started) (px/fn->thread (fn [] 42) :start false) ;; => Thread instance (not started) ``` ``` -------------------------------- ### First Resolved Promise with `p/any` Source: https://github.com/funcool/promesa/blob/master/doc/promises.md Use `p/any` to get the result of the first promise that successfully resolves from a collection of promises. It returns a promise that resolves with the value of the first successful promise. ```clojure (def result (p/any [(p/delay 125 1) (p/delay 200 2) (p/delay 120 3)])) @result ;; => 3 ``` -------------------------------- ### Create a Promise from a Thread with thread-call Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Use `thread-call` to create and start an unpooled thread that executes a function and returns a non-cancellable promise. The promise resolves or rejects based on the function's outcome. Optional thread parameters can be provided. ```clojure (thread-call f & {:as opts}) -> Promise ``` ```clojure (px/thread-call (fn [] 42) :name "worker") ;; => 42 ``` -------------------------------- ### Get the first resolved value or a default Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md Use `any` to get a promise that resolves with the value of the first promise that resolves, ignoring any rejections. An optional default value can be provided to be used if all promises reject. ```clojure (any promises) -> Promise (any promises default) -> Promise @(p/any [(p/rejected (Exception. "1")) (p/rejected (Exception. "2")) (p/resolved 3)]) ;; => 3 @(p/any [(p/rejected (Exception. "error"))] :default-value) ;; => :default-value ``` -------------------------------- ### Create a Promise Asynchronously with an Executor Source: https://github.com/funcool/promesa/blob/master/doc/promises.md Use `p/create` with a factory function and an executor to run the factory asynchronously. Requires importing `promesa.exec`. ```clojure (require '[promesa.exec :as exec]) @(p/create (fn [resolve reject] (resolve 1)) exec/default-executor) ;; => 1 ``` -------------------------------- ### Create and Monitor Semaphore Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/semaphore.md Demonstrates how to create a semaphore with a specified number of permits and check its available permits. ```clojure (def sem (psm/create :permits 5)) (.availablePermits ^java.util.concurrent.Semaphore sem) ;; => 5 ``` -------------------------------- ### Get Bulkhead Statistics Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/quick-reference.md Retrieves statistics for a given bulkhead. This is useful for monitoring and debugging. ```clojure (pxb/get-stats bh) ``` -------------------------------- ### Get Thread Name Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Retrieves the name of the current thread or a specified thread. Useful for debugging and identification. ```clojure (px/get-name) ;; => "main" (px/get-name (px/current-thread)) ;; => "main" ``` -------------------------------- ### Get Current Thread Instance Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Retrieves the current thread object. Useful for subsequent thread operations. ```clojure (px/current-thread) ``` -------------------------------- ### Channel Multiplexing with `mult` Source: https://github.com/funcool/promesa/blob/master/doc/channels.md Demonstrates how to use `sp/mult` to create a multiplexer and `sp/tap` to subscribe multiple channels to it. Values sent to the multiplexer are received by all tapped channels. ```clojure (def mx (sp/mult)) (a/go (let [ch (sp/chan)] (sp/tap mx ch) (println "go 1:" (sp/! mx :a) ;; Will print to stdout (maybe in different order) ;; go 1: :a ;; go 2: :a ``` -------------------------------- ### create Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/semaphore.md Creates a Semaphore instance with the specified number of permits. The default is 1 permit. ```APIDOC ## create ### Description Creates a Semaphore instance with the specified number of permits. ### Signature ```clojure (create & {:keys [permits] :or {permits 1}}) -> java.util.concurrent.Semaphore ``` ### Parameters #### Options Map - **permits** (int) - Optional - Initial number of permits. Defaults to 1. ### Returns - java.util.concurrent.Semaphore instance. ### Example ```clojure (require '[promesa.exec.semaphore :as psm]) (def sem (psm/create :permits 5)) ;; => Semaphore with 5 permits (def binary-sem (psm/create :permits 1)) ;; => Binary semaphore (like a mutex) ``` ``` -------------------------------- ### Create a Promise using a Factory Function Source: https://github.com/funcool/promesa/blob/master/doc/promises.md Use `p/create` with a factory function that takes `resolve` and `reject` callbacks. The factory executes synchronously by default. ```clojure @(p/create (fn [resolve reject] (resolve 1))) ;; => 1 ``` -------------------------------- ### Get Thread ID Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Retrieves the unique ID of the current thread or a specified thread. Useful for tracking and logging. ```clojure (px/get-thread-id) ;; => 1 (px/get-thread-id (px/current-thread)) ;; => 1 ``` -------------------------------- ### Run Tests on JVM Source: https://github.com/funcool/promesa/blob/master/doc/contributing.md Execute this command to run tests for the Promesa project on the JVM platform. ```bash clojure -X:dev:test ``` -------------------------------- ### Create Resolved Promise Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/quick-reference.md Creates a promise that is immediately resolved with a value. Useful for starting promise chains with a known value. ```clojure (p/resolved 42) ``` -------------------------------- ### Async Bulkhead as java.util.concurrent.Executor Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Shows how async bulkheads implement the Executor interface, allowing them to be used with Promesa's executor functions like px/submit, px/run, and px/exec. ```clojure (def bh (pxb/create :type :async :permits 5)) ;; All of these work: (px/submit bh f) (px/run bh f) (px/exec bh f) ;; Can bind as default executor (px/with-executor bh @(px/submit (fn [] 42))) ``` -------------------------------- ### Submit Tasks to Default Executors Source: https://github.com/funcool/promesa/blob/master/_autodocs/configuration.md Use keyword shortcuts with `px/submit` to direct tasks to predefined executors like :cached, :vthread, or :current-thread. ```clojure (require '[promesa.exec :as px]) @(px/submit :cached (fn [] 42)) @(px/submit :vthread (fn [] 42)) @(px/submit :current-thread (fn [] 42)) ``` -------------------------------- ### Clone Promesa Repository Source: https://github.com/funcool/promesa/blob/master/doc/contributing.md Use this command to clone the public Promesa repository from GitHub. ```bash git clone https://github.com/funcool/promesa ``` -------------------------------- ### thread-call Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Creates and starts an unpooled thread executing a function, returning a non-cancellable promise. Supports thread naming, priority, daemon status, and virtual threads. ```APIDOC ## thread-call ### Description Creates and starts an unpooled thread executing `f`, returning a non-cancellable promise. Supports thread naming, priority, daemon status, and virtual threads. ### Signature ```clojure (thread-call f & {:as opts}) ``` ### Parameters #### Options - **f** (fn) - Required - Function to execute - **name** (string) - Optional - Optional thread name - **priority** (int) - Optional - Optional thread priority - **daemon** (boolean) - Optional - Optional daemon flag - **virtual** (boolean) - Optional - Use virtual threads ### Returns Promise that resolves/rejects with the result of `f`. ### Example ```clojure @(px/thread-call (fn [] 42) :name "worker") ;; => 42 ``` ``` -------------------------------- ### Run Clojure Tests Source: https://github.com/funcool/promesa/blob/master/README.md Execute the Clojure unit tests using the provided command. ```shell clojure -M:dev -m promesa.tests.main ``` -------------------------------- ### Handle Bulkhead Capacity Limit Reached Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Demonstrates how to catch and handle exceptions when a bulkhead's queue is full and a task is rejected. The exception data contains details about the limit reached. ```clojure (def bh (pxb/create :type :async :permits 1 :queue 2)) ;; Fill up the bulkhead (doseq [_ (range 4)] (try (px/submit bh (fn [] (Thread/sleep 10000))) (catch clojure.lang.ExceptionInfo e (when (= (:code (ex-data e)) :capacity-limit-reached) (println "Bulkhead full!"))))) ``` -------------------------------- ### Catch Errors in Promise Chains Source: https://github.com/funcool/promesa/blob/master/_autodocs/errors.md Errors propagate down promise chains until a `catch` handler is encountered. This example demonstrates an error being thrown and then recovered by a subsequent `catch`. ```clojure (require '[promesa.core :as p]) @(-> (p/resolved 1) (p/then (fn [x] (throw (Exception. "error")))) (p/then (fn [x] (inc x))) ;; This is skipped (p/catch (fn [e] "recovered"))) ;; => "recovered" ``` -------------------------------- ### Async Bulkhead Creation and Task Submission Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Creates an async bulkhead to manage tasks executed by an executor. Tasks are submitted using px/submit and will queue if permits are unavailable. ```clojure (def bh (pxb/create :type :async :permits 5 :queue 100)) @(px/submit bh expensive-async-fn) ``` -------------------------------- ### create Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Creates a bulkhead instance with concurrency limits. It supports both asynchronous and synchronous types, allowing configuration of permits, queue size, timeout, and executor. ```APIDOC ## create ```clojure (create & {:keys [type permits queue timeout executor] :as params}) -> Bulkhead | SemaphoreBulkhead ``` Creates a bulkhead instance with concurrency limits. ### Parameters | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | type | keyword | :async | Bulkhead type: `:async`/`:executor` or `:sync`/`:semaphore` | | permits | int | 1 | Maximum concurrent executions allowed | | queue | int | Integer/MAX_VALUE | Maximum queued tasks allowed | | timeout | long | nil | Timeout for enqueuing tasks (milliseconds). Only for sync type. | | executor | Executor | default-executor | Executor to use (async type only) | **Returns:** Bulkhead instance (implements Executor). **Example:** ```clojure (require '[promesa.exec.bulkhead :as pxb] '[promesa.exec :as px]) ;; Async bulkhead: limits concurrent executions in an executor (def async-bh (pxb/create :type :async :permits 5 :queue 20)) ;; Sync bulkhead: blocks in current thread (def sync-bh (pxb/create :type :sync :permits 3)) ;; With custom executor (def custom-bh (pxb/create :type :async :executor (px/fixed-executor :parallelism 4) :permits 2)) ``` ``` -------------------------------- ### Create Async and Sync Bulkheads Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Creates async and sync bulkhead instances with specified concurrency limits and queue sizes. Async bulkheads can optionally use a custom executor. ```clojure (require '[promesa.exec.bulkhead :as pxb] '[promesa.exec :as px]) ;; Async bulkhead: limits concurrent executions in an executor (def async-bh (pxb/create :type :async :permits 5 :queue 20)) ;; Sync bulkhead: blocks in current thread (def sync-bh (pxb/create :type :sync :permits 3)) ;; With custom executor (def custom-bh (pxb/create :type :async :executor (px/fixed-executor :parallelism 4) :permits 2)) ``` -------------------------------- ### Get the value of the first promise to resolve Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md Use `race` when you are interested in the result of the first promise that successfully resolves. It returns a promise that resolves with the value of that first promise. ```clojure (race promises) -> Promise @(p/race [(p/delay 100 1) (p/delay 50 2)]) ;; => 2 (resolves after 50ms) ``` -------------------------------- ### Rate Limiting with Timeout using Sync Bulkhead Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Illustrates rate limiting with a timeout using a sync bulkhead. If acquiring a permit takes longer than 2 seconds, a TimeoutException is caught. ```clojure ;; 3 concurrent tasks, 2 second timeout (def rate-limiter (pxb/create :type :sync :permits 3 :timeout 2000)) (try (pxb/invoke rate-limiter (fn [] (slow-operation))) (catch java.util.concurrent.TimeoutException _ (println "Rate limit exceeded"))) ``` -------------------------------- ### reduce Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md A promise-aware reduce function that applies an accumulation function `f` over a collection `coll`, starting with an initial value `init`. It can handle asynchronous operations within the accumulation function. ```APIDOC ## reduce ### Description Promise-aware reduce. Applies function `f` over a collection, potentially waiting for async operations. ### Parameters #### Path Parameters - **f** ((acc, item) -> Promise) - Required - Accumulation function - **init** (any) - Required - Initial accumulator value - **coll** (seq) - Required - Collection to reduce ### Returns Promise - A promise resolving to the final accumulator value. ### Example ```clojure @(p/reduce (fn [acc x] (p/resolved (+ acc x))) 0 [1 2 3 4]) ;; => 10 ``` ``` -------------------------------- ### Handle Division by Zero in Promesa Source: https://github.com/funcool/promesa/blob/master/_autodocs/errors.md Demonstrates catching an ArithmeticException when a division by zero occurs within a Promesa chain. Ensure the operation is wrapped to handle potential arithmetic errors. ```clojure @(-> (p/resolved 1) (p/then (fn [x] (/ 1 0)))) ;; => ArithmeticException: Divide by zero ``` -------------------------------- ### Acquire and Release Semaphore Permits Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/semaphore.md Shows how to acquire and release permits from a semaphore, updating the available permit count. ```clojure (psm/acquire sem) (.availablePermits ^java.util.concurrent.Semaphore sem) ;; => 4 (psm/acquire sem :permits 2) (.availablePermits ^java.util.concurrent.Semaphore sem) ;; => 2 (psm/release sem :permits 3) (.availablePermits ^java.util.concurrent.Semaphore sem) ;; => 5 ``` -------------------------------- ### Unwrap Exceptions Automatically Source: https://github.com/funcool/promesa/blob/master/_autodocs/errors.md Promesa automatically unwraps wrapped exceptions in most scenarios, simplifying error handling by presenting the original exception. This example shows an arithmetic exception not being wrapped. ```clojure (require '[promesa.core :as p] '[promesa.util :as pu]) @(-> (p/resolved 1) (p/then (fn [x] (/ 1 0)))) ;; => Throws ArithmeticException (not wrapped) ``` -------------------------------- ### as-> Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md Promise-aware 'as' threading macro. Similar to `clojure.core/as->`, but it handles promise unwrapping. ```APIDOC ## as-> ### Description Promise-aware as threading macro. Like `clojure.core/as->` but unwraps promises. ### Signature ```clojure (as-> expr name & forms) ``` ### Returns Promise ``` -------------------------------- ### create Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md Creates a promise from a factory function that receives resolve and reject callbacks. ```APIDOC ## create ### Description Creates a promise from a factory function. The factory is similar to the JavaScript Promise constructor callback. ### Parameters #### Path Parameters - **f** ((resolve, reject) -> any) - Required - Factory function that receives resolve and reject callbacks - **executor** (Executor or keyword) - Optional - Executor to run the factory asynchronously ### Throws Exceptions thrown by `f` are caught and the promise is rejected with them. ### Example ```clojure (p/create (fn [resolve reject] (resolve 42))) ;; => resolves to 42 (p/create (fn [resolve reject] (reject (Exception. "failed"))) :thread) ;; => rejects asynchronously in a thread ``` ``` -------------------------------- ### Handle Async Stack Overflow in Promesa Source: https://github.com/funcool/promesa/blob/master/_autodocs/errors.md Shows how a StackOverflowError can occur with deeply nested or infinite recursive asynchronous operations in Promesa. This example defines a recursive function that leads to a stack overflow. ```clojure (defn infinite-recursion [] (-> (p/resolved 1) (p/then (fn [_] (infinite-recursion))))) @(infinite-recursion) ;; => StackOverflowException ``` -------------------------------- ### Control Access with Semaphore Source: https://github.com/funcool/promesa/blob/master/_autodocs/INDEX.md Use `psm/create` to initialize a semaphore with a specified number of permits. `psm/acquire` and `psm/release` are used to manage access to a shared resource. ```clojure (require '[promesa.exec.semaphore :as psm]) (def sem (psm/create :permits 10)) (psm/acquire sem) (try (use-shared-resource) (finally (psm/release sem))) ``` -------------------------------- ### Extract promise value or default Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md Use `extract` to get the current value of a promise. If the promise is still pending, it returns a specified default value or nil if no default is provided. It can also return the exception if the promise was rejected. ```clojure (p/extract (p/resolved 42)) ;; => 42 (p/extract (p/deferred) :no-value) ;; => :no-value (p/extract (p/rejected (Exception. "error"))) ;; => Exception instance ``` -------------------------------- ### Closing a Channel with an Exception Source: https://github.com/funcool/promesa/blob/master/doc/channels.md Shows how to explicitly close a channel with an error cause using `sp/close` and `ex-info`. ```clojure (sp/close ch (ex-info "error" {})) ``` -------------------------------- ### API Client with Rate Limiting Source: https://github.com/funcool/promesa/blob/master/_autodocs/configuration.md Sets up an API client with rate limiting using an asynchronous bulkhead. It defines a cached executor and limits concurrent API calls. ```clojure (def api-executor (px/cached-executor :max-size 10)) (def api-limiter (pxb/create :type :async :permits 5 :queue 50 :executor api-executor)) (defn call-api [endpoint] (px/submit api-limiter (fn [] (http-get endpoint)))) ``` -------------------------------- ### Create Async Bulkhead Instance Source: https://github.com/funcool/promesa/blob/master/doc/bulkhead.md Creates an asynchronous bulkhead instance with specified concurrency and queue limits. Use this to manage concurrent tasks executed in an executor. ```clojure (require '[promesa.exec.bulkhead :as pxb] '[promesa.exec :as px]) ;; All parameters are optional and have defaults (def instance (pxb/create :type :async :permits 1 :queue 16)) @(px/submit instance (fn [] (Thread/sleep 1000) 1)) ;; => 1 ``` -------------------------------- ### Limiting Database Connections with Sync Bulkhead Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Shows how to limit concurrent database connections using a sync bulkhead. Database queries are executed via pxb/invoke to enforce the concurrency limit. ```clojure ;; Limit concurrent database connections (def db-limiter (pxb/create :type :sync :permits 10)) (defn execute-query [query] (pxb/invoke db-limiter (fn [] (db/execute query)))) ;; Execute query with concurrency limit (execute-query "SELECT * FROM users") ``` -------------------------------- ### Rate Limiting with Bulkhead Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/quick-reference.md Creates a rate limiter using an asynchronous bulkhead with a capacity of 10 permits. Tasks submitted via `px/submit` to this limiter will be rate-limited. ```clojure (def limiter (pxb/create :type :async :permits 10)) (px/submit limiter fetch-data) ``` -------------------------------- ### acquire Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/semaphore.md Acquires permits from the semaphore. By default, it blocks until permits are available. ```APIDOC ## acquire ### Description Acquires permits from the semaphore. Blocks by default until permits are available. ### Signature ```clojure (acquire sem) -> boolean (acquire sem & {:keys [permits timeout blocking] :or {blocking true permits 1}}) -> boolean ``` ### Parameters #### Path Parameters - **sem** (Semaphore) - Required - The semaphore instance. #### Query Parameters - **permits** (int) - Optional - Number of permits to acquire. Defaults to 1. - **timeout** (long) - Optional - Timeout in milliseconds. - **blocking** (boolean) - Optional - If true, blocks until available; if false, tries immediately. Defaults to true. ### Returns - `true` if permits acquired, `false` if timeout exceeded (in non-blocking mode). ### Blocks Yes (unless `:blocking false` or `:timeout` specified). ### Example ```clojure (def sem (psm/create :permits 3)) ;; Acquire 1 permit (blocking) (psm/acquire sem) ;; => true ;; Acquire 2 permits with timeout (psm/acquire sem :permits 2 :timeout 1000) ;; => true if 2 permits acquired within 1 second ;; Try non-blocking (psm/acquire sem :blocking false) ;; => true if permit available, false otherwise ``` ``` -------------------------------- ### Sequential Execution with `p/do` Source: https://github.com/funcool/promesa/blob/master/doc/promises.md The `p/do` macro executes expressions sequentially, returning the value of the last expression. It handles exceptions by returning a rejected promise. ```clojure (p/do (let [a (rand-int 10) b (rand-int 10)] (+ a b))) ``` ```clojure (p/do (expr1) (expr2) (expr3)) ``` ```clojure (p/let [_ (expr1) _ (expr2)] (expr3)) ``` -------------------------------- ### Create Bulkhead Rate Limiter Source: https://github.com/funcool/promesa/blob/master/_autodocs/INDEX.md Instantiate a bulkhead rate limiter with a specified number of permits. This controls concurrent access to a resource. ```clojure (pxb/create :permits 5) ``` -------------------------------- ### Sync Bulkhead Creation and Task Invocation Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Creates a sync bulkhead that uses a semaphore to block the current thread. Tasks are invoked using pxb/invoke and will block until a permit is acquired. ```clojure (def bh (pxb/create :type :sync :permits 3)) (pxb/invoke bh (fn [] (expensive-sync-fn))) ``` -------------------------------- ### Import Statements for Promesa Source: https://github.com/funcool/promesa/blob/master/_autodocs/README.md Import necessary namespaces for core promises, executors, bulkhead, and semaphore functionalities. ```clojure (require '[promesa.core :as p]) (require '[promesa.exec :as px]) (require '[promesa.exec.bulkhead :as pxb]) (require '[promesa.exec.semaphore :as psm]) ``` -------------------------------- ### Execute Task with Custom Executor Source: https://github.com/funcool/promesa/blob/master/_autodocs/INDEX.md Use `px/submit` with a specified executor (e.g., `:vthread`) to run a task. This allows for fine-grained control over thread management. ```clojure (require '[promesa.exec :as px]) @(px/submit :vthread (fn [] 42)) ``` -------------------------------- ### run Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Submits a task for execution, returning a promise that resolves when the task completes or rejects on error. ```APIDOC ## run ### Description Submits a task for execution, returning a promise that resolves when task completes or rejects on error. ### Signature ```clojure (run f) -> Promise (run executor f) -> Promise ``` ### Parameters #### Path Parameters - **f** (fn) - Required - Task to execute (should return nil or void) - **executor** (Executor or keyword) - Required - Executor to use ### Returns Promise that completes when task completes. ### Example ```clojure @(px/run (fn [] (println "done"))) ;; => prints "done", returns nil @(px/run :thread (fn [] (/ 1 0))) ;; => rejects with ArithmeticException ``` ``` -------------------------------- ### let* Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md An exception-unsafe version of `let`. This macro assumes that the execution context is already within a promise and does not perform additional exception handling for bindings. ```APIDOC ## let* ### Description Exception-unsafe version of `let`. Assumes already in promise context. ### Signature ```clojure (let* [bindings] & body) ``` ``` -------------------------------- ### Channel with Custom Executor Source: https://github.com/funcool/promesa/blob/master/doc/channels.md Demonstrates how to create a channel that uses a custom thread pool executor for its internal dispatching. ```clojure (require '[promesa.exec :as px]) (def executor (px/cached-executor)) (def ch (sp/chan :exc executor)) ``` -------------------------------- ### Go Block with Channel Take Source: https://github.com/funcool/promesa/blob/master/doc/channels.md Demonstrates a `go` block that waits for a value from a channel with a timeout. `go` blocks in Promesa return promises and leverage virtual threads on the JVM. ```clojure @(sp/go (sp/ :timeout ``` -------------------------------- ### Create Sync Bulkhead Source: https://github.com/funcool/promesa/blob/master/_autodocs/configuration.md Creates a synchronous bulkhead using semaphores for concurrency control. It limits the number of permits and can enforce a timeout for enqueuing. ```clojure (def bh (pxb/create :type :sync :permits 5 :timeout 1000)) ``` -------------------------------- ### Create a promise from a factory function Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md Use `create` to build a promise from a factory function that receives `resolve` and `reject` callbacks. An optional executor can be provided to run the factory asynchronously. ```clojure (p/create (fn [resolve reject] (resolve 42))) ;; => resolves to 42 (p/create (fn [resolve reject] (reject (Exception. "failed"))) :thread) ;; => rejects asynchronously in a thread ``` -------------------------------- ### Create Async Bulkhead Source: https://github.com/funcool/promesa/blob/master/_autodocs/configuration.md Creates an asynchronous bulkhead for rate limiting and concurrency control. It manages permits, queue size, and uses a specified executor. ```clojure (pxb/create & {:keys [type permits queue timeout executor]}) ``` ```clojure (def bh (pxb/create :type :async :permits 10 :queue 50 :executor (px/cached-executor :max-size 20))) ``` -------------------------------- ### Promise Chaining with User-Defined Executor Source: https://github.com/funcool/promesa/blob/master/doc/promises.md Shows how to use a user-defined executor (e.g., :default) to schedule each chained callback as a separate task, improving responsiveness for long chains. ```clojure (require '[promesa.exec :as px]) @(->> (p/delay 100 1) (p/fmap :default inc) (p/fmap :default inc)) ;; => 3 ``` -------------------------------- ### exec Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Submits a task for execution. Returns immediately and always returns a promise. ```APIDOC ## exec ### Description Submits a task for execution. Returns immediately (fire and forget). Always returns a promise (never throws). ### Signature ```clojure (exec f) -> Promise (exec executor f) -> Promise ``` ### Parameters #### Path Parameters - **f** (fn) - Required - Task to execute - **executor** (Executor or keyword) - Optional - Executor to use (default: *default-executor*) ### Returns Promise. Promise rejects if executor rejects the task. ### Example ```clojure (px/exec (fn [] (println "fire and forget"))) ;; => immediately returns promise (px/exec :thread (fn [] (println "in thread"))) ``` ``` -------------------------------- ### Create a Scheduled Executor Source: https://github.com/funcool/promesa/blob/master/_autodocs/configuration.md Set up a scheduled executor with a configurable number of scheduler threads and an optional custom thread factory. Tasks can be scheduled for delayed execution. ```clojure (px/scheduled-executor & {:keys [parallelism thread-factory] :or {parallelism 1}}) (def scheduler (px/scheduled-executor :parallelism 4)) @(px/schedule scheduler 1000 (fn [] "delayed")) ``` -------------------------------- ### Promise-aware doseq Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md Use `p/doseq` for sequential execution of a body over a collection, with promise support. It uses `run` internally and returns a promise that resolves to nil. ```clojure (doseq [[binding xs]] & body) -> Promise ``` ```clojure @(p/doseq [x [1 2 3]] (p/resolved (println x))) ;; prints 1, 2, 3 ``` -------------------------------- ### Thread-Safe Task Submission to Async Bulkhead Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Demonstrates the thread-safety of async bulkheads. Multiple threads can safely submit tasks to the same bulkhead instance, with execution limited by the configured permits. ```clojure (def bh (pxb/create :type :async :permits 10)) (dotimes [i 100] (px/submit bh (fn [] (println i)))) ;; => All submissions are safe, executes with 10 concurrent tasks ``` -------------------------------- ### Create Async Bulkhead Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/quick-reference.md Creates an asynchronous bulkhead for rate limiting. Use this when you need to control the concurrency of asynchronous tasks. ```clojure (def bh (pxb/create :type :async :permits 5)) @(px/submit bh (fn [] 42)) ``` -------------------------------- ### Create a Deferred Promise and Resolve Asynchronously Source: https://github.com/funcool/promesa/blob/master/doc/promises.md Use `p/deferred` to create a promise in a pending state, which can then be resolved or rejected asynchronously using `p/resolve!` or `p/reject!`. ```clojure (defn some-fn [ms] (let [p (p/deferred)] (p/resolve! p nil) p)) ``` -------------------------------- ### Using as Executor Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Bulkhead instances implement `java.util.concurrent.Executor`, allowing them to be used directly with `px/submit` and `px/run` for executing tasks under concurrency constraints. ```APIDOC ## Using as Executor Bulkhead implements `java.util.concurrent.Executor`, so it can be used with `px/submit` and `px/run`: ```clojure (px/submit bulkhead f) -> Promise (px/run bulkhead f) -> Promise ``` **Example:** ```clojure (def bh (pxb/create :type :async :permits 2)) @(px/submit bh (fn [] (Thread/sleep 1000) 42)) ;; => 42 @(px/run bh (fn [] (println "executed"))) ;; => nil (after execution) ``` ``` -------------------------------- ### Submit Task to Bulkhead Executor Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Submits a task to a bulkhead, which acts as a Java Executor. The task is executed respecting the bulkhead's concurrency limits. Use px/submit for asynchronous execution. ```clojure (def bh (pxb/create :type :async :permits 2)) @(px/submit bh (fn [] (Thread/sleep 1000) 42)) ``` -------------------------------- ### wrap Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md Convenience alias for `promise` that accepts a single argument. ```APIDOC ## wrap ### Description Convenience alias for `promise` that accepts a single argument. ### Parameters #### Path Parameters - **v** (any) - Required - Value to coerce into a promise ### Returns A promise instance. ### Source `src/promesa/core.cljc:57-61` ``` -------------------------------- ### Deref/Await Promises (Blocking) Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/quick-reference.md Demonstrates various ways to block and wait for a promise to complete. These methods are used when synchronous behavior is required. ```clojure ;; These all block until promise completes @p ;; deref with @ reader macro (deref p) (p/await p) (p/await p 5000) ;; with timeout (p/join p) ;; lower level ``` -------------------------------- ### Wait for all promises to complete (including rejections) Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md Use `wait-all*` when you need to know when all promises have settled, regardless of whether they resolved successfully or rejected. It returns a promise that resolves to nil once all input promises are complete. ```clojure (wait-all* promises) -> Promise @(p/wait-all* [(p/resolved 1) (p/rejected (Exception. "error"))]) ;; => nil (completes regardless of rejections) ``` -------------------------------- ### let Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md A promise-aware `let` macro that waits for each binding to resolve before executing the body. It returns a promise that resolves with the result of the body. ```APIDOC ## let ### Description Promise-aware let macro. Waits for each binding to resolve before proceeding. Returns a promise. ### Signature ```clojure (let [bindings] & body) ``` ### Request Example ```clojure @(p/let [x (p/resolved 1) y (p/resolved 2)] (+ x y)) ;; => 3 ``` ``` -------------------------------- ### Create Semaphore Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/semaphore.md Creates a Semaphore instance with a specified number of permits. Defaults to 1 permit for a binary semaphore. ```clojure (require '[promesa.exec.semaphore :as psm]) (def sem (psm/create :permits 5)) ;; => Semaphore with 5 permits (def binary-sem (psm/create :permits 1)) ;; => Binary semaphore (like a mutex) ``` -------------------------------- ### Create a Thread-per-Task Executor Source: https://github.com/funcool/promesa/blob/master/_autodocs/configuration.md Instantiate an executor that creates a new thread for each submitted task. Requires Java 19+ with the `--enable-preview` flag. ```clojure (px/thread-per-task-executor) (def executor (px/thread-per-task-executor)) ``` -------------------------------- ### Limit Concurrent Execution with Bulkhead Source: https://github.com/funcool/promesa/blob/master/_autodocs/INDEX.md Use `pxb/create` to set up a bulkhead limiter, then `px/submit` tasks to it. This pattern limits the number of concurrent executions to prevent resource exhaustion. ```clojure (require '[promesa.exec.bulkhead :as pxb] '[promesa.exec :as px]) (def limiter (pxb/create :type :async :permits 5)) @(px/submit limiter (fn [] (expensive-operation))) ``` -------------------------------- ### -> Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/core.md A promise-aware threading macro, similar to `clojure.core/->`. It automatically unwraps promises between steps, allowing for sequential operations on promise results. ```APIDOC ## -> ### Description Promise-aware threading macro. Like `clojure.core/->` but unwraps promises between steps. ### Signature ```clojure (-> expr & forms) ``` ### Request Example ```clojure (p/-> (p/resolved {:a 1}) (assoc :b 2) :b) ;; => 2 ``` ``` -------------------------------- ### Create and Put Value in Channel Source: https://github.com/funcool/promesa/blob/master/doc/channels.md Creates a buffered channel and performs a blocking put operation. Use `sp/put!` for blocking puts or `@sp/put` for a promise-based put. ```clojure (require '[promesa.exec.csp :as sp]) (def ch (sp/chan :buf 2)) ;; perform a blocking put operation using a blocking operation (sp/put! ch :a) ;; => true ;; Or perform a blocking put operation using `put` function ;; that returns a promise/future-like object (CompletableFuture) @(sp/put ch :b) ;; => true ``` -------------------------------- ### Create ForkJoin Thread Factory Source: https://github.com/funcool/promesa/blob/master/_autodocs/configuration.md Configures a thread factory for Promesa's forkjoin executor. You can specify a custom name format and whether threads should be daemons. ```clojure (px/forkjoin-thread-factory & {:keys [name daemon] :or {name "promesa/forkjoin/%s" daemon true}}) ``` ```clojure (def factory (px/forkjoin-thread-factory :name "fj-worker-%s")) ``` -------------------------------- ### Catch BulkheadError (Capacity Limit) Source: https://github.com/funcool/promesa/blob/master/_autodocs/errors.md Shows how to catch a `BulkheadError` with the code `:capacity-limit-reached` when an async bulkhead's queue is full. ```clojure (require '[promesa.exec.bulkhead :as pxb] '[promesa.exec :as px]) (def bh (pxb/create :type :async :permits 1 :queue 2)) (try ;; Submit more than permits + queue (doseq [_ (range 5)] (px/submit bh (fn [] (Thread/sleep 10000)))) (catch clojure.lang.ExceptionInfo e (let [data (ex-data e)] (when (= (:code data) :capacity-limit-reached) (println "Bulkhead queue full!"))))) ``` -------------------------------- ### Create Sync Bulkhead Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/quick-reference.md Creates a synchronous bulkhead for rate limiting. Use this for controlling the concurrency of synchronous operations. ```clojure (pxb/create :type :sync :permits N) ``` -------------------------------- ### Run Babashka Tests Source: https://github.com/funcool/promesa/blob/master/README.md Execute the tests specifically for the Babashka environment. ```shell bb test:bb ``` -------------------------------- ### *default-scheduler* Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md A dynamic variable for binding a custom default scheduler. ```APIDOC ## *default-scheduler* ### Description Dynamic variable for binding a custom default scheduler. ### Source `src/promesa/exec.cljc:54` ``` -------------------------------- ### Create a Virtual Thread-per-Task Executor Source: https://github.com/funcool/promesa/blob/master/_autodocs/configuration.md Create an executor that uses a virtual thread for each task. This requires Java 19+ with the `--enable-preview` flag and has no configuration options. ```clojure (px/vthread-per-task-executor) (def executor (px/vthread-per-task-executor)) ``` -------------------------------- ### Run Task with Bulkhead Executor Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/bulkhead.md Runs a task using a bulkhead as an Executor. This is suitable for side effects where the return value is not critical. The task executes respecting concurrency limits. ```clojure (def bh (pxb/create :type :async :permits 2)) @(px/run bh (fn [] (println "executed"))) ``` -------------------------------- ### Create a ForkJoin Executor Source: https://github.com/funcool/promesa/blob/master/_autodocs/configuration.md Configure a ForkJoin executor with options for parallelism, core and max pool sizes, async mode, keep-alive time, and a custom worker thread factory. ```clojure (px/forkjoin-executor & {:keys [parallelism factory async core-size max-size keepalive] :or {max-size 0x7fff async true keepalive 60000}}) (def executor (px/forkjoin-executor :parallelism 16 :async true)) ``` -------------------------------- ### Sequential Promise Composition with `p/let` Source: https://github.com/funcool/promesa/blob/master/doc/promises.md Use `p/let` for composing asynchronous operations sequentially, similar to synchronous `let` bindings. It returns a promise and short-circuits on errors. ```clojure (def result (p/let [x (p/delay 1000 42) y (p/delay 1200 41) z 2] (+ x y z))) @result ;; => 85 ``` ```clojure (p/then (sleep 42) (fn [x] (p/then (sleep 41) (fn [y] (p/then 2 (fn [z] (p/promise (do (+ x y z))))))))) ``` -------------------------------- ### Configure Default Executor Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Globally configure the default executor using `configure-default-executor`. The parameters accepted are the same as those for `forkjoin-executor`. ```clojure (configure-default-executor & params) -> ExecutorService ``` ```clojure (px/configure-default-executor :parallelism 16) ;; => default executor now has 16 parallelism ``` -------------------------------- ### Create Thread-per-Task Executor (Java 19+) Source: https://github.com/funcool/promesa/blob/master/_autodocs/api-reference/executors.md Creates an ExecutorService that spawns a new platform thread for each submitted task. Requires Java 19+ with virtual threads enabled. ```clojure (thread-per-task-executor & {:as options}) ``` -------------------------------- ### Chaining operations with `then` Source: https://github.com/funcool/promesa/blob/master/doc/promises.md Demonstrates traditional promise chaining using the `then` function. ```clojure (-> (p/resolved {:a 1 :c 3}) (p/then #(assoc % :b 2)) (p/then #(dissoc % :c))) ``` -------------------------------- ### Channel with Custom Exception Handler Source: https://github.com/funcool/promesa/blob/master/doc/channels.md Illustrates creating a channel with a specific exception handler (`sp/throw-uncaught`) for transducer errors. ```clojure (def ch (sp/chan :buf 1 :xf (map inc) :exh sp/throw-uncaught)) ``` -------------------------------- ### Create a Promise from a Value Source: https://github.com/funcool/promesa/blob/master/doc/promises.md Use `p/promise` to create a promise that resolves with a given value or rejects if the value is an exception. This function automatically coerces the input to the appropriate promise instance. ```clojure (require '[promesa.core :as p]) ;; creates a promise from value (p/promise 1) ;; creates a rejected promise (p/promise (ex-info "error" {})) ```