Make Python FastAPI apps work with Spring Boot ecosystem (Eureka, Config Server, Actuator)
Project description
Spring-Ready Python
Make your Python FastAPI app work seamlessly with Spring Boot ecosystem: Eureka, Config Server, Spring Boot Admin, and Prometheus.
Why This Exists
You have a Spring Boot microservices architecture with Eureka, Config Server, Spring Boot Admin, and Prometheus monitoring. You want to add a Python service but keep everything working together. This library makes that dead simple.
Features
✅ Eureka Service Registration - Automatic registration with heartbeat
✅ Config Server Integration - Load config from Spring Cloud Config with Eureka discovery
✅ Actuator Endpoints - /actuator/health, /actuator/info, /actuator/prometheus
✅ FastAPI Integration - Drop-in support for FastAPI apps
✅ Fail-Fast Behavior - Matches Spring Boot's startup failure handling
✅ Exponential Backoff Retry - Retry logic for Eureka and Config Server
✅ Zero Magic - Own implementation, no hidden dependencies
Installation
pip install spring-ready-python
Optional dependencies:
# For Config Server support
pip install spring-config-client-python
# For Prometheus metrics
pip install prometheus-client
Quick Start
from spring_ready import SpringReadyApp
from fastapi import FastAPI
# Create FastAPI app
app = FastAPI()
# Add Spring integration
spring_app = SpringReadyApp(app)
spring_app.start()
# Your routes
@app.get("/")
def read_root():
return {"message": "Hello from Spring-Ready Python!"}
# Run with uvicorn
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8080)
That's it. Your app now:
- Registers with Eureka
- Loads config from Config Server (discovered via Eureka)
- Exposes
/actuator/health,/actuator/info,/actuator/prometheus - Shows up in Spring Boot Admin
Configuration
Set via environment variables (matching Spring Boot conventions):
# Application
SPRING_APPLICATION_NAME=my-python-service
APP_PORT=8080
SPRING_PROFILES_ACTIVE=production
# Eureka
EUREKA_SERVER_URL=http://eureka:8761/eureka/
EUREKA_INSTANCE_IP=192.168.1.100 # Optional: custom IP for registration
EUREKA_INSTANCE_HOSTNAME=my-service.example.com # Optional: custom hostname
# Config Server (optional - will be discovered from Eureka)
CONFIG_SERVER_URI=http://config-server:8888
CONFIG_SERVER_USERNAME=admin
CONFIG_SERVER_PASSWORD=secret
Environment Variables Reference
| Variable | Description | Default | Example |
|---|---|---|---|
SPRING_APPLICATION_NAME |
Application name | python-service |
my-python-service |
APP_PORT |
Application port | 8080 |
8080 |
SPRING_PROFILES_ACTIVE |
Active profile | default |
production |
EUREKA_SERVER_URL |
Eureka server URL(s) | http://localhost:8761/eureka/ |
http://eureka:8761/eureka/ |
EUREKA_INSTANCE_IP |
Custom IP for registration | Auto-detected | 192.168.1.100 |
EUREKA_INSTANCE_HOSTNAME |
Custom hostname | Auto-detected | my-service.local |
EUREKA_INSTANCE_SECURE |
Register with HTTPS URLs | false |
true |
CONFIG_SERVER_URI |
Config Server URL | Discovered from Eureka | http://config:8888 |
CONFIG_SERVER_SERVICE_ID |
Config Server service ID | CONFIG-SERVER |
CONFIG-SERVER |
CONFIG_SERVER_USERNAME |
Config Server username | None | admin |
CONFIG_SERVER_PASSWORD |
Config Server password | None | secret |
Docker Example
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
ENV SPRING_APPLICATION_NAME=my-service
ENV EUREKA_SERVER_URL=http://eureka:8761/eureka/
ENV SPRING_PROFILES_ACTIVE=production
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
# docker-compose.yml
services:
my-service:
build: .
environment:
- EUREKA_SERVER_URL=http://eureka:8761/eureka/
- SPRING_PROFILES_ACTIVE=production
ports:
- "8080:8080"
Advanced Usage
Custom Health Checks
from spring_ready import SpringReadyApp
spring_app = SpringReadyApp(app)
spring_app.start()
# Add custom health check
def check_database():
# Your database check logic
return database.is_connected()
spring_app.health_endpoint.add_check("database", check_database)
Service Discovery
# Find another service registered in Eureka
config_server_url = spring_app.service_discovery.get_service_url("CONFIG-SERVER")
# Get all instances of a service
instances = spring_app.service_discovery.get_instances("my-other-service")
for instance in instances:
print(f"Instance: {instance.base_url}")
Manual Configuration
from spring_ready import SpringReadyApp
spring_app = SpringReadyApp(
app=app,
app_name="my-service",
app_port=8080,
eureka_servers=["http://eureka1:8761/eureka/", "http://eureka2:8761/eureka/"],
profile="production",
fail_fast=True,
prefer_ip_address=True
)
spring_app.start()
Custom IP Address Registration
from spring_ready import SpringReadyApp
# Specify a custom IP address for Eureka registration
# Useful in Docker/Kubernetes when you need to advertise a specific IP
spring_app = SpringReadyApp(
app=app,
app_name="my-service",
instance_ip="192.168.1.100", # Custom IP address
instance_hostname="my-service.example.com" # Optional: custom hostname
)
spring_app.start()
Or via environment variables:
export EUREKA_INSTANCE_IP=192.168.1.100
export EUREKA_INSTANCE_HOSTNAME=my-service.example.com
HTTPS Registration (Secure Mode)
When your application uses HTTPS, you need to register with HTTPS URLs in Eureka so that Spring Boot Admin and other services can connect to it correctly.
from spring_ready import SpringReadyApp
# Register with HTTPS URLs in Eureka
spring_app = SpringReadyApp(
app=app,
app_name="my-service",
app_port=8443,
secure=True # Register with https:// URLs
)
spring_app.start()
Or via environment variable:
export EUREKA_INSTANCE_SECURE=true
When secure=True:
- The
homePageUrl,statusPageUrl, andhealthCheckUrlwill usehttps:// - The
securePortwill be enabled and set to yourapp_port - The regular
portwill be disabled
This is equivalent to Spring Boot's:
eureka:
instance:
secure-port-enabled: true
non-secure-port-enabled: false
How It Works
Startup Sequence
- Eureka Registration: Registers with Eureka (with retry/backoff)
- Config Discovery: Discovers Config Server from Eureka
- Config Loading: Loads configuration into
os.environ - Actuator Setup: Exposes health, info, and metrics endpoints
- Heartbeat: Starts background thread for Eureka heartbeats (every 30s)
Shutdown Sequence
- Stops heartbeat thread
- Deregisters from Eureka
- Clean exit
Behavior Matching Spring Boot
| Feature | Spring Boot | spring-ready-python |
|---|---|---|
| Fail-fast on startup | ✓ | ✓ |
| Exponential backoff retry | ✓ | ✓ |
| Eureka heartbeat (30s) | ✓ | ✓ |
| Config Server discovery | ✓ | ✓ |
| Actuator endpoints | ✓ | ✓ |
| Graceful shutdown | ✓ | ✓ |
Actuator Endpoints
GET /actuator/health
Returns application health status:
{
"status": "UP",
"components": {
"diskSpace": {"status": "UP"},
"eureka": {"status": "UP"},
"ping": {"status": "UP"}
}
}
GET /actuator/info
Returns application metadata:
{
"app": {
"name": "my-python-service",
"version": "1.0.0"
},
"python": {
"version": "3.11.5",
"runtime": {
"name": "CPython",
"version": "3.11.5"
}
}
}
GET /actuator/prometheus
Returns Prometheus metrics in exposition format:
# HELP python_info Python platform information
# TYPE python_info gauge
python_info{implementation="CPython",version="3.11.5"} 1.0
...
Troubleshooting
No Registration Attempts to Eureka Server
Symptom: You don't see any connection attempts to your Eureka server in logs or network monitoring.
Cause: The application is likely using the default Eureka URL (http://localhost:8761/eureka/) instead of your server.
Solution:
-
Set the environment variable (Recommended):
export EUREKA_SERVER_URL=http://10.10.0.1:8761/eureka/ python your_app.py
-
Or pass it explicitly in code:
spring_app = SpringReadyApp( app, eureka_servers=["http://10.10.0.1:8761/eureka/"] )
-
Verify your configuration:
import os print(f"EUREKA_SERVER_URL: {os.getenv('EUREKA_SERVER_URL')}")
-
Check the startup logs: Look for this message:
INFO:spring_ready.core:Configured Eureka server(s): http://10.10.0.1:8761/eureka/If you see:
WARNING:spring_ready.core:Using default Eureka server URL (http://localhost:8761/eureka/)Then you need to set
EUREKA_SERVER_URL. -
Enable debug logging to see detailed registration attempts:
import logging logging.basicConfig(level=logging.DEBUG)
-
Verify network connectivity:
curl http://10.10.0.1:8761/eureka/appsShould return XML/JSON with registered applications.
Common mistakes:
- Forgetting to set
EUREKA_SERVER_URLin Docker/Kubernetes deployments - Setting the variable in your IDE but not in the runtime environment
- Using
localhostwhen running in containers (use service names or IPs instead)
Eureka Registration Fails
Check Eureka server is reachable:
curl http://eureka:8761/eureka/apps
Set fail_fast=False to start anyway:
spring_app = SpringReadyApp(app, fail_fast=False)
Config Server Not Found
Ensure Config Server is registered in Eureka:
curl http://eureka:8761/eureka/apps/CONFIG-SERVER
Or provide direct URL:
export CONFIG_SERVER_URI=http://config-server:8888
Port Already in Use
Change the port:
spring_app = SpringReadyApp(app, app_port=8081)
Or via environment:
export APP_PORT=8081
Differences from Spring Boot
| Aspect | Spring Boot | Python |
|---|---|---|
| Metrics names | jvm.memory.used |
process_virtual_memory_bytes |
| Runtime info | Java/JVM | Python/CPython |
| Config refresh | /actuator/refresh |
Not supported (restart required) |
| Auto-configuration | Annotations | Explicit initialization |
Requirements
- Python 3.9+
- FastAPI
- requests
Optional:
spring-config-client-pythonfor Config Server supportprometheus-clientfor metrics
License
MIT
Contributing
Contributions welcome! This library is intentionally simple and focused. See CONTRIBUTING.md.
Comparison with Spring Boot
// Spring Boot (Kotlin)
@SpringBootApplication
@EnableDiscoveryClient
class MyApplication
// Configuration in application.yml
# Python equivalent
from spring_ready import SpringReadyApp
from fastapi import FastAPI
app = FastAPI()
spring_app = SpringReadyApp(app)
spring_app.start()
# Configuration from environment variables
Note: This library focuses on making Python apps work with existing Spring Boot infrastructure. It's not a replacement for Spring Boot itself.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spring_ready_python-1.1.2.tar.gz.
File metadata
- Download URL: spring_ready_python-1.1.2.tar.gz
- Upload date:
- Size: 53.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c1ab4ec19979313c0137a617136acb2d0bba38277b2788ac190475f0cf3c60c
|
|
| MD5 |
10211e78db0edee230f383f8cefd93d0
|
|
| BLAKE2b-256 |
2adcf270f0705c386b92a243f7b530e03ea16fc0e362a2a3d166dd22b2f16e18
|
Provenance
The following attestation bundles were made for spring_ready_python-1.1.2.tar.gz:
Publisher:
python-publish.yml on tcivie/spring_ready_python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spring_ready_python-1.1.2.tar.gz -
Subject digest:
8c1ab4ec19979313c0137a617136acb2d0bba38277b2788ac190475f0cf3c60c - Sigstore transparency entry: 942062687
- Sigstore integration time:
-
Permalink:
tcivie/spring_ready_python@aa8b6f65880b0570a0984e546c85ea92cedaf56d -
Branch / Tag:
refs/tags/v1.1.2 - Owner: https://github.com/tcivie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@aa8b6f65880b0570a0984e546c85ea92cedaf56d -
Trigger Event:
release
-
Statement type:
File details
Details for the file spring_ready_python-1.1.2-py3-none-any.whl.
File metadata
- Download URL: spring_ready_python-1.1.2-py3-none-any.whl
- Upload date:
- Size: 56.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76385ea764924dec2d5ef3d089aad3811884c68d3e5eb95e42a42640d9513a1b
|
|
| MD5 |
4ca2629ae5426977eb61a91d40b8aae6
|
|
| BLAKE2b-256 |
667f25f183e5176acca68ded9bf389dec99bea1f95037dd34016a1153578d414
|
Provenance
The following attestation bundles were made for spring_ready_python-1.1.2-py3-none-any.whl:
Publisher:
python-publish.yml on tcivie/spring_ready_python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spring_ready_python-1.1.2-py3-none-any.whl -
Subject digest:
76385ea764924dec2d5ef3d089aad3811884c68d3e5eb95e42a42640d9513a1b - Sigstore transparency entry: 942062704
- Sigstore integration time:
-
Permalink:
tcivie/spring_ready_python@aa8b6f65880b0570a0984e546c85ea92cedaf56d -
Branch / Tag:
refs/tags/v1.1.2 - Owner: https://github.com/tcivie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@aa8b6f65880b0570a0984e546c85ea92cedaf56d -
Trigger Event:
release
-
Statement type: