Skip to content

Commit 33a6e9a

Browse files
committed
Add DynamoDB table auto-creation on startup for order-history-service
- Add DynamoDBTableInitializer that creates table via @PostConstruct - Remove duplicate table creation logic from integration tests - Simplify component test (no longer needs manual table creation) Co-authored by Claude Code
1 parent 6c9903c commit 33a6e9a

5 files changed

Lines changed: 65 additions & 111 deletions

File tree

ftgo-order-history-service/order-history-service-dynamodb/src/integrationTest/java/net/chrisrichardson/ftgo/cqrs/orderhistory/dynamodb/OrderHistoryDaoDynamoDbTest.java

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
package net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb;
22

3-
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
4-
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
5-
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
6-
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
7-
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
8-
import com.amazonaws.services.dynamodbv2.model.KeyType;
9-
import com.amazonaws.services.dynamodbv2.model.Projection;
10-
import com.amazonaws.services.dynamodbv2.model.ProjectionType;
11-
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
12-
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
133
import io.eventuate.common.json.mapper.JSonMapper;
144
import net.chrisrichardson.ftgo.common.Money;
155
import net.chrisrichardson.ftgo.cqrs.orderhistory.Order;
@@ -35,7 +25,6 @@
3525
import org.testcontainers.junit.jupiter.Testcontainers;
3626
import org.testcontainers.utility.DockerImageName;
3727

38-
import java.util.Arrays;
3928
import java.util.List;
4029
import java.util.Optional;
4130

@@ -70,9 +59,6 @@ static void dynamoDbProperties(DynamicPropertyRegistry registry) {
7059
registry.add("aws.secret.access.key", localstack::getSecretKey);
7160
}
7261

73-
@Autowired
74-
private AmazonDynamoDB amazonDynamoDB;
75-
7662
private String consumerId;
7763
private Order order1;
7864
private String orderId;
@@ -83,12 +69,8 @@ static void dynamoDbProperties(DynamicPropertyRegistry registry) {
8369
private Optional<SourceEvent> eventSource;
8470
private long restaurantId;
8571

86-
private static boolean tableCreated = false;
87-
8872
@BeforeEach
8973
void setup() {
90-
createTableIfNotExists();
91-
9274
consumerId = "consumerId" + System.currentTimeMillis();
9375
orderId = "orderId" + System.currentTimeMillis();
9476
restaurantName = "Ajanta" + System.currentTimeMillis();
@@ -102,39 +84,6 @@ void setup() {
10284
dao.addOrder(order1, eventSource);
10385
}
10486

105-
private void createTableIfNotExists() {
106-
if (tableCreated) {
107-
return;
108-
}
109-
110-
try {
111-
CreateTableRequest request = new CreateTableRequest()
112-
.withTableName("ftgo-order-history")
113-
.withKeySchema(new KeySchemaElement("orderId", KeyType.HASH))
114-
.withAttributeDefinitions(Arrays.asList(
115-
new AttributeDefinition("orderId", ScalarAttributeType.S),
116-
new AttributeDefinition("consumerId", ScalarAttributeType.S),
117-
new AttributeDefinition("creationDate", ScalarAttributeType.N)
118-
))
119-
.withGlobalSecondaryIndexes(new GlobalSecondaryIndex()
120-
.withIndexName("ftgo-order-history-by-consumer-id-and-creation-time")
121-
.withKeySchema(Arrays.asList(
122-
new KeySchemaElement("consumerId", KeyType.HASH),
123-
new KeySchemaElement("creationDate", KeyType.RANGE)
124-
))
125-
.withProjection(new Projection().withProjectionType(ProjectionType.ALL))
126-
.withProvisionedThroughput(new ProvisionedThroughput(3L, 3L))
127-
)
128-
.withProvisionedThroughput(new ProvisionedThroughput(3L, 3L));
129-
130-
amazonDynamoDB.createTable(request);
131-
tableCreated = true;
132-
} catch (Exception e) {
133-
// Table might already exist
134-
tableCreated = true;
135-
}
136-
}
137-
13887
@Test
13988
void shouldFindOrder() {
14089
Optional<Order> order = dao.findOrder(orderId);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb;
2+
3+
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
4+
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
5+
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
6+
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
7+
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
8+
import com.amazonaws.services.dynamodbv2.model.KeyType;
9+
import com.amazonaws.services.dynamodbv2.model.Projection;
10+
import com.amazonaws.services.dynamodbv2.model.ProjectionType;
11+
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
12+
import com.amazonaws.services.dynamodbv2.model.ResourceInUseException;
13+
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
14+
import jakarta.annotation.PostConstruct;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
17+
18+
import java.util.Arrays;
19+
20+
public class DynamoDBTableInitializer {
21+
22+
private static final Logger logger = LoggerFactory.getLogger(DynamoDBTableInitializer.class);
23+
private static final String TABLE_NAME = "ftgo-order-history";
24+
private static final String GSI_NAME = "ftgo-order-history-by-consumer-id-and-creation-time";
25+
26+
private final AmazonDynamoDB amazonDynamoDB;
27+
28+
public DynamoDBTableInitializer(AmazonDynamoDB amazonDynamoDB) {
29+
this.amazonDynamoDB = amazonDynamoDB;
30+
}
31+
32+
@PostConstruct
33+
public void createTableIfNotExists() {
34+
try {
35+
CreateTableRequest request = new CreateTableRequest()
36+
.withTableName(TABLE_NAME)
37+
.withKeySchema(new KeySchemaElement("orderId", KeyType.HASH))
38+
.withAttributeDefinitions(Arrays.asList(
39+
new AttributeDefinition("orderId", ScalarAttributeType.S),
40+
new AttributeDefinition("consumerId", ScalarAttributeType.S),
41+
new AttributeDefinition("creationDate", ScalarAttributeType.N)
42+
))
43+
.withGlobalSecondaryIndexes(new GlobalSecondaryIndex()
44+
.withIndexName(GSI_NAME)
45+
.withKeySchema(Arrays.asList(
46+
new KeySchemaElement("consumerId", KeyType.HASH),
47+
new KeySchemaElement("creationDate", KeyType.RANGE)
48+
))
49+
.withProjection(new Projection().withProjectionType(ProjectionType.ALL))
50+
.withProvisionedThroughput(new ProvisionedThroughput(3L, 3L))
51+
)
52+
.withProvisionedThroughput(new ProvisionedThroughput(3L, 3L));
53+
54+
amazonDynamoDB.createTable(request);
55+
logger.info("Created DynamoDB table: {}", TABLE_NAME);
56+
} catch (ResourceInUseException e) {
57+
logger.info("DynamoDB table already exists: {}", TABLE_NAME);
58+
}
59+
}
60+
}

ftgo-order-history-service/order-history-service-dynamodb/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/dynamodb/OrderHistoryDynamoDBConfiguration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,9 @@ public OrderHistoryDao orderHistoryDao(DynamoDB dynamoDB) {
6060
public HealthIndicator dynamoDBHealthIndicator(DynamoDB dynamoDB) {
6161
return new DynamoDBHealthIndicator(dynamoDB);
6262
}
63+
64+
@Bean
65+
public DynamoDBTableInitializer dynamoDBTableInitializer(AmazonDynamoDB amazonDynamoDB) {
66+
return new DynamoDBTableInitializer(amazonDynamoDB);
67+
}
6368
}

ftgo-order-history-service/order-history-service-main/build.gradle

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,12 @@ dependencies {
2626
integrationTestImplementation 'io.eventuate.tram.core:eventuate-tram-test-util'
2727

2828
// Component test dependencies
29-
componentTestImplementation 'org.springframework.boot:spring-boot-starter-test'
3029
componentTestImplementation 'io.rest-assured:rest-assured'
3130
componentTestImplementation 'org.testcontainers:localstack'
32-
componentTestImplementation 'org.testcontainers:junit-jupiter'
3331
componentTestImplementation 'org.testcontainers:testcontainers'
3432
componentTestImplementation 'io.eventuate.messaging.kafka:eventuate-messaging-kafka-testcontainers'
3533
componentTestImplementation 'io.eventuate.common:eventuate-common-testcontainers'
36-
componentTestImplementation 'io.eventuate.tram.core:eventuate-tram-spring-consumer-kafka'
37-
componentTestImplementation 'io.eventuate.tram.core:eventuate-tram-spring-testing-support-producer-kafka'
38-
componentTestImplementation 'io.eventuate.tram.core:eventuate-tram-test-util'
39-
componentTestImplementation 'io.eventuate.tram.core:eventuate-tram-spring-testing-support-outbox'
40-
componentTestImplementation 'io.eventuate.tram.core:eventuate-tram-testing-support'
4134
componentTestImplementation "io.eventuate.platform.testcontainer.support:eventuate-platform-testcontainer-support-service:$eventuatePlatformTestContainerSupportVersion"
42-
componentTestImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.767'
4335
}
4436

4537
bootJar {

ftgo-order-history-service/order-history-service-main/src/componentTest/java/net/chrisrichardson/ftgo/cqrs/orderhistory/OrderHistoryServiceOutOfProcessComponentTest.java

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
11
package net.chrisrichardson.ftgo.cqrs.orderhistory;
22

3-
import com.amazonaws.auth.AWSStaticCredentialsProvider;
4-
import com.amazonaws.auth.BasicAWSCredentials;
5-
import com.amazonaws.client.builder.AwsClientBuilder;
6-
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
7-
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
8-
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
9-
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
10-
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
11-
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
12-
import com.amazonaws.services.dynamodbv2.model.KeyType;
13-
import com.amazonaws.services.dynamodbv2.model.Projection;
14-
import com.amazonaws.services.dynamodbv2.model.ProjectionType;
15-
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
16-
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
173
import io.eventuate.messaging.kafka.testcontainers.EventuateKafkaNativeCluster;
184
import io.eventuate.messaging.kafka.testcontainers.EventuateKafkaNativeContainer;
195
import io.eventuate.testcontainers.service.ServiceContainer;
@@ -31,7 +17,6 @@
3117
import org.testcontainers.utility.DockerImageName;
3218

3319
import java.nio.file.Paths;
34-
import java.util.Arrays;
3520

3621
import static org.assertj.core.api.Assertions.assertThat;
3722
import static org.testcontainers.containers.localstack.LocalStackContainer.Service.DYNAMODB;
@@ -70,47 +55,10 @@ public class OrderHistoryServiceOutOfProcessComponentTest {
7055

7156
@BeforeAll
7257
static void startContainers() {
73-
// Start infrastructure first
7458
Startables.deepStart(kafka, dynamodb).join();
75-
76-
// Create DynamoDB table before starting the service
77-
createDynamoDBTable();
78-
79-
// Now start the service
8059
service.start();
8160
}
8261

83-
private static void createDynamoDBTable() {
84-
String endpoint = dynamodb.getEndpointOverride(DYNAMODB).toString();
85-
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
86-
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, dynamodb.getRegion()))
87-
.withCredentials(new AWSStaticCredentialsProvider(
88-
new BasicAWSCredentials(dynamodb.getAccessKey(), dynamodb.getSecretKey())))
89-
.build();
90-
91-
CreateTableRequest request = new CreateTableRequest()
92-
.withTableName("ftgo-order-history")
93-
.withKeySchema(new KeySchemaElement("orderId", KeyType.HASH))
94-
.withAttributeDefinitions(Arrays.asList(
95-
new AttributeDefinition("orderId", ScalarAttributeType.S),
96-
new AttributeDefinition("consumerId", ScalarAttributeType.S),
97-
new AttributeDefinition("creationDate", ScalarAttributeType.N)
98-
))
99-
.withGlobalSecondaryIndexes(new GlobalSecondaryIndex()
100-
.withIndexName("ftgo-order-history-by-consumer-id-and-creation-time")
101-
.withKeySchema(Arrays.asList(
102-
new KeySchemaElement("consumerId", KeyType.HASH),
103-
new KeySchemaElement("creationDate", KeyType.RANGE)
104-
))
105-
.withProjection(new Projection().withProjectionType(ProjectionType.ALL))
106-
.withProvisionedThroughput(new ProvisionedThroughput(3L, 3L))
107-
)
108-
.withProvisionedThroughput(new ProvisionedThroughput(3L, 3L));
109-
110-
client.createTable(request);
111-
logger.info("Created DynamoDB table: ftgo-order-history");
112-
}
113-
11462
@BeforeEach
11563
void setup() {
11664
baseUri = String.format("http://localhost:%d", service.getFirstMappedPort());

0 commit comments

Comments
 (0)