Created
August 13, 2025 10:10
-
-
Save bennyandresen/9a861983afde4b408356257e6e66fc55 to your computer and use it in GitHub Desktop.
services-flake datomic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { pkgs, lib, config, name, ... }: | |
| let | |
| types = lib.types; | |
| versions = { | |
| datomic = "1.0.7387"; | |
| sqlite-jdbc = "3.50.2.0"; | |
| }; | |
| datomicZip = pkgs.fetchurl { | |
| url = | |
| "https://datomic-pro-downloads.s3.amazonaws.com/${versions.datomic}/datomic-pro-${versions.datomic}.zip"; | |
| sha256 = "sha256-ral2iqJD8FsHtI1tH0NRp39LvVJuIhxE+KiCXVQVOPA="; | |
| }; | |
| sqliteJdbc = pkgs.fetchurl { | |
| url = | |
| "https://github.com/xerial/sqlite-jdbc/releases/download/${versions.sqlite-jdbc}/sqlite-jdbc-${versions.sqlite-jdbc}.jar"; | |
| sha256 = "sha256-mA+EnJRLKPFFW/dLn/Hwc5rrbAGY5CFhWDvH4NVzkWM="; | |
| }; | |
| setupScript = pkgs.writeShellApplication { | |
| name = "setup-datomic"; | |
| text = '' | |
| mkdir -p ${config.dataDir} | |
| if [ ! -f ${config.dataDir}/sqlite.db ]; then | |
| echo "Creating sqlite database at ${config.dataDir}/sqlite.db" | |
| ${pkgs.sqlite}/bin/sqlite3 ${config.dataDir}/sqlite.db " | |
| PRAGMA foreign_keys = ON; | |
| PRAGMA journal_mode = WAL; | |
| PRAGMA synchronous = NORMAL; | |
| PRAGMA mmap_size = 134217728; | |
| PRAGMA journal_size_limit = 67108864; | |
| PRAGMA cache_size = 2000; | |
| CREATE TABLE datomic_kvs ( | |
| id TEXT NOT NULL, | |
| rev INTEGER, | |
| map TEXT, | |
| val BYTEA, | |
| CONSTRAINT pk_id PRIMARY KEY (id) | |
| ); | |
| " | |
| fi | |
| ''; | |
| }; | |
| startScript = pkgs.writeShellApplication { | |
| name = "start-datomic"; | |
| runtimeInputs = [ pkgs.jdk23_headless ]; | |
| text = '' | |
| echo Starting datomic transactor on port ${builtins.toString config.port} | |
| export DATOMIC_HOME="${datomicFiles}" | |
| export DATOMIC_DB="${config.dbName}" | |
| export DATOMIC_LOG_DIR="/tmp/datomic/${name}/log" | |
| CLASSPATH='${datomicFiles}/resources:${datomicFiles}/datomic-transactor-pro-${versions.datomic}.jar:${datomicFiles}/lib/*:${datomicFiles}/bin' | |
| # run db creation script in background | |
| # ${datomicFiles}/bin/shell ${createDatomicDbScript} & | |
| # can't use bundled shell script because it sets cwd, thus breaking relative paths | |
| java -server -cp "$CLASSPATH" jline.ConsoleRunner clojure.main ${datomicFiles}/bin/shell.clj ${createDatomicDbScript} & | |
| # Run datomic transactor | |
| # can't use bundled shell script because it sets cwd, thus breaking relative paths | |
| exec java -server -cp "$CLASSPATH" \ | |
| ${ | |
| builtins.toString config.javaOpts | |
| } clojure.main --main datomic.launcher ${transactorProperties} | |
| ''; | |
| }; | |
| transactorProperties = pkgs.writeTextFile { | |
| name = "transactor.properties"; | |
| text = '' | |
| port=${builtins.toString config.port} | |
| host=${config.host} | |
| storage-access=remote | |
| protocol=sql | |
| sql-driver-class=org.sqlite.JDBC | |
| sql-url=jdbc:sqlite:${config.dataDir}/sqlite.db | |
| # See https://docs.datomic.com/on-prem/capacity.html | |
| memory-index-threshold=${config.memoryIndexThreshold} | |
| memory-index-max=${config.memoryIndexMax} | |
| object-cache-max=${config.objectCacheMax} | |
| ping-host=${config.health.host} | |
| ping-port=${builtins.toString config.health.port} | |
| ''; | |
| }; | |
| createDatomicDbScript = pkgs.writeTextFile { | |
| name = "create-db.bsh"; | |
| text = '' | |
| db_name = System.getenv("DATOMIC_DB"); | |
| if (db_name == null || db_name.isEmpty()) { | |
| db_name = "app"; | |
| } | |
| db_uri = "datomic:sql://" + db_name + "?jdbc:sqlite:${config.dataDir}/sqlite.db"; | |
| System.out.println("db_uri = " + db_uri); | |
| for (int i = 0; i < 12; i++) { | |
| Thread.sleep(5000); | |
| System.out.println("Testing connection to database '" + db_name + "'..."); | |
| try { | |
| if (Peer.createDatabase(db_uri)) { | |
| System.out.println("Created database '" + db_name + "'"); | |
| } | |
| System.out.println("Connect using DB URI " + db_uri); | |
| System.exit(0); | |
| } catch (Exception e) { | |
| // System.out.println(e.getMessage()); | |
| } | |
| } | |
| System.out.println("WARNING: Could not create or connect to database " + db_name + " after 60s."); | |
| ''; | |
| }; | |
| # Prepare datomic files | |
| datomicFiles = pkgs.runCommand "datomic-files" { } '' | |
| mkdir -p $out | |
| ${pkgs.unzip}/bin/unzip ${datomicZip} -d $out | |
| mv $out/datomic-pro-${versions.datomic}/* $out/ | |
| rm -rf $out/datomic-pro-${versions.datomic} | |
| rm -rf $out/presto-server | |
| mkdir -p $out/lib | |
| cp ${sqliteJdbc} $out/lib/sqlite-jdbc-${versions.sqlite-jdbc}.jar | |
| ''; | |
| in { | |
| options = { | |
| host = lib.mkOption { | |
| default = "0.0.0.0"; | |
| type = types.str; | |
| description = "Host for datomic to listen on"; | |
| }; | |
| port = lib.mkOption { | |
| type = types.port; | |
| default = 4334; | |
| description = "Port for datomic to listen on"; | |
| }; | |
| dbName = lib.mkOption { | |
| type = types.str; | |
| default = "app"; | |
| description = "Name of the Datomic database"; | |
| }; | |
| javaOpts = lib.mkOption { | |
| type = with types; either str (listOf str); | |
| default = [ "-Xmx1g" "-Xms1g" "-XX:+UseG1GC" "-XX:MaxGCPauseMillis=50" ]; | |
| description = "JVM options for the Datomic transactor"; | |
| example = lib.literalExpression '' | |
| [ | |
| "-Xmx1g" | |
| "-Xms1g" | |
| "-XX:+UseG1GC" | |
| "-XX:MaxGCPauseMillis=50" | |
| ] | |
| ''; | |
| }; | |
| memoryIndexThreshold = lib.mkOption { | |
| type = types.str; | |
| default = "32m"; | |
| description = "Memory index threshold"; | |
| }; | |
| memoryIndexMax = lib.mkOption { | |
| type = types.str; | |
| default = "256m"; | |
| description = "Maximum memory index"; | |
| }; | |
| objectCacheMax = lib.mkOption { | |
| type = types.str; | |
| default = "128m"; | |
| description = "Maximum object cache"; | |
| }; | |
| health = { | |
| host = lib.mkOption { | |
| default = "localhost"; | |
| type = types.str; | |
| description = "Host for datomic health check endpoint to listen on"; | |
| }; | |
| port = lib.mkOption { | |
| type = types.port; | |
| default = 4336; | |
| description = "Port for datomic health check endpoint to listen on"; | |
| }; | |
| }; | |
| }; | |
| config = { | |
| outputs.settings = { | |
| processes."${name}-init" = { command = setupScript; }; | |
| processes."${name}" = { | |
| command = startScript; | |
| is_tty = true; | |
| readiness_probe = { | |
| http_get = { | |
| host = config.health.host; | |
| port = config.health.port; | |
| path = "/health"; | |
| }; | |
| initial_delay_seconds = 2; | |
| period_seconds = 10; | |
| timeout_seconds = 4; | |
| success_threshold = 1; | |
| failure_threshold = 5; | |
| }; | |
| depends_on."${name}-init".condition = "process_completed_successfully"; | |
| availability = { | |
| restart = "on_failure"; | |
| max_restarts = 2; | |
| }; | |
| }; | |
| }; | |
| }; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| description = "example flake datomic-pro with juspay/services-flake"; | |
| inputs = { | |
| nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; | |
| flake-parts.url = "github:hercules-ci/flake-parts"; | |
| flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; | |
| process-compose-flake.url = "github:Platonic-Systems/process-compose-flake"; | |
| services-flake.url = "github:juspay/services-flake"; | |
| systems.url = "github:nix-systems/default"; | |
| }; | |
| outputs = inputs@{ flake-parts, ... }: | |
| flake-parts.lib.mkFlake { inherit inputs; } { | |
| systems = import inputs.systems; | |
| imports = [ inputs.process-compose-flake.flakeModule ]; | |
| perSystem = { self', pkgs, lib, config, ... }: | |
| let inherit (inputs.services-flake.lib) multiService; | |
| in { | |
| process-compose."default" = { | |
| imports = [ | |
| inputs.services-flake.processComposeModules.default | |
| (multiService ./datomic.nix) | |
| ]; | |
| cli.options.no-server = true; | |
| services.datomic."example1" = { | |
| enable = true; | |
| dbName = "one"; | |
| dataDir = "data/one"; | |
| }; | |
| services.datomic."example2" = { | |
| enable = true; | |
| dbName = "two"; | |
| port = 4337; | |
| health.port = 4339; | |
| dataDir = "data/two"; | |
| }; | |
| }; | |
| }; | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment