datomic

itaied 2025-11-24T06:37:24.284789Z

hey all how do you setup you datomic + ions env? we have in the repo the ion-config.edn and also the config.edn with aws data we want to have test env as well and we consider how to inject those configuration based on the env in order to deploy the ions i need the production aws metadata, so i need it in some CI env vars, which i would rather avoid and just inject in the prod env, but as i understand it's required earlier i would like to hear some setups for dev, test and prod

cch1 2025-11-24T14:21:03.154389Z

We use separate AWS accounts (both under one top-level management account) for our production, staging and development environments. We use the same ion-config.edn for both (by using consistent naming in the CF template). For tests, we use db-local. For the deploy (to development or production or staging) the trickiest part is getting old-school AWS Java SDK v1 credentials setup (we normally use SSO credentialing, and something like https://pypi.org/project/aws2-wrap/ to bridge the gap.

cch1 2025-11-24T14:24:33.582819Z

To inject configuration by environment, we use SSM (using different accounts makes this really easy), SecretsManager and (for stable, non-sensitive stuff) an EDN config file that accompanies the deploy and is read at startup by aero. It leverages the aero profile feature to differentiate amongst the environments. We read the stage via the CF template using the Ion EnvironementMap option. In our case, in production, it is set to {:stage :production}. For tests (which use db-local) we just set the DATOMIC_ENV_MAP to {:stage :test}.

cch1 2025-11-24T14:27:34.803549Z

If I understand the crux of your question, the key is the datomic EnvironmentMap feature. With just one value set in there (and never changed) you can branch on the environment and feed that to aero for reading an environment-specific configuration.

itaied 2025-11-24T14:35:06.745229Z

i actually just started walking that path - figured out aero + DATOMIC_ENV_VAR and ion/get-env may be the solution thank you for sharing! i will make use of that

cch1 2025-11-24T14:35:23.279449Z

That is the magic ticket IMO.

πŸ™Œ 1
itaied 2025-11-24T21:14:49.861989Z

in your setup, how and when do you execute the db migrations (i guess using caribou)? i want to run the migrations before the ions are deployed, but i don't want to allow access outside the compute group either (e.g ci)

cch1 2025-11-24T23:02:40.453299Z

We run migrations at system startup -it's not an external process.

cch1 2025-11-24T23:41:18.195629Z

(and yes, we use caribou for that)

itaied 2025-11-25T05:10:12.750559Z

do you use ions? i wonder how can i execute migrations on startup (before traffic is routed)

cch1 2025-11-25T13:07:46.356609Z

Yes, we do use ions. You are headed towards the subject of lifecycle hooks. Which are lacking for atomic ions. @jaret has that on his wish list, but until then there will be challenges.

cch1 2025-11-25T13:08:42.508939Z

The approach we use of having Caribou migrate before the system starts up ensures that migrations are done before an individual node can run new code to service requests. But coordinating that across all nodes isn’t really possible. The solution is to always use backwards compatible migrations!

itaied 2025-11-25T13:13:38.602839Z

adding an attribute to an endpoint before updating datomic schema will break the api datomic cannot execute a query for an attribute that doesn't exist, but adding attrs is backward compatible for example, http endpoint for "get-user" that return a new attribute

cch1 2025-11-25T14:22:01.386689Z

For that kind of problem, you could adopt the approach that we use: transact the schema as part of system startup. Then you know that you will never run new code against old schema. You still run the risk of running old code against the new schema, but if you follow an "accretion only" methodology then that is not a problem. We've been successful with that approach for years. You could also transact the new schema in a blocking step in the CD portion of your pipeline and get the same guarantees.

πŸ‘ 1
itaied 2025-11-25T16:51:49.909969Z

i understand, thank you i wonder what is the system startup part when using lambdas, because it just reference to fns

cch1 2025-11-25T16:53:16.690709Z

For that to work, I create a closure around all the handlers (lambda and http direct) that force a system startup on the inbound event.

cch1 2025-11-25T16:53:37.428289Z

This is where it would be really nice if ions had lifecycle hooks.

cch1 2025-11-25T16:53:44.295549Z

But, the closure approach works.

itaied 2025-11-25T17:26:59.407739Z

oh i see, so for every incoming event you run the migrations? which actually doesn't execute since there's no new migration

cch1 2025-11-25T17:28:08.745309Z

No. The system is started once when the first event arrives. During system startup, migrations are run to apply the deltas. What you describe could work, but it would be quite slow.

cch1 2025-11-25T17:28:52.777029Z

(starting the system exactly once is achieved by a closure around the event handlers and an atom)

itaied 2025-11-25T17:29:25.092649Z

assuming the lambdas kept alive. for example for cold starts it will execute multiple times, correct?

cch1 2025-11-25T17:30:54.345699Z

Clojure code does not run in the lambdas at all. The lambdas run code provided by the Datomic Cloud Ion platform. The code is simple: relay the event to the long-running EC2 instance and wait for a response. The EC2 instance is where your Clojure code runs.

cch1 2025-11-25T17:31:42.504539Z

I think this is a common misconception about ions: lambdas are nicely integrated into the platform, but you never have to write lambda code or worry about cold starts and their "ephemerality".

cch1 2025-11-25T17:32:24.148369Z

(FWIW, I have never even seen the code that runs in the lambdas. I just know its effects)

itaied 2025-11-25T17:32:34.699799Z

ohh right! i got confused there but i knew it thank's for bringing that up

πŸ‘ 1
itaied 2025-11-25T17:45:08.930239Z

so it's max executed by the number of machines (atom per jvm), right? a lifecycle could have been good here, but i guess we can also leverage the cloud or ci to max it at 1...

cch1 2025-11-25T19:26:36.077069Z

Correct. A combination of accrete-only practices and a tool (caribou, in our case) that minimizes the db interaction required to skip already-applied migrations makes it work well.

βœ… 1
itaied 2025-11-25T21:08:53.071959Z

there's something nice in handling schema migrations directly in the code (as txs) without external tools

cch1 2025-11-26T14:00:31.052579Z

The real payoff for us has been in testing and development. But there are other benefits derived from the very strong binding of code + schema.