A transaction processing system that does as much synchronously as possible, and removes various elements of complexity that were inherited from Fulcro 2 in the standard tx processing.
See with-synchronous-transactions
for how to install it.
This tx processing system does as much work synchronously as possible, though it does try to preserve the call-order semantics of the standard transaction processing: That is to say that if the optimistic action of a transaction submits a new transaction then that new submission will run after the current already-in-progress transaction has finished processing:
(defmutation g [_]
(action [{:keys [state]}] (swap! state ...))
(ok-action [{:keys [app]}] (transact! app [(h)]))
(remote [_] true))
(defmutation f [_]
(action [{:keys [state app]}]
(swap! state ...)
(transact! app [(g)])))
...
(dom/a {:onClick (fn []
(transact! this [(f {:x 1})])
(transact! this [(f {:x 2})])
(transact! this [(f {:x 3})])))
A user clicking the above link with std processing could see any of the following:
f,f,f,g,g,g,h,h,h
f,f,f,g,h,g,g,h,h
f,f,f,g,g,h,g,h,h
etc.
In sync tx processing, you would more likely see:
f,g,f,g,f,g,h,h,h
because there is no guarantee in Fulcro's semantics about the space between two calls to transact!
. If your
application relies on the groupings that happen with the standard tx processing (submissions while holding a thread
go into the queue first) then your application may break when you switch to sync processing.
Note that transactions are treated as atomically as possible. So, if you want a specific grouping you should submit it as a single tx:
(transact! [(f) (g)])
(transact! [(f) (g)])
is guaranteed to do f,g,f,g
, and never f,f,g,g
, though it is still possible to see f,g,h,f,g,h
.
This sync transaction processing system allows you to push most (if not all) behavior of even nested transactions into a single synchronous operation. This will lead to significant improvements in the snappiness of the UI for optimistic operation and should also reduce over-rendering (multiple calls to render due to multiple async operations).
If your remote is mocked as a synchronous operation, then you can also leverage this tx processor to enable completely synchronous testing of your headless Fulcro application.
WARNING: This tx processing system does not support:
ptransact!
: Pessimistic transactions are a legacy feature of Fulcro 2 that is no longer necessary. New
applications should not use the feature, and this sync tx processing system does not support it. The call
will succeed, but will behave as a normal transact!
.A transaction processing system that does as much synchronously as possible, and removes various elements of complexity that were inherited from Fulcro 2 in the standard tx processing. See `with-synchronous-transactions` for how to install it. This tx processing system does as much work synchronously as possible, though it does try to preserve the call-order *semantics* of the standard transaction processing: That is to say that if the optimistic action of a transaction submits a new transaction then that new submission will run *after* the current already-in-progress transaction has finished processing: ``` (defmutation g [_] (action [{:keys [state]}] (swap! state ...)) (ok-action [{:keys [app]}] (transact! app [(h)])) (remote [_] true)) (defmutation f [_] (action [{:keys [state app]}] (swap! state ...) (transact! app [(g)]))) ... (dom/a {:onClick (fn [] (transact! this [(f {:x 1})]) (transact! this [(f {:x 2})]) (transact! this [(f {:x 3})]))) ``` A user clicking the above link with std processing could see any of the following: ``` f,f,f,g,g,g,h,h,h f,f,f,g,h,g,g,h,h f,f,f,g,g,h,g,h,h etc. ``` In sync tx processing, you would more likely see: ``` f,g,f,g,f,g,h,h,h ``` because there is *no guarantee* in Fulcro's semantics about the space between two calls to `transact!`. If your application relies on the groupings that happen with the standard tx processing (submissions while holding a thread go into the queue first) then your application may break when you switch to sync processing. Note that transactions *are* treated as atomically as possible. So, if you want a specific grouping you should submit it as a single tx: ``` (transact! [(f) (g)]) (transact! [(f) (g)]) ``` is guaranteed to do `f,g,f,g`, and never `f,f,g,g`, though it is still possible to see `f,g,h,f,g,h`. This sync transaction processing system allows you to push most (if not all) behavior of even nested transactions into a single synchronous operation. This will lead to significant improvements in the snappiness of the UI for optimistic operation and should also reduce over-rendering (multiple calls to render due to multiple async operations). If your remote is mocked as a synchronous operation, then you can also leverage this tx processor to enable completely synchronous testing of your headless Fulcro application. WARNING: This tx processing system does *not* support: * `ptransact!`: Pessimistic transactions are a legacy feature of Fulcro 2 that is no longer necessary. New applications should not use the feature, and this sync tx processing system does not support it. The call will succeed, but will behave as a normal `transact!`.
[app abort-id]
Implementation of abort when using this tx processing
[app abort-id] Implementation of abort when using this tx processing
(activate-submissions! app)
Activate all of the transactions that have been submitted since the last activation. After the items are activated a single processing step will run for the active queue.
Activation can be blocked by the tx-node options for things like waiting for the next render frame.
Activate all of the transactions that have been submitted since the last activation. After the items are activated a single processing step will run for the active queue. Activation can be blocked by the tx-node options for things like waiting for the next render frame.
(add-send! app
{:com.fulcrologic.fulcro.algorithms.tx-processing/keys [id options]
:as tx-node}
ele-idx
remote)
Generate a new send node and add it to the appropriate send queue.
Generate a new send node and add it to the appropriate send queue.
(available-work? app)
Returns true if the submission queue has work on it that can proceed without any restrictions.
Returns true if the submission queue has work on it that can proceed without any restrictions.
(current-thread-id)
Get the current thread id on the JVM. Returns 0 on JS.
Get the current thread id on the JVM. Returns 0 on JS.
(current-thread-running-tx? {:com.fulcrologic.fulcro.application/keys [id]
:as app})
Is the current thread running the TX queue?
Is the current thread running the TX queue?
(dispatch-result! app
tx-node
{:com.fulcrologic.fulcro.algorithms.tx-processing/keys
[results dispatch desired-ast-nodes transmitted-ast-nodes
original-ast-node]
:as tx-element}
remote)
Figure out the dispatch routine to trigger for the given network result. If it exists, send the result to it.
Returns the tx-element with the remote marked complete.
Figure out the dispatch routine to trigger for the given network result. If it exists, send the result to it. Returns the tx-element with the remote marked complete.
(distribute-element-results!
app
tx-node
{:keys [:com.fulcrologic.fulcro.algorithms.tx-processing/results
:com.fulcrologic.fulcro.algorithms.tx-processing/complete?]
:as tx-element})
Distribute results and mark the remotes for those elements as complete.
Distribute results and mark the remotes for those elements as complete.
(distribute-results! app txn-id ele-idx)
Side-effects against the app state to distribute the result for txn-id element at ele-idx. This will call the result handler and mark that remote as complete.
Side-effects against the app state to distribute the result for txn-id element at ele-idx. This will call the result handler and mark that remote as complete.
(do-post-processing! app)
Runs the queued post processing steps until the post-processing queue is empty.
Runs the queued post processing steps until the post-processing queue is empty.
(in-transaction? {:com.fulcrologic.fulcro.application/keys [id] :as app})
Returns true if the current thread is in the midst of running the optimistic actions of a new transaction.
Returns true if the current thread is in the midst of running the optimistic actions of a new transaction.
(post-processing? app)
Is there post processing to do?
Is there post processing to do?
(process-queue!
{:com.fulcrologic.fulcro.application/keys [state-atom runtime-atom] :as app})
Run through the active queue and do a processing step.
Run through the active queue and do a processing step.
(process-send-queues! app)
Process the send queues against the remotes, which will cause idle remotes with queued work to issue network requests.
Process the send queues against the remotes, which will cause idle remotes with queued work to issue network requests.
(process-tx-node! app
{:keys
[:com.fulcrologic.fulcro.algorithms.tx-processing/options]
:as tx-node})
(queue-element-sends! app
tx-node
{:com.fulcrologic.fulcro.algorithms.tx-processing/keys
[idx dispatch started?]})
Queue all (unqueued) remote actions for the given element. Returns the (possibly updated) node.
Queue all (unqueued) remote actions for the given element. Returns the (possibly updated) node.
(queue-sends! app
{:keys [:com.fulcrologic.fulcro.algorithms.tx-processing/options
:com.fulcrologic.fulcro.algorithms.tx-processing/elements]
:as tx-node})
Finds any item(s) on the given node that are ready to be placed on the network queues and adds them. Non-optimistic multi-element nodes will only queue one remote operation at a time.
Finds any item(s) on the given node that are ready to be placed on the network queues and adds them. Non-optimistic multi-element nodes will only queue one remote operation at a time.
(record-result! app txn-id ele-idx remote result)
(record-result! app txn-id ele-idx remote result result-key)
Deal with a network result on the given txn/element.
Deal with a network result on the given txn/element.
(release-post-render-tasks! app)
Should be called after the application renders to ensure that transactions blocked until the next render become unblocked. Schedules an activation.
Should be called after the application renders to ensure that transactions blocked until the next render become unblocked. Schedules an activation.
(remove-send! app remote txn-id ele-idx)
Removes the send node (if present) from the send queue on the given remote.
Removes the send node (if present) from the send queue on the given remote.
(run-after! app f)
Add f
as a function that will run after the current transaction has been fully processed.
Add `f` as a function that will run after the current transaction has been fully processed.
(run-all-immediate-work! app)
Runs the submission queue. If the submission queue's optimistic actions submit more to the submission queue, then those are processed as well until the submission queue remains empty. This can start network requests.
Runs the submission queue. If the submission queue's optimistic actions submit more to the submission queue, then those are processed as well until the submission queue remains empty. This can start network requests.
(submit-sync-tx! app tx)
(submit-sync-tx! {:com.fulcrologic.fulcro.application/keys [runtime-atom]
:as app}
tx
options)
(top-level? {:com.fulcrologic.fulcro.application/keys [id]})
Returns true if the current thread is running non-nested transaction processing code.
Returns true if the current thread is running non-nested transaction processing code.
(with-synchronous-transactions app)
Installs synchronous transaction processing on a fulcro application.
(defonce app (stx/with-synchronous-transactions
(app/fulcro-app {...})))
This plug-in attempts to do as much work as possible synchronously, including the processing of "remotes" that can behave synchronously. This processing system preserves transactional ordering semantics for nested submissions, but cannot guarantee that the overall sequence of operations will exactly match what you'd see if using the standard tx processing.
The options map you can pass to transact!
supports most of the same things as the standard tx processing, with the significant exception of
:optimistic? false
(pessimistic transactions). It also always assumes synchronous operation, thought the
synchronous?
option (if used) does imply that only the current component should be refreshed in the UI.
:ref
- ident. The component ident to include in the transaction env.:component
- React element. The instance of the component that should appear in the transaction env.:synchronous?
- When true, causes the rendering to only refresh the calling component (if possible), since the implication
is for fast-as-possible refresh semantics, even though this tx processing is already sync.:refresh
- A hint. Vector containing idents (of components) and keywords (of props). Things that have changed and should be re-rendered
on screen. Only necessary when the underlying rendering algorithm won't auto-detect, such as when UI is derived from the
state of other components or outside of the directly queried props. Interpretation depends on the renderer selected:
The ident-optimized render treats these as "extras".:only-refresh
- A hint. Vector of idents/keywords. If the underlying configured rendering algorithm supports it: The
components using these are the only things that will be refreshed in the UI, and they may be refreshed immediately on
transact!
. This can be used to avoid the overhead of looking for stale data when you know exactly what
you want to refresh on screen as an extra optimization. Idents are not checked against queries.If the options
include :ref
(which comp/transact! sets), then it will be auto-included on the :refresh
list.
Returns the transaction ID of the submitted transaction.
Installs synchronous transaction processing on a fulcro application. ``` (defonce app (stx/with-synchronous-transactions (app/fulcro-app {...}))) ``` This plug-in attempts to do as much work as possible synchronously, including the processing of "remotes" that can behave synchronously. This processing system preserves transactional ordering semantics for nested submissions, but cannot guarantee that the overall sequence of operations will exactly match what you'd see if using the standard tx processing. The options map you can pass to `transact!` supports most of the same things as the standard tx processing, with the significant exception of `:optimistic? false` (pessimistic transactions). It also *always* assumes synchronous operation, thought the `synchronous?` option (if used) does imply that only the current component should be refreshed in the UI. - `:ref` - ident. The component ident to include in the transaction env. - `:component` - React element. The instance of the component that should appear in the transaction env. - `:synchronous?` - When true, causes the rendering to only refresh the calling component (if possible), since the implication is for fast-as-possible refresh semantics, even though this tx processing is already sync. - `:refresh` - A hint. Vector containing idents (of components) and keywords (of props). Things that have changed and should be re-rendered on screen. Only necessary when the underlying rendering algorithm won't auto-detect, such as when UI is derived from the state of other components or outside of the directly queried props. Interpretation depends on the renderer selected: The ident-optimized render treats these as "extras". - `:only-refresh` - A hint. Vector of idents/keywords. If the underlying configured rendering algorithm supports it: The components using these are the *only* things that will be refreshed in the UI, and they may be refreshed immediately on `transact!`. This can be used to avoid the overhead of looking for stale data when you know exactly what you want to refresh on screen as an extra optimization. Idents are *not* checked against queries. If the `options` include `:ref` (which comp/transact! sets), then it will be auto-included on the `:refresh` list. Returns the transaction ID of the submitted transaction.
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close