Skip to content
Brenton Ashworth edited this page Jul 2, 2013 · 9 revisions

Simulating Effects

  • Effect functions

Effecting the outside world

Our application is now receiving input from the outside world. In this section we will make it effect the outside world by allowing it to send its counter value to a service.

To accomplish this we will add an effect function to the dataflow. Effect functions generate messages which will be sent out from the application. This function will be added to the tutorial-client.behavior namespace.

The exact arguments to an effect function will depend on how that function is configured. Effect functions always return a sequence of messages to send. This function will take a counter value as an argument.

(defn publish-counter [count]
  [{msg/type :swap msg/topic [:other-counters] :value count}])

The returned message is similar to the message above which is used to set the value of the other counters. When this message arrives at the service, the session id will be added to the topic before the message is forwarded to the other clients.

To add this function to the dataflow, we add an :effect key. Effects are configured as a set of vectors. Each vector has three elements, a set of inputs, the effect function and the arguments specification.

:effect #{[#{[:my-counter]} publish-counter :single-val]}

The arguments specification indicates that the function should be passed a single value which will be the value at :my-counter in the data model. For more information on argument specifiers, see [[Derived Values]].

This configuration will cause the publish-counter function to be called whenever the value at :my-counter changes.

The complete dataflow definition now looks like the one shown below.

(def example-app
  {:version 2
   :transform [[:inc  [:my-counter] inc-transform]
               [:swap [:**]         swap-transform]]
   :effect #{[#{[:my-counter]} publish-counter :single-val]}
   :emit [{:init init-main}
          [#{[:my-counter] [:other-counters :*]} (app/default-emitter [:main])]]})

Consuming effects

What happens to effects after they are generated? Effect messages are put on a queue and can be consumed by a service. Our simulated service will handle these messages by printing them to the JavaScript console.

In the tutorial-client.simulated.services namespace, add the following function which will be used to process outgoing messages. In the real service, this function would send the message over the network to a back-end service.

(defn services-fn [message input-queue]
  (.log js/console (str "Sending message to server: " message)))

The handler function receives the message and the input-queue. The input-queue is used to allow callbacks to send results back to the application. Here it is ignored.

Back in the tutorial-client.simulated.start namespace we need to arrange for every message placed on the effect queue to be processed by this handler function.

First we require the io.pedestal.app namespace.

[io.pedestal.app :as app]

Then we use the consume-effects function to set this up.

(app/consume-effects (:app app) services/services-fn)

The main function should now look like the one shown below.

(defn ^:export main []
  (let [app (start/create-app d/data-renderer-config)
        services (services/->MockServices (:app app))]
    (app/consume-effects (:app app) services/services-fn)
    (p/start services)
    app))

To test that this works, refresh the page and then open the JavaScript console and click on the Increment Counter button. You should see the message printed in the console.

Next steps

This simple application now has some basic values and can send and receive messages. The next section will introduce dataflow in a bit more detail as we look at how to use derive functions to generate new values.

The tag for this step is v2.0.5.

Home | Derived Values

Clone this wiki locally