Fork me on GitHub
#beginners
<
2017-10-18
>
josh_tackett02:10:20

Can dosync cause pieces of code to be run multiple times? I'm dealing with a strange issue where print lines are occurring multiple times within one test, but only when running simultaneous tests. When I run the test in isolation, I get the correct number of printlines

josh_tackett02:10:36

@noisesmith wow really?

noisesmith02:10:41

it's in the doc

noisesmith02:10:55

user=> (doc dosync)
-------------------------
clojure.core/dosync
([& exprs])
Macro
  Runs the exprs (in an implicit do) in a transaction that encompasses
  exprs and any nested calls.  Starts a transaction if none is already
  running on this thread. Any uncaught exception will abort the
  transaction and flow out of dosync. The exprs may be run more than
  once, but any effects on Refs will be atomic.

noisesmith02:10:29

"the exprs may be run more than once"

josh_tackett02:10:20

@noisesmith hmmm ok what's an alternative to dosync then?

josh_tackett02:10:30

because all those calls are causing timeout issues

noisesmith02:10:13

how much code do you have inside the dosync?

noisesmith02:10:37

how are you using your refs, how much does each one hold?

noisesmith02:10:13

I mean, if you are not using refs, don't use dosync, but if you are, you can't modify them without dosync (but definitely don't just wrap all the code in one big dosync)

josh_tackett02:10:45

@noisesmith got ya, let me take a shot at it now and see how the tests run

oliv20:10:12

hey folks, how can I discover which profile was activated when I run lein task ?

oliv22:10:06

how can I improve my code currently I have the following code to communication with cognito aws

(ns api.aws.cognito
  (:require [api.config :as config])
  (:import [com.amazonaws.services.cognitoidentity AmazonCognitoIdentityClientBuilder]
           [com.amazonaws.auth AWSStaticCredentialsProvider BasicAWSCredentials]
           [com.amazonaws.services.cognitoidentity.model GetOpenIdTokenForDeveloperIdentityRequest]
           (com.amazonaws.regions Regions)))

(defn- credentials [config]
  (let [{:keys [access-id secret-key]} config]
    (-> (new BasicAWSCredentials access-id secret-key)
        (AWSStaticCredentialsProvider.))))

(defn- create-client [config]
  (->
    (AmazonCognitoIdentityClientBuilder/standard)
    (.withRegion Regions/US_EAST_2)
    (.withCredentials (credentials))
    (.build)))

(defn- open-id-request [config]
  (let [{:keys [identity-pool-id token-duration-in-seconds user-id cognito-developer-provider-name]} config]
    (doto (new GetOpenIdTokenForDeveloperIdentityRequest)
      (.setIdentityPoolId identity-pool-id)
      (.setTokenDuration token-duration-in-seconds)
      (.setLogins {:cognito-developer-provider-name cognito-developer-provider-name
                   :user-id user-id}))))

(defn generate-open-id! []
  (let [config (config/for :aws :cognito)
        client (create-client config)
        request (open-id-request config)]
    (.getOpenIdTokenForDeveloperIdentity client request)))
what bother me is the generate-open-id! as you can see generate-open-id is not receiving the config as parameter ( should be ? ), the config for is my cprop configuration loaded from my resources
(ns api.config
  (:require [cprop.core :refer [load-config]]
            [cprop.source :as source]))

(def config (load-config :merge [(source/from-resource)
                                 (source/from-system-props)
                                 (source/from-env)]))
(defn for[& keywords]
  (get-in config keywords))
my question is: should I pass the configuration to the generate-open-id! ? doing that, the service layer ( responsible to call the cognito ) should “hide” the configuration or receive from the caller ?
service layer
 (defn usecase [request-params] 
  (let [credentials  (cognito/generate-open-id (config/for :aws :cognito)]
   .. some business rule here ...  )

oliv22:10:34

how you guys normally do that ?

noisesmith22:10:32

I create and initialize config in my system startup

noisesmith22:10:42

since it's something the app should know and propagate

noisesmith22:10:24

I use stuartsierra/component so that each part of the app knows the config it needs when I create it's initial state - other state management libs (integrant, mount, etc.) allow the same sort of workflow

noisesmith22:10:26

this way the config isn't tied to the function (which should be config agnostic) but rather some sort of app state (which is intrinsically tied to config) - in some rare cases the config is the only "initialization" but it still is one, in other cases the config is used to build, or alongside, some acquired stateful resource

noisesmith22:10:52

eg. - when you create a client, you might want to use it to do other things, instead of creating a new one repeatedly

oliv22:10:46

thanks @noisesmith, going to read about component ! so you would create the “cognito componet” and on “initialize of the componet” you setup the configuration there

oliv22:10:05

and the functions need to use the cognito will ask to the component system, right ?

noisesmith22:10:20

yeah, and that returns the object that tracks the state and does the actions that require state

noisesmith22:10:30

the idea is most of your functions stay pure, based only on arguments, and things that need state are created explicitly on startup, and each one can ask to receive the stateful parts of the app it needs to access

oliv22:10:43

so, the function that needs the stateful component , should receive the component or should ask for the component inside ? ( you know what I mean ? )

noisesmith23:10:16

yes - and that works out differently with thedifferent libs

noisesmith23:10:21

but that's the general idea

oliv23:10:25

(defn f [request component]) 
or
(defn f [request]
 (let [comp (system/component :cognito)))

noisesmith23:10:01

yeah- usually you give the component as the first arg, that way you can use partial

noisesmith23:10:46

with mount it would look more like the second one - it encourages keeping each one in a namespace global

noisesmith23:10:09

with stuartsierra/component you are instead encouraged to always provide it as an argument

oliv23:10:44

cool ! so my first touch-point ( usally my http handler ) will receive the system/component and propagate downstream, right ?

noisesmith23:10:36

yeah - with http I make the http server a component, and the db etc. are passed in at startup and I use middleware to make them visible to the requesthandler

noisesmith23:10:16

what component does is you declare what each thing provides and what it needs, and then it sorts them out and figure out what order to start them in and which ones to pass as args to which other ones

oliv23:10:24

> I use middleware to make them visible to the requesthandler didn’t get that, can you exemplify it ?

noisesmith23:10:20

sure - (defn with-db-component [component handler] (fn [request] (handler (assoc request :db-state (:db component))))

noisesmith23:10:37

I put that middleware around the handler, and pass the result to the http server on startup

oliv23:10:24

so you associate the db into request

noisesmith23:10:48

right - and that middleware is invoked inside the component that starts up the http server

noisesmith23:10:13

(since the server is also a stateful thing - it's running using a port with a specific handler)

oliv23:10:35

will try that and let you know

noisesmith23:10:04

there are many examples and pre-rolled helpers for using component in common use cases if you do a bit of searching

oliv23:10:54

thks sir !