This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-10-18
Channels
- # aws (1)
- # aws-lambda (1)
- # beginners (48)
- # boot (15)
- # cider (3)
- # cljs-dev (4)
- # cljsrn (4)
- # clojure (241)
- # clojure-chicago (1)
- # clojure-dusseldorf (12)
- # clojure-greece (41)
- # clojure-italy (3)
- # clojure-russia (16)
- # clojure-spec (7)
- # clojure-uk (34)
- # clojurescript (88)
- # community-development (9)
- # cursive (8)
- # data-science (55)
- # datomic (40)
- # devops (1)
- # emacs (20)
- # fulcro (19)
- # graphql (3)
- # hoplon (46)
- # luminus (11)
- # lumo (4)
- # off-topic (27)
- # onyx (26)
- # other-languages (25)
- # pedestal (2)
- # powderkeg (6)
- # re-frame (11)
- # reagent (4)
- # ring-swagger (17)
- # rum (4)
- # shadow-cljs (103)
- # spacemacs (14)
- # specter (6)
- # unrepl (21)
- # yada (1)
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
@noisesmith wow really?
it's in the doc
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.
"the exprs may be run more than once"
@noisesmith hmmm ok what's an alternative to dosync then?
because all those calls are causing timeout issues
just do
?
how much code do you have inside the dosync?
how are you using your refs, how much does each one hold?
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)
@noisesmith got ya, let me take a shot at it now and see how the tests run
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 ... )
I create and initialize config in my system startup
since it's something the app should know and propagate
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
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
eg. - when you create a client, you might want to use it to do other things, instead of creating a new one repeatedly
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
yeah, and that returns the object that tracks the state and does the actions that require state
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
so, the function that needs the stateful component , should receive the component or should ask for the component inside ? ( you know what I mean ? )
yes - and that works out differently with thedifferent libs
but that's the general idea
(defn f [request component])
or
(defn f [request]
(let [comp (system/component :cognito)))
yeah- usually you give the component as the first arg, that way you can use partial
with mount it would look more like the second one - it encourages keeping each one in a namespace global
with stuartsierra/component you are instead encouraged to always provide it as an argument
cool ! so my first touch-point ( usally my http handler ) will receive the system/component and propagate downstream, right ?
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
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
> I use middleware to make them visible to the requesthandler didn’t get that, can you exemplify it ?
sure - (defn with-db-component [component handler] (fn [request] (handler (assoc request :db-state (:db component))))
I put that middleware around the handler, and pass the result to the http server on startup
right - and that middleware is invoked inside the component that starts up the http server
(since the server is also a stateful thing - it's running using a port with a specific handler)
there are many examples and pre-rolled helpers for using component in common use cases if you do a bit of searching