rinha2-back-end-python

Home

Python 3.14 implementation for the Rinha de Backend 2024/Q1 challenge. Manages a fictional bank API with transaction processing and balance statements under strict resource constraints (1.5 CPU, 550MB RAM total across all containers). Built with Flask 3.1, Gunicorn, and psycopg2.

Wiki Pages

PageDescription
ChallengeWhat is Rinha de Backend 2024/Q1
ArchitectureStack, services, resource constraints
Getting StartedPrerequisites and how to run
PerformanceResults, benchmarks, resource usage
CI/CD PipelineGitHub Actions workflows

Key Features

  • Python 3.14 with Flask 3.1 for lightweight HTTP routing
  • Gunicorn WSGI server for multi-worker concurrency
  • psycopg2 for efficient PostgreSQL connectivity
  • PostgreSQL stored procedures for server-side business logic
  • Consistent throughput under strict resource constraints

GitHub · Jonathan Peris

Architecture

Tech Stack

TechnologyVersionPurpose
Python3.14Language runtime
Flask3.1.3Web framework
Gunicorn25.3.0WSGI HTTP server (4 workers, 2 threads)
psycopg2-binary2.9.12PostgreSQL adapter
PostgreSQL16.7Database with stored procedures
NGINX1.27Reverse proxy / load balancer (least_conn)
Docker-Containerization (python:3.14-slim base)
k6-Load / stress testing

Overview

NGINX (:9999, least_conn)
├── webapi1-python (:8080, 0.4 CPU, 100MB) — Gunicorn 4w x 2t
├── webapi2-python (:8080, 0.4 CPU, 100MB) — Gunicorn 4w x 2t
└── PostgreSQL (0.5 CPU, 330MB)
    ├── InsertTransacao() — atomic balance + validation
    └── GetSaldoClienteById() — statement with JSONB

Services

ServiceRoleCPURAM
webapi1Python API instance (Gunicorn 4w x 2t)0.4100MB
webapi2Python API instance (Gunicorn 4w x 2t)0.4100MB
nginxReverse proxy / load balancer (least_conn)0.220MB
postgresqlDatabase with stored procedures0.5330MB
k6Load testing(not counted)(not counted)
grafana + influxdbObservability dashboards(not counted)(not counted)

Load Balancing

Nginx uses least_conn strategy to distribute requests across the two API instances.

Database

Business logic is implemented in PostgreSQL stored procedures (InsertTransacao, GetSaldoClienteById). The database uses UNLOGGED tables and is tuned for maximum write performance:

  • synchronous_commit=0 — no wait for WAL flush
  • fsync=0 — skip fsync on writes
  • full_page_writes=0 — skip full page writes

Connection Management

The API uses psycopg2 SimpleConnectionPool with 1-10 connections per instance for efficient database access.

Gunicorn Configuration

--workers=4 --threads=2 --worker-class=sync --bind=0.0.0.0:8080 --timeout=30

Challenge

Rinha de Backend 2024/Q1

The Rinha de Backend is a Brazilian backend programming challenge. The 2024/Q1 edition simulates a fictional bank called “Rinha Financeira” that manages up to 5 named clients, each seeded at startup with a credit limit and initial balance.

Endpoints

Three API endpoints are implemented:

EndpointMethodDescription
/clientes/{id}/transacoesPOSTSubmit a debit or credit transaction for a client (IDs 1-5)
/clientes/{id}/extratoGETGet a client’s current balance, credit limit, and recent transactions
/healthzGETHealth check endpoint

Constraints

The challenge imposes strict resource limits across all containers combined:

  • 1.5 CPU total shared across all services
  • 550MB RAM total shared across all services
  • The system is stress tested using Grafana k6 with concurrent users submitting transactions and querying statements

Source

Full specification: github.com/zanfranceschi/rinha-de-backend-2024-q1

Getting Started

Prerequisites

  • Docker with Docker Compose

Clone and Run

git clone https://github.com/jonathanperis/rinha2-back-end-python.git
cd rinha2-back-end-python
docker compose up nginx -d --build

Access

The API is available at http://localhost:9999

Endpoints

EndpointMethodDescription
/clientes/{id}/transacoesPOSTSubmit debit or credit transaction
/clientes/{id}/extratoGETGet account balance statement
/healthzGETHealth check

Example Requests

Create Transaction

curl -X POST http://localhost:9999/clientes/1/transacoes \
  -H "Content-Type: application/json" \
  -d '{"valor": 1000, "tipo": "c", "descricao": "deposito"}'

Get Statement

curl http://localhost:9999/clientes/1/extrato

Health Check

curl http://localhost:9999/healthz

Run Stress Tests

docker compose up k6 --build --force-recreate

Performance

Resource Constraints

The challenge allows a total of 1.5 CPU and 550MB RAM across all containers.

Actual Usage

MetricLimitActualMargin
RAM550MB~250MB60% below limit
Response time-< 800msAll requests

Results

  • All requests completed under 800ms
  • Total RAM usage of approximately 250MB, which is 60% below the 550MB limit
  • Built for learning purposes

Stress Testing

Load tests are run using the shared rinha2-back-end-k6 test suite, which simulates concurrent users performing debits, credits, validations, and statement queries.

Reports are published automatically to GitHub Pages after each main release.

CI/CD Pipeline

Workflows

This repository uses four GitHub Actions workflows:

WorkflowFileTriggerDescription
Build Checkbuild-check.ymlPull requestsDocker build + health check (20 retries)
Main Releasemain-release.ymlPush to mainMulti-platform Docker push (amd64/arm64) to GHCR + container test + k6 load test
CodeQLcodeql.ymlPush to main, PRs, weeklySecurity and code quality analysis
Deploydeploy.ymlPush to mainDeploy docs to GitHub Pages via Actions

build-check.yml

  • Trigger: Pull requests
  • Steps: Builds the API container with Docker Compose and runs a health check endpoint test (20 retries) to verify the service starts correctly
  • Purpose: Catch build failures and regressions before merging

main-release.yml

  • Trigger: Push to main branch
  • Steps:
    1. Builds a multi-platform Docker image (linux/amd64, linux/arm64) and pushes to GitHub Container Registry (GHCR)
    2. Runs a container health check test against the production compose stack
    3. Runs k6 load tests and commits the stress test report to docs/reports/
  • Purpose: Automated release of production-ready container images with verification
  • Image: ghcr.io/jonathanperis/rinha2-back-end-python:latest

codeql.yml

  • Trigger: Push to main, pull requests, weekly schedule
  • Steps: Runs GitHub CodeQL analysis for security vulnerabilities and code quality
  • Purpose: Continuous security scanning

deploy.yml

  • Trigger: Push to main branch
  • Steps: Deploys the docs/ directory to GitHub Pages using actions/deploy-pages
  • Purpose: Publish documentation and stress test reports to GitHub Pages