This is the backend application developed for the Rinha de Backend - 2025 challenge. The solution is built in Java and Spring Boot, and it is designed for high concurrency and resilience under strict resource constraints.
- Language: Java 21
- Framework: Spring Boot 3.5.3
- Web Server: Tomcat (embedded in Spring Boot)
- Database: PostgreSQL 16
- HTTP Client: Spring WebClient (Project Reactor)
- Load Balancer: Nginx
- Containerization: Docker and Docker Compose
- Other: Lombok (for boilerplate reduction), Maven
The solution is a multi-container application orchestrated by Docker Compose. The architecture is designed to handle high-volume requests and manage external service dependencies reliably.
api1andapi2: Two instances of a Spring Boot application, running on a standard JVM. They are responsible for processing business logic, handling communication with external services, and interacting with the database.db: A single PostgreSQL instance that serves as a shared, persistent data store for both API instances.nginx: This service acts as a load balancer and reverse proxy. It distributes all incoming client requests on port9999to either theapi1orapi2instance, ensuring even load distribution and high availability.- External Payment Processors: The
payment-processor-defaultandpayment-processor-fallbackservices are external dependencies that are started separately but are connected to the same Docker network as the API instances.
The application implements a dynamic and resilient strategy to choose which external Payment Processor to use for each transaction.
- Health Checks: A scheduled task runs periodically (e.g., every 30 seconds for local development) to check the health status of both the Default and Fallback processors via their
/payments/service-healthendpoints. The results are cached in memory. - Dynamic Selection: When a
POST /paymentsrequest is received, the application's logic prioritizes processors based on the cached health data:- If both processors are healthy, the one with the lowest
minResponseTimeis chosen to optimize for performance. - If only one processor is healthy, that one is chosen.
- If both are unhealthy, the application defaults to attempting the Default processor and relies on its resilience mechanisms to handle the failure gracefully.
- If both processors are healthy, the one with the lowest
- Resilience: The
WebClientcalls to external processors are configured with a 2-second timeout and 1 retry attempt. This prevents the application from hanging on slow or transiently failing external services, ensuring a responsive and stable API.
To get the complete solution running on your local machine, follow these steps.
-
Prerequisites: Ensure you have Docker Desktop and Git installed.
-
Clone the Rinha Repository: First, clone the official Rinha challenge repository:
git clone https://github.com/zanfranceschi/rinha-de-backend-2025.git
-
Start External Payment Processors:
- Navigate into the payment processors directory of the cloned repository:
cd rinha-de-backend-2025/payment-processor - Start the services (for Mac M-series, use the
arm64file):docker compose -f docker-compose-arm64.yml up -d
- You can verify they're running by checking
docker psor by visitinghttp://localhost:8001/payments/service-healthin your browser.
- Navigate into the payment processors directory of the cloned repository:
-
Build Your Backend Application's Docker Image:
- Navigate to the root of your Java project (
rinha-backend):cd /path/to/your/rinha-backend - Build the Docker image:
docker build -t rinha-backend-app .
- Navigate to the root of your Java project (
-
Navigate to Your Submission Directory:
- Go to your solution's folder within the Rinha repository.
cd rinha-de-backend-2025/participantes/your-name-java
- Go to your solution's folder within the Rinha repository.
-
Start Your Backend Solution:
docker compose up -d
- All services should start. Verify by running
docker ps.
- All services should start. Verify by running
-
Test the Application (via cURL):
- Purge Payments:
curl -X POST http://localhost:9999/purge-payments -H 'Content-Type: application/json' - Process Payment:
curl -X POST http://localhost:9999/payments -H 'Content-Type: application/json' -d '{"correlationId": "a-unique-uuid", "amount": 123.45}' - Payment Summary:
curl http://localhost:9999/payments-summary
- Purge Payments: