Skip to content

Commit ac67be0

Browse files
authored
feat: add multi stream append support (#330)
1 parent 411c2c2 commit ac67be0

37 files changed

+1289
-66
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ jobs:
1515
name: Tests (CI)
1616
uses: ./.github/workflows/tests.yml
1717
with:
18-
image: ${{ fromJSON(vars.KURRENTDB_DOCKER_IMAGES).ci.fullname }}
18+
runtime: ci
1919
secrets: inherit
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Load KurrentDB Runtime Configuration
2+
on:
3+
workflow_call:
4+
inputs:
5+
runtime:
6+
description: "The runtime's name. Current options are: `ci`, `previous-lts`, `latest`"
7+
type: string
8+
9+
outputs:
10+
runtime:
11+
description: The runtime's name
12+
value: ${{ inputs.runtime }}
13+
14+
registry:
15+
description: The Docker registry
16+
value: ${{ jobs.load.outputs.registry }}
17+
18+
image:
19+
description: The Docker image
20+
value: ${{ jobs.load.outputs.image }}
21+
22+
tag:
23+
description: The Docker image tag
24+
value: ${{ jobs.load.outputs.tag }}
25+
26+
full_image_name:
27+
description: The full Docker image name (including registry, image, and tag)
28+
value: ${{ jobs.load.outputs.full_image_name }}
29+
30+
jobs:
31+
load:
32+
runs-on: ubuntu-latest
33+
outputs:
34+
registry: ${{ steps.set.outputs.registry }}
35+
image: ${{ steps.set.outputs.image }}
36+
tag: ${{ steps.set.outputs.tag }}
37+
full_image_name: ${{ steps.set.outputs.full_image_name }}
38+
39+
steps:
40+
- name: Set KurrentDB Runtime Configuration Properties
41+
id: set
42+
run: |
43+
echo "registry=${{ fromJSON(vars.KURRENTDB_DOCKER_IMAGES)[inputs.runtime].registry }}" >> $GITHUB_OUTPUT
44+
echo "tag=${{ fromJSON(vars.KURRENTDB_DOCKER_IMAGES)[inputs.runtime].tag }}" >> $GITHUB_OUTPUT
45+
echo "image=${{ fromJSON(vars.KURRENTDB_DOCKER_IMAGES)[inputs.runtime].image }}" >> $GITHUB_OUTPUT
46+
echo "full_image_name=${{ fromJSON(vars.KURRENTDB_DOCKER_IMAGES)[inputs.runtime].fullname }}" >> $GITHUB_OUTPUT

.github/workflows/lts.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
name: Tests (LTS)
1616
uses: ./.github/workflows/tests.yml
1717
with:
18-
image: ${{ fromJSON(vars.KURRENTDB_DOCKER_IMAGES).lts.fullname }}
18+
runtime: lts
1919
secrets: inherit
2020

2121
# Will be removed in the future
@@ -24,5 +24,7 @@ jobs:
2424

2525
uses: ./.github/workflows/plugins-tests.yml
2626
with:
27-
image: "docker.eventstore.com/eventstore-ee/eventstoredb-commercial:24.2.0-jammy"
27+
registry: docker.eventstore.com/eventstore-ee
28+
image: eventstoredb-commercial
29+
tag: 24.2.0-jammy
2830
secrets: inherit

.github/workflows/plugins-tests.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@ name: enterprise plugins tests workflow
33
on:
44
workflow_call:
55
inputs:
6+
registry:
7+
required: true
8+
type: string
69
image:
710
required: true
811
type: string
12+
tag:
13+
required: true
14+
type: string
915

1016
jobs:
1117
single_node:
@@ -46,7 +52,7 @@ jobs:
4652
- name: Execute Gradle build
4753
run: ./gradlew ci --tests ${{ matrix.test }}Tests
4854
env:
49-
KURRENTDB_IMAGE: ${{ inputs.image }}
55+
KURRENTDB_IMAGE: ${{inputs.registry}}/${{ inputs.image }}:${{ inputs.tag }}
5056
SECURE: true
5157

5258
- uses: actions/upload-artifact@v4
@@ -81,7 +87,9 @@ jobs:
8187
- name: Set up cluster with Docker Compose
8288
run: docker compose up -d
8389
env:
84-
KURRENTDB_IMAGE: ${{ inputs.image }}
90+
KURRENTDB_DOCKER_REGISTRY: ${{ inputs.registry }}
91+
KURRENTDB_DOCKER_IMAGE: ${{ inputs.image }}
92+
KURRENTDB_DOCKER_TAG: ${{ inputs.tag }}
8593

8694
- name: Generate user certificates
8795
run: docker compose --file configure-user-certs-for-tests.yml up

.github/workflows/previous-lts.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ jobs:
1515
name: Tests (Previous LTS)
1616
uses: ./.github/workflows/tests.yml
1717
with:
18-
image: ${{ fromJSON(vars.KURRENTDB_DOCKER_IMAGES)['previous-lts'].fullname }}
18+
runtime: previous-lts
1919
secrets: inherit

.github/workflows/tests.yml

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@ name: tests workflow
33
on:
44
workflow_call:
55
inputs:
6-
image:
6+
runtime:
77
required: true
88
type: string
99

1010
jobs:
11+
load_configuration:
12+
uses: ./.github/workflows/load-configuration.yml
13+
with:
14+
runtime: ${{ inputs.runtime }}
15+
1116
single_node:
17+
needs: load_configuration
1218
name: Single node
1319

1420
strategy:
1521
fail-fast: false
1622
matrix:
17-
test: [Streams, PersistentSubscriptions, Telemetry]
23+
test: [Streams, PersistentSubscriptions, Telemetry, MultiStreamAppend]
1824

1925
runs-on: ubuntu-latest
2026
steps:
@@ -41,16 +47,10 @@ jobs:
4147
- name: Execute Gradle build
4248
run: ./gradlew ci --tests ${{ matrix.test }}Tests
4349
env:
44-
KURRENTDB_IMAGE: ${{ inputs.image }}
45-
46-
- uses: actions/upload-artifact@v4
47-
if: failure()
48-
with:
49-
name: esdb_logs.tar.gz
50-
path: /tmp/esdb_logs.tar.gz
51-
if-no-files-found: error
50+
KURRENTDB_IMAGE: ${{ needs.load_configuration.outputs.full_image_name }}
5251

5352
secure:
53+
needs: load_configuration
5454
name: Secure
5555

5656
strategy:
@@ -86,7 +86,7 @@ jobs:
8686
- name: Execute Gradle build
8787
run: ./gradlew ci --tests ${{ matrix.test }}Tests
8888
env:
89-
KURRENTDB_IMAGE: ${{ inputs.image }}
89+
KURRENTDB_IMAGE: ${{ needs.load_configuration.outputs.full_image_name }}
9090
SECURE: true
9191

9292
- uses: actions/upload-artifact@v4
@@ -96,12 +96,13 @@ jobs:
9696
path: /tmp/esdb_logs.tar.gz
9797

9898
cluster:
99+
needs: load_configuration
99100
name: Cluster
100101

101102
strategy:
102103
fail-fast: false
103104
matrix:
104-
test: [Streams, PersistentSubscriptions]
105+
test: [Streams, PersistentSubscriptions, MultiStreamAppend]
105106

106107
runs-on: ubuntu-latest
107108
steps:
@@ -117,7 +118,9 @@ jobs:
117118
- name: Set up cluster with Docker Compose
118119
run: docker compose up -d
119120
env:
120-
KURRENTDB_IMAGE: ${{ inputs.image }}
121+
KURRENTDB_DOCKER_REGISTRY: ${{ needs.load_configuration.outputs.registry }}
122+
KURRENTDB_DOCKER_IMAGE: ${{ needs.load_configuration.outputs.image }}
123+
KURRENTDB_DOCKER_TAG: ${{ needs.load_configuration.outputs.tag }}
121124

122125
- name: Set up JDK 8
123126
uses: actions/setup-java@v3

docker-compose.yml

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
version: "3.5"
2-
31
services:
42
volumes-provisioner:
53
image: hasnat/volumes-provisioner
@@ -26,71 +24,57 @@ services:
2624
- volumes-provisioner
2725

2826
esdb-node1: &template
29-
image: ${KURRENTDB_IMAGE:-docker.kurrent.io/eventstore/eventstoredb-ee:lts}
27+
image: ${KURRENTDB_DOCKER_REGISTRY:-docker.kurrent.io/eventstore}/${KURRENTDB_DOCKER_IMAGE:-eventstoredb-ee}:${KURRENTDB_DOCKER_TAG:-lts}
3028
env_file:
3129
- vars.env
3230
environment:
3331
- EVENTSTORE_GOSSIP_SEED=172.30.240.12:2113,172.30.240.13:2113
34-
- EVENTSTORE_INT_IP=172.30.240.11
35-
- EVENTSTORE_CERTIFICATE_FILE=/etc/eventstore/certs/node1/node.crt
36-
- EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/eventstore/certs/node1/node.key
37-
- EVENTSTORE_ADVERTISE_HTTP_PORT_TO_CLIENT_AS=2111
32+
- EVENTSTORE_REPLICATION_IP=172.30.240.11
33+
- EVENTSTORE_CERTIFICATE_FILE=/etc/kurrentdb/certs/node1/node.crt
34+
- EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/kurrentdb/certs/node1/node.key
35+
- EVENTSTORE_ADVERTISE_NODE_PORT_TO_CLIENT_AS=2111
3836
ports:
3937
- 2111:2113
4038
networks:
4139
clusternetwork:
4240
ipv4_address: 172.30.240.11
4341
volumes:
44-
- ./certs:/etc/eventstore/certs
42+
- ./certs:/etc/kurrentdb/certs
4543
restart: unless-stopped
4644
depends_on:
4745
- cert-gen
4846

4947
esdb-node2:
5048
<<: *template
51-
env_file:
52-
- vars.env
5349
environment:
5450
- EVENTSTORE_GOSSIP_SEED=172.30.240.11:2113,172.30.240.13:2113
55-
- EVENTSTORE_INT_IP=172.30.240.12
56-
- EVENTSTORE_CERTIFICATE_FILE=/etc/eventstore/certs/node2/node.crt
57-
- EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/eventstore/certs/node2/node.key
58-
- EVENTSTORE_ADVERTISE_HTTP_PORT_TO_CLIENT_AS=2112
51+
- EVENTSTORE_REPLICATION_IP=172.30.240.12
52+
- EVENTSTORE_CERTIFICATE_FILE=/etc/kurrentdb/certs/node2/node.crt
53+
- EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/kurrentdb/certs/node2/node.key
54+
- EVENTSTORE_ADVERTISE_NODE_PORT_TO_CLIENT_AS=2112
5955
ports:
6056
- 2112:2113
6157
networks:
6258
clusternetwork:
6359
ipv4_address: 172.30.240.12
64-
volumes:
65-
- ./certs:/etc/eventstore/certs
66-
restart: unless-stopped
67-
depends_on:
68-
- cert-gen
6960

7061
esdb-node3:
7162
<<: *template
72-
env_file:
73-
- vars.env
7463
environment:
7564
- EVENTSTORE_GOSSIP_SEED=172.30.240.11:2113,172.30.240.12:2113
76-
- EVENTSTORE_INT_IP=172.30.240.13
77-
- EVENTSTORE_CERTIFICATE_FILE=/etc/eventstore/certs/node3/node.crt
78-
- EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/eventstore/certs/node3/node.key
79-
- EVENTSTORE_ADVERTISE_HTTP_PORT_TO_CLIENT_AS=2113
65+
- EVENTSTORE_REPLICATION_IP=172.30.240.13
66+
- EVENTSTORE_CERTIFICATE_FILE=/etc/kurrentdb/certs/node3/node.crt
67+
- EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/kurrentdb/certs/node3/node.key
68+
- EVENTSTORE_ADVERTISE_NODE_PORT_TO_CLIENT_AS=2113
8069
ports:
8170
- 2113:2113
8271
networks:
8372
clusternetwork:
8473
ipv4_address: 172.30.240.13
85-
volumes:
86-
- ./certs:/etc/eventstore/certs
87-
restart: unless-stopped
88-
depends_on:
89-
- cert-gen
9074

9175
networks:
9276
clusternetwork:
93-
name: eventstoredb.local
77+
name: kurrentdb.local
9478
driver: bridge
9579
ipam:
9680
driver: default
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package io.kurrent.dbclient;
2+
3+
public class AppendStreamFailure {
4+
private final io.kurrentdb.protocol.streams.v2.AppendStreamFailure inner;
5+
6+
AppendStreamFailure(io.kurrentdb.protocol.streams.v2.AppendStreamFailure inner) {
7+
this.inner = inner;
8+
}
9+
10+
public String getStreamName() {
11+
return this.inner.getStream();
12+
}
13+
14+
public void visit(MultiAppendStreamErrorVisitor visitor) {
15+
if (this.inner.getErrorCase() == io.kurrentdb.protocol.streams.v2.AppendStreamFailure.ErrorCase.STREAM_REVISION_CONFLICT) {
16+
visitor.onWrongExpectedRevision(this.inner.getStreamRevisionConflict().getStreamRevision());
17+
return;
18+
}
19+
20+
if (this.inner.getErrorCase() == io.kurrentdb.protocol.streams.v2.AppendStreamFailure.ErrorCase.ACCESS_DENIED) {
21+
visitor.onAccessDenied(this.inner.getAccessDenied());
22+
}
23+
24+
if (this.inner.getErrorCase() == io.kurrentdb.protocol.streams.v2.AppendStreamFailure.ErrorCase.STREAM_DELETED) {
25+
visitor.onStreamDeleted();
26+
return;
27+
}
28+
29+
if (this.inner.getErrorCase() == io.kurrentdb.protocol.streams.v2.AppendStreamFailure.ErrorCase.TRANSACTION_MAX_SIZE_EXCEEDED) {
30+
visitor.onTransactionMaxSizeExceeded(this.inner.getTransactionMaxSizeExceeded().getMaxSize());
31+
return;
32+
}
33+
34+
throw new IllegalArgumentException("Append failure does not match any known error type");
35+
}
36+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.kurrent.dbclient;
2+
3+
import java.util.Iterator;
4+
5+
public class AppendStreamRequest {
6+
private final String streamName;
7+
private final Iterator<EventData> events;
8+
private final StreamState expectedState;
9+
10+
public AppendStreamRequest(String streamName, Iterator<EventData> events, StreamState expectedState) {
11+
this.streamName = streamName;
12+
this.events = events;
13+
this.expectedState = expectedState;
14+
}
15+
16+
public String getStreamName() {
17+
return streamName;
18+
}
19+
20+
public Iterator<EventData> getEvents() {
21+
return events;
22+
}
23+
24+
public StreamState getExpectedState() {
25+
return expectedState;
26+
}
27+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.kurrent.dbclient;
2+
3+
public class AppendStreamSuccess {
4+
private final io.kurrentdb.protocol.streams.v2.AppendStreamSuccess inner;
5+
6+
AppendStreamSuccess(io.kurrentdb.protocol.streams.v2.AppendStreamSuccess inner) {
7+
this.inner = inner;
8+
}
9+
10+
public String getStreamName() {
11+
return this.inner.getStream();
12+
}
13+
14+
public long getStreamRevision() {
15+
return this.inner.getStreamRevision();
16+
}
17+
18+
public long getPosition() {
19+
return this.inner.getPosition();
20+
}
21+
}

0 commit comments

Comments
 (0)