Skip to content

Instantly share code, notes, and snippets.

@martintrojer
Last active December 23, 2015 15:39
Show Gist options
  • Save martintrojer/6657390 to your computer and use it in GitHub Desktop.
Save martintrojer/6657390 to your computer and use it in GitHub Desktop.
simulant blog post
(def url "http://localhost:3000/data")
(defn post-some-data [test]
(let [data (zipmap (clojure.data.generators/vec clojure.data.generators/scalar)
(clojure.data.generators/vec clojure.data.generators/scalar))]
[(clj-http.client/put url {:body (pr-str data) :content-type :edn :throw-entire-message? true})
data]))
(defn get-data [id]
(update-in
(clj-http.client/get url {:query-params {:id id}})
[:body] read-string))
(defn post-and-get-data [my-ids]
(let [[{:keys [body status]} data] (post-some-data test)
id (-> body read-string :id)
{:keys [body]} (get-data id)]
(when-not (= (:body data) (:body body))
(log/error "Data mismatch!"))
(conj my-ids id)))
(defn run-some-tests [cnt]
(loop [ctr cnt, my-ids #{}]
(when-not (zero? ctr)
(recur
(dec ctr)
(post-and-get-data remove-data my-ids)))))
(defn test-site
(dotimes [_ 10]
(future run-some-tests)))
(defn- get-an-id [action]
(let [latest-action (d/entity (d/db db/sim-conn) (:db/id action))]
(-> latest-action :agent/_actions first :agent/siteIds seq rand-nth)))
(defn post-some-data [action]
(let [{:keys [body status]} (post-data (:action/payload action))]
(-> body read-string :id)))
(defn get-some-data [action]
(when-let [id (get-an-id action)]
[id (get-data id)]))
[[;; The set of Ids a agent have gotten back from the site
{:db/ident :agent/siteIds
:db/cardinality :db.cardinality/many}
;; The payload to be sent TO the site in a put action
{:db/ident :action/payload}
;; The payload returned FROM the site in a get action
{:db/ident :action/sitePayload}
;; The Id returned FROM the site in a put action, and send TO the site
;; in a get/delete action
{:db/ident :action/siteId}]]
(def site-user-model-data
[{:db/id model-id
:model/type :model.type/siteUsage
:model/userCount 100
:model/meanPayloadSize 2
:model/meanSecsBetweenHits 10}])
(def site-user-model
(-> @(d/transact db/sim-conn site-user-model-data)
(util/tx-ent model-id)))
;; activity for this sim
(def site-usage-test
(sim/create-test db/sim-conn site-user-model
{:db/id (d/tempid :test)
:test/duration (util/hours->msec 1)
}))
;; sim
(def site-usage-sim
(sim/create-sim db/sim-conn site-usage-test {:db/id (d/tempid :sim)
:sim/processCount 10}))
(defmethod sim/create-test :model.type/siteUsage
[conn model test]
(let [test (create-test conn model test)
api-users (create-api-users conn test)]
(util/transact-batch conn (mapcat #(generate-api-user-usage test %) api-users) 1000)
(d/entity (d/db conn) (util/e test))))
(defmethod sim/perform-action :action.type/delete
[action process]
(let [site-id (do-action action process remove-some-data)
agents (-> action :agent/_actions)]
(when site-id
@(d/transact db/sim-conn [[:db/add (:db/id action) :action/siteId site-id]
[:db/retract (:db/id (first agents)) :agent/siteIds site-id]]))))
[[;; We are modelling site usage simulation
{:db/ident :model.type/siteUsage}
;; Configuration parameters for the model
{:db/ident :model/userCount
:db/doc "Number of API users"}
{:db/ident :model/meanPayloadSize
:db/doc "Mean size of payload (geometric distribution)."}
{:db/ident :model/meanSecsBetweenHits
:db/doc "Mean time between api hits in seconds (geometric distribution)"}]]
(defn- get-payload-map [action-type payload-attribute]
(->> (d/q '[:find ?id ?payload
:in $ ?action-type ?payload-attribute
:where
[?e :action/type ?action-type]
[?e :action/siteId ?id]
[?e ?payload-attribute ?payload]]
simdb action-type payload-attribute)
(map (fn [[id payload]] [id (read-string payload)]))
(into {})))
(let [posted-payloads (get-payload-map :action.type/put :action/payload)
received-payloads (get-payload-map :action.type/get :action/sitePayload)]
(doseq [[id payload] received-payloads]
(assert (= payload (posted-payloads id)))))
(defroutes app-routes
(GET "/" [] (generate-response :ok))
(GET "/liveids" [] (generate-response (live-ids)))
(GET "/data" {params :params} (get-data params))
(PUT "/data" {params :params} (store-data params))
(DELETE "/data" {params :params} (remove-data params))
(route/not-found (generate-response :not-found)))
(def pruns
(->> #(sim/run-sim-process db/sim-uri (:db/id site-usage-sim))
(repeatedly (:sim/processCount site-usage-sim))
(into [])))
;; wait for sim to finish
(time
(mapv (fn [prun] @(:runner prun)) pruns))
;; +-------------------+
;; | agent |*----- 1 to N ---+
;; +-------------------+ |
;; | actions | \|/
;; | type | +--------------------+
;; | errorDescription | | action |
;; +-------------------+ +--------------------+
;; | siteIds | | atTime |
;; +-------------------+ | type |
;; +--------------------+
;; | payload |
;; | sitePayload |
;; | siteId |
;; +--------------------+
[[ ;; One type of test
{:db/ident :test.type/putGetDelte}
;; One type of agent (simulating a user)
{:db/ident :agent.type/apiUser}
;; Three type of actions
{:db/ident :action.type/put}
{:db/ident :action.type/get}
{:db/ident :action.type/delete}]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment