Getting Started
Dependencies
- Maven
<properties> <scala.binary.version>2.13</scala.binary.version> </properties> <dependencies> <dependency> <groupId>com.lightbend.akka</groupId> <artifactId>akka-persistence-r2dbc_${scala.binary.version}</artifactId> <version>1.1.0</version> </dependency> </dependencies>
- sbt
libraryDependencies += "com.lightbend.akka" %% "akka-persistence-r2dbc" % "1.1.0"
- Gradle
def versions = [ ScalaBinary: "2.13" ] dependencies { implementation "com.lightbend.akka:akka-persistence-r2dbc_${versions.ScalaBinary}:1.1.0" }
This plugin depends on Akka 2.8.1 or later, and note that it is important that all akka-*
dependencies are in the same version, so it is recommended to depend on them explicitly to avoid problems with transient dependencies causing an unlucky mix of versions.
The plugin is published for Scala 2.13 and 2.12.
Enabling
To enable the plugins to be used by default, add the following line to your Akka application.conf
:
akka.persistence.journal.plugin = "akka.persistence.r2dbc.journal"
akka.persistence.snapshot-store.plugin = "akka.persistence.r2dbc.snapshot"
akka.persistence.state.plugin = "akka.persistence.r2dbc.state"
More information in:
Local testing
The database can be run in Docker. Here’s a sample docker compose file:
- Postgres
-
source
version: '2.2' services: postgres-db: image: postgres:latest ports: - 5432:5432 environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres
- Yugabyte
-
source
version: '2' # Local Yugabyte database, see https://docs.yugabyte.com/latest/deploy/docker/docker-compose/ volumes: yb-master-data-1: yb-tserver-data-1: services: yb-master: image: yugabytedb/yugabyte:2.16.0.0-b90 container_name: yb-master-n1 volumes: - yb-master-data-1:/mnt/master command: [ "/home/yugabyte/bin/yb-master", "--fs_data_dirs=/mnt/master", "--master_addresses=yb-master-n1:7100", "--rpc_bind_addresses=yb-master-n1:7100", "--replication_factor=1" ] ports: - "7000:7000" environment: SERVICE_7000_NAME: yb-master yb-tserver: image: yugabytedb/yugabyte:2.16.0.0-b90 container_name: yb-tserver-n1 shm_size: '512mb' volumes: - yb-tserver-data-1:/mnt/tserver command: [ "/home/yugabyte/bin/yb-tserver", "--fs_data_dirs=/mnt/tserver", "--start_pgsql_proxy", "--rpc_bind_addresses=yb-tserver-n1:9100", "--tserver_master_addrs=yb-master-n1:7100", "--ysql_sequence_cache_minval=1", "--yb_num_shards_per_tserver=1" ] ports: - "9042:9042" - "5433:5433" - "9000:9000" environment: SERVICE_5433_NAME: ysql SERVICE_9042_NAME: ycql SERVICE_6379_NAME: yedis SERVICE_9000_NAME: yb-tserver depends_on: - yb-master
Start with:
- Postgres
-
docker-compose -f docker/docker-compose-postgres.yml up
- Yugabyte
-
docker-compose -f docker/docker-compose-yugabyte.yml up
Creating the schema
Tables and indexes:
- Postgres
-
source
CREATE TABLE IF NOT EXISTS event_journal( slice INT NOT NULL, entity_type VARCHAR(255) NOT NULL, persistence_id VARCHAR(255) NOT NULL, seq_nr BIGINT NOT NULL, db_timestamp timestamp with time zone NOT NULL, event_ser_id INTEGER NOT NULL, event_ser_manifest VARCHAR(255) NOT NULL, event_payload BYTEA NOT NULL, deleted BOOLEAN DEFAULT FALSE NOT NULL, writer VARCHAR(255) NOT NULL, adapter_manifest VARCHAR(255), tags TEXT ARRAY, meta_ser_id INTEGER, meta_ser_manifest VARCHAR(255), meta_payload BYTEA, PRIMARY KEY(persistence_id, seq_nr) ); -- `event_journal_slice_idx` is only needed if the slice based queries are used CREATE INDEX IF NOT EXISTS event_journal_slice_idx ON event_journal(slice, entity_type, db_timestamp, seq_nr); CREATE TABLE IF NOT EXISTS snapshot( slice INT NOT NULL, entity_type VARCHAR(255) NOT NULL, persistence_id VARCHAR(255) NOT NULL, seq_nr BIGINT NOT NULL, write_timestamp BIGINT NOT NULL, ser_id INTEGER NOT NULL, ser_manifest VARCHAR(255) NOT NULL, snapshot BYTEA NOT NULL, meta_ser_id INTEGER, meta_ser_manifest VARCHAR(255), meta_payload BYTEA, PRIMARY KEY(persistence_id) ); CREATE TABLE IF NOT EXISTS durable_state ( slice INT NOT NULL, entity_type VARCHAR(255) NOT NULL, persistence_id VARCHAR(255) NOT NULL, revision BIGINT NOT NULL, db_timestamp timestamp with time zone NOT NULL, state_ser_id INTEGER NOT NULL, state_ser_manifest VARCHAR(255), state_payload BYTEA NOT NULL, tags TEXT ARRAY, PRIMARY KEY(persistence_id, revision) ); -- `durable_state_slice_idx` is only needed if the slice based queries are used CREATE INDEX IF NOT EXISTS durable_state_slice_idx ON durable_state(slice, entity_type, db_timestamp, revision);
- Postgres JSONB
-
source
CREATE TABLE IF NOT EXISTS event_journal( slice INT NOT NULL, entity_type VARCHAR(255) NOT NULL, persistence_id VARCHAR(255) NOT NULL, seq_nr BIGINT NOT NULL, db_timestamp timestamp with time zone NOT NULL, event_ser_id INTEGER NOT NULL, event_ser_manifest VARCHAR(255) NOT NULL, event_payload JSONB NOT NULL, deleted BOOLEAN DEFAULT FALSE NOT NULL, writer VARCHAR(255) NOT NULL, adapter_manifest VARCHAR(255), tags TEXT ARRAY, meta_ser_id INTEGER, meta_ser_manifest VARCHAR(255), meta_payload BYTEA, PRIMARY KEY(persistence_id, seq_nr) ); -- `event_journal_slice_idx` is only needed if the slice based queries are used CREATE INDEX IF NOT EXISTS event_journal_slice_idx ON event_journal(slice, entity_type, db_timestamp, seq_nr); CREATE TABLE IF NOT EXISTS snapshot( slice INT NOT NULL, entity_type VARCHAR(255) NOT NULL, persistence_id VARCHAR(255) NOT NULL, seq_nr BIGINT NOT NULL, write_timestamp BIGINT NOT NULL, ser_id INTEGER NOT NULL, ser_manifest VARCHAR(255) NOT NULL, snapshot JSONB NOT NULL, meta_ser_id INTEGER, meta_ser_manifest VARCHAR(255), meta_payload BYTEA, PRIMARY KEY(persistence_id) ); CREATE TABLE IF NOT EXISTS durable_state ( slice INT NOT NULL, entity_type VARCHAR(255) NOT NULL, persistence_id VARCHAR(255) NOT NULL, revision BIGINT NOT NULL, db_timestamp timestamp with time zone NOT NULL, state_ser_id INTEGER NOT NULL, state_ser_manifest VARCHAR(255), state_payload JSONB NOT NULL, tags TEXT ARRAY, PRIMARY KEY(persistence_id, revision) ); -- `durable_state_slice_idx` is only needed if the slice based queries are used CREATE INDEX IF NOT EXISTS durable_state_slice_idx ON durable_state(slice, entity_type, db_timestamp, revision);
- Yugabyte
-
source
CREATE TABLE IF NOT EXISTS event_journal( slice INT NOT NULL, entity_type VARCHAR(255) NOT NULL, persistence_id VARCHAR(255) NOT NULL, seq_nr BIGINT NOT NULL, db_timestamp timestamp with time zone NOT NULL, event_ser_id INTEGER NOT NULL, event_ser_manifest VARCHAR(255) NOT NULL, event_payload BYTEA NOT NULL, deleted BOOLEAN DEFAULT FALSE NOT NULL, writer VARCHAR(255) NOT NULL, adapter_manifest VARCHAR(255), tags TEXT ARRAY, meta_ser_id INTEGER, meta_ser_manifest VARCHAR(255), meta_payload BYTEA, PRIMARY KEY(persistence_id HASH, seq_nr ASC) ); -- `event_journal_slice_idx` is only needed if the slice based queries are used CREATE INDEX IF NOT EXISTS event_journal_slice_idx ON event_journal(slice ASC, entity_type ASC, db_timestamp ASC, seq_nr ASC, persistence_id, deleted) SPLIT AT VALUES ((127), (255), (383), (511), (639), (767), (895)); CREATE TABLE IF NOT EXISTS snapshot( slice INT NOT NULL, entity_type VARCHAR(255) NOT NULL, persistence_id VARCHAR(255) NOT NULL, seq_nr BIGINT NOT NULL, write_timestamp BIGINT NOT NULL, ser_id INTEGER NOT NULL, ser_manifest VARCHAR(255) NOT NULL, snapshot BYTEA NOT NULL, meta_ser_id INTEGER, meta_ser_manifest VARCHAR(255), meta_payload BYTEA, PRIMARY KEY(persistence_id HASH) ); CREATE TABLE IF NOT EXISTS durable_state ( slice INT NOT NULL, entity_type VARCHAR(255) NOT NULL, persistence_id VARCHAR(255) NOT NULL, revision BIGINT NOT NULL, db_timestamp timestamp with time zone NOT NULL, state_ser_id INTEGER NOT NULL, state_ser_manifest VARCHAR(255), state_payload BYTEA NOT NULL, tags TEXT ARRAY, PRIMARY KEY(persistence_id HASH, revision ASC) ); -- `durable_state_slice_idx` is only needed if the slice based queries are used CREATE INDEX IF NOT EXISTS durable_state_slice_idx ON durable_state(slice ASC, entity_type ASC, db_timestamp ASC, revision ASC, persistence_id) SPLIT AT VALUES ((127), (255), (383), (511), (639), (767), (895));
The ddl script can be run in Docker with:
- Postgres
-
docker exec -i docker_postgres-db_1 psql -U postgres -t < ddl-scripts/create_tables_postgres.sql
- Yugabyte
-
docker exec -i yb-tserver-n1 /home/yugabyte/bin/ysqlsh -h yb-tserver-n1 -t < ddl-scripts/create_tables_yugabyte.sql
Dropping the schema
- Postgres
-
source
DROP INDEX event_journal_slice_idx; DROP TABLE IF EXISTS event_journal; DROP TABLE IF EXISTS snapshot; DROP TABLE IF EXISTS durable_state;
- Yugabyte
-
source
DROP INDEX event_journal_slice_idx; DROP TABLE IF EXISTS event_journal; DROP TABLE IF EXISTS snapshot; DROP TABLE IF EXISTS durable_state;