Skip to content

Instantly share code, notes, and snippets.

What would you like to do?

Deploying your app

Datomic provides tooling to deploy your code to the cloud services. It's quick and avoids downtime.

There are a few steps in the process:

  • Push: Prepares and uploads a release of your application
  • Deploy: Updates an application with zero downtime

The process is best done after committing your code so that the git rev can be used as a unique identifier for the release.

During development it may be useful to quickly release unstable code to a development environment. We can support that by adding some helper functions to our user namespace.

Note: We're not considering multiple deployments here.

Helper to do quick dev releases

Firstly, let's provide a release helper function in our user namespace. We can use this to release from the REPL during development.

This code does a push, then a deploy and finally polls until the deploy reports it's finished running. It should provide what we need during development to do a one-step deployment.

Note: the extra code to support :creds-profile & :region might be excessive but gives us full access to the ion-dev API.

Note: We're hardcoding the compute group name for now - seems like something which might be resolved from system name via AWS CLI.

(ns user
  (:require [ :as ion-dev]))

(def group "og-condense-sandbox-Compute-XXXZZZYYY")

(defn release
  "Do push and deploy of app.  Supports stable and unstable releases.  Returns when deploy finishes running."
    (let [push-data (ion-dev/push args)
          deploy-args (merge (select-keys args [:creds-profile :region :uname])
                             (select-keys push-data [:rev])
                             {:group group})]
      (let [deploy-data (ion-dev/deploy deploy-args)
            deploy-status-args (merge (select-keys args [:creds-profile :region])
                                      (select-keys deploy-data [:execution-arn]))]
        (loop []
          (let [status-data (ion-dev/deploy-status deploy-status-args)]
            (if (= "RUNNING" (:code-deploy-status status-data))
              (do (Thread/sleep 5000) (recur))
    (catch Exception e
      {:deploy-status "ERROR"
       :message (.getMessage e)})))


Now let's create a simple script for cases where we're not at a REPL. The only sophistication here is ensuring the script completes cleanly and returns a valid status code.

Note: This doesn't provide a way to pass args into the release process. Needs thought.

(require 'user)

(let [ret (user/release {})]
  (println ret)
  (if (= (:deploy-status ret) "SUCCEEDED")
    (System/exit 0)
    (System/exit 1)))


Finally, a simple makefile target to ensure releases are run consistently.

	clojure -A:dev scripts/release.clj

This comment has been minimized.

Copy link

@jzwolak jzwolak commented Nov 11, 2020

There's a problem with the interaction between the script and the release fn. The release fn returns when :code-deploy-status has finished running, but the script checks the result of :deploy-status. The :deploy-status may still be running (and does in my case) for some time after the :code-deploy-status has completed. Mine takes another second or two. Therefore, the script returns "1", which the Makefile recognizes as failed. I updated my version of the release fn to loop on :deploy-status instead of :code-deploy-status.

Thanks for this code! It's made a real difference for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment