Skip to content

Latest commit

 

History

History
112 lines (83 loc) · 4.28 KB

File metadata and controls

112 lines (83 loc) · 4.28 KB

AGENTS.md — perftest

Guidance for AI coding agents working in this repository.


Tech stack

Concern Choice
Language Java 17
Framework Spring Boot 3.2.5
Build Maven (pom.xml, no Gradle)
Persistence Spring Data JPA + Hibernate
Transactions Atomikos 6.x via com.atomikos:transactions-spring-boot3-starter:6.0.1
Database PostgreSQL (latest)
Validation Jakarta Bean Validation (spring-boot-starter-validation)
Testing JUnit 5 + Spring Boot Test + Testcontainers (postgres:latest)

Package layout

com.example.perftest
├── PerfTestApplication.java      entry point
├── entity/                       JPA entities
├── repository/                   Spring Data JPA repositories
├── service/                      @Transactional business logic
├── controller/                   @RestController REST endpoints
└── config/                       cross-cutting config (@RestControllerAdvice, etc.)

Key conventions

Transactions

  • All mutating service methods carry @Transactional (JTA, managed by Atomikos).
  • Read-only queries use @Transactional(readOnly = true).
  • Never annotate controllers or repositories with @Transactional; keep it in the service layer only.
  • The Atomikos starter is not Spring Boot's built-in spring-boot-starter-jta-atomikos. Do not replace it or add the built-in one — they conflict.

DataSource configuration

  • The XA data source is configured via spring.jta.atomikos.datasource.* properties in application.properties.
  • The XA class is org.postgresql.xa.PGXADataSource.
  • Do not introduce a manual DataSource or EntityManagerFactory bean — Atomikos auto-configuration owns those.

Entities

  • Use GenerationType.SEQUENCE with a dedicated @SequenceGenerator per entity (not IDENTITY), as XA transactions require sequence-based ID generation.
  • Audit timestamps (createdAt, updatedAt) are managed via @PrePersist / @PreUpdate.

REST layer

  • Base path convention: /api/{resource} (plural noun, lowercase).
  • Error responses use Spring's ProblemDetail (RFC 7807). Throw EntityNotFoundException for 404, IllegalArgumentException for 400, IllegalStateException for 409 — GlobalExceptionHandler maps them.
  • No @Transactional in controllers; delegate entirely to services.

Validation

  • Use Jakarta constraint annotations on entity fields.
  • Accept @Valid @RequestBody in controller POST/PUT methods.
  • Do not duplicate validation logic in services if the entity already constrains it.

Running the application

Start the database (Docker required):

docker build -f Dockerfile.postgres -t perftest-postgres .
docker run -d --name perftest-postgres -p 5432:5432 perftest-postgres

Run the application:

mvn spring-boot:run

Base URL: http://localhost:8080/api/accounts


Testing

Tests use Testcontainers — a real postgres:latest container is started automatically. No external database needed for tests.

@DynamicPropertySource overrides the Atomikos XA properties to point at the container:

registry.add("spring.jta.atomikos.datasource.xa-properties.serverName", postgres::getHost);
registry.add("spring.jta.atomikos.datasource.xa-properties.portNumber", postgres::getFirstMappedPort);

Run all tests:

mvn test

Run only the performance test:

mvn test -Dtest=AccountPerformanceTest

The performance test (AccountPerformanceTest) uses 20 threads, a CountDownLatch starting gun, and reports min/avg/p95/p99/max latency plus throughput (ops/s) for each phase.


What to avoid

  • Do not switch to spring-boot-starter-jta-atomikos — the project deliberately uses com.atomikos:transactions-spring-boot3-starter:6.0.1.
  • Do not use GenerationType.IDENTITY on any entity — incompatible with XA transactions.
  • Do not add spring.datasource.* properties — Atomikos owns the datasource; mixing the two will cause startup failure.
  • Do not mock the AccountService or AccountRepository in integration tests — use Testcontainers so XA transaction semantics are exercised against a real database.
  • Do not add @Transactional to test methods — it bypasses the JTA transaction manager and produces misleading results.