Really Simple Service Registry - Python Client
Project description
SRSR Python Client
Python client library for the srsr service registry.
The client automatically handles registration, heartbeat maintenance, and deregistration with the service registry server. It supports configurable heartbeat intervals and error handling for robust service discovery in microservice architectures.
Installation
# Base package
pip install srsrpy
# With Flask extension
pip install srsrpy[flask]
Configuration
Registry Address
The service registry address can be specified in three ways (in order of precedence):
- Explicitly in code: Pass the address to
ServiceRegistryClient - Environment variable: Set
SRSR_REGISTRY_URL(e.g.,export SRSR_REGISTRY_URL=http://localhost:4214) - Default: Uses
http://localhost:4214if not specified
from srsrpy import ServiceRegistryClient
# Explicit address
client = ServiceRegistryClient('my-service', registry_address='http://registry:4214', service_address='http://localhost:3000')
# Use environment variable or default
client = ServiceRegistryClient('my-service', service_address='http://localhost:3000')
Service Port Specification Rules
When registering your service, the service's port can be specified in different ways:
- In the service address:
service_address='http://localhost:3000' - As a separate argument:
service_port='3000'(without port in address) - Omitted entirely: The service is registered without port information.
Important: Port cannot be specified in both the address and as a separate argument - this raises a ValueError.
from srsrpy import ServiceRegistryClient
# Valid: Port in service address
client = ServiceRegistryClient('my-service', service_address='http://localhost:3000')
# Valid: Port as separate argument (address without port)
client = ServiceRegistryClient('my-service', service_address='http://localhost', service_port='3000')
# Valid: Port as separate argument (no address)
client = ServiceRegistryClient('my-service', service_port='3000')
# Valid: No port specified
client = ServiceRegistryClient('my-service', service_address='http://localhost')
# Invalid: Port in both places - raises ValueError
client = ServiceRegistryClient('my-service', service_address='http://localhost:3000', service_port='3000')
Basic Usage
Using Environment Variables with from_env()
For cloud-native and containerized applications, you can configure the client entirely through environment variables using the from_env() factory method:
from srsrpy import ServiceRegistryClient
# Set environment variables (e.g., in your deployment config, Dockerfile, or .env)
# export SRSR_SERVICE_NAME=my-service
# export SRSR_REGISTRY_URL=http://registry:4214 # Optional, defaults to localhost:4214
# export SRSR_SERVICE_ADDRESS=http://localhost:3000 # Optional
# export SRSR_HEARTBEAT_INTERVAL=20 # Optional
def main():
# Configuration comes entirely from environment variables
with ServiceRegistryClient.from_env():
# Your service runs here...
run_service()
if __name__ == "__main__":
main()
Environment Variables:
SRSR_SERVICE_NAME- Service name (required)SRSR_REGISTRY_URL- Registry address (optional, defaults tohttp://localhost:4214)SRSR_SERVICE_ADDRESS- Service address (optional)SRSR_SERVICE_PORT- Service port (optional)SRSR_HEARTBEAT_INTERVAL- Heartbeat interval in seconds (optional, defaults to 20)
Using Context Manager (Recommended)
The recommended approach is to use the context manager pattern, which automatically handles registration and deregistration:
from srsrpy import ServiceRegistryClient
def main():
# Using 'with' automatically registers on entry and deregisters on exit
with ServiceRegistryClient(
'my-service', # Service name (required)
registry_address='http://localhost:4214', # Registry server address (optional)
service_address='http://localhost:3000' # This service's address (optional)
):
# Your service runs here, heartbeats are sent in the background
run_service()
# Deregistration happens automatically, even if an exception occurs
if __name__ == "__main__":
main()
The context manager will:
- Register with the service registry when entering the
withblock - Raise a
RuntimeErrorif registration fails - Automatically deregister when exiting the block (even if an exception occurs)
- Not suppress any exceptions that occur within the block
Manual Registration (Alternative)
You can also manage registration manually if needed:
from srsrpy import ServiceRegistryClient
def main():
# Connect to registry at localhost:4214, register this service at localhost:3000
client = ServiceRegistryClient(
'my-service', # Service name (required)
registry_address='http://localhost:4214', # Registry server address (optional)
service_address='http://localhost:3000' # This service's address (optional)
)
# Register and start automatic heartbeats
success = client.register()
if not success:
print("Failed to register with service registry")
return
try:
# Your service runs here...
# Heartbeats are sent automatically every 20 seconds
run_service()
finally:
# Always deregister on shutdown
client.deregister()
if __name__ == "__main__":
main()
Port-Only Registration
If your service cannot determine its full address, you can register with just a port:
from srsrpy import ServiceRegistryClient
# The server will deduce the client IP and use http scheme
client = ServiceRegistryClient(
'my-service', # Service name
registry_address='http://localhost:4214', # Registry server (optional)
service_port='3000' # Just the port - server deduces IP
)
success = client.register()
Advanced Configuration
from srsrpy import ServiceRegistryClient
def heartbeat_error_handler(error):
print(f"Service registry heartbeat failed: {error}")
def main():
client = ServiceRegistryClient(
'my-service', # Service name
registry_address='http://localhost:4214', # Registry server (optional)
service_address='http://localhost:3000', # Service address (optional)
heartbeat_interval=10, # Custom interval in seconds (default: 20)
heartbeat_error_handler=heartbeat_error_handler # Optional error callback
)
success = client.register()
if success:
# Service logic here...
pass
Configuration Options
heartbeat_interval (int)
Sets how often heartbeats are sent to the registry in seconds. Default is 20 seconds.
heartbeat_error_handler (callable)
Sets an optional callback function that will be called whenever heartbeat requests fail. The handler receives the error that occurred. By default, heartbeat failures are silently ignored.
# Example: Log heartbeat failures and update metrics
def error_handler(error):
logger.error(f"Registry heartbeat failed: {error}")
metrics.increment_counter("registry_heartbeat_failures")
client = ServiceRegistryClient(
'my-service',
registry_address='http://localhost:4214',
service_address='http://localhost:3000',
heartbeat_error_handler=error_handler
)
Interface
register() -> bool
Registers the service with the registry and starts automatic heartbeat maintenance. Returns True if registration succeeds, False otherwise.
deregister() -> None
Stops heartbeat maintenance and deregisters the service from the registry. Safe to call multiple times.
Error Handling
The client handles various error conditions gracefully:
- Network failures during registration: Registration returns
False - Network failures during heartbeat: By default, silently ignored (service will timeout and be deregistered). Optionally surfaced through
heartbeat_error_handler - Invalid responses: Handled appropriately (e.g., missing ID field)
- Connection errors: Caught and handled without crashing the application
Heartbeat Error Handling
By default, heartbeat failures are silently ignored to prevent noisy logging. However, you can provide a custom error handler to:
- Log heartbeat failures for debugging
- Update metrics or monitoring systems
- Take application-specific actions
Signal Handler Example
For graceful shutdown, the context manager pattern automatically handles cleanup. If you need to preserve existing signal handlers for manual registration:
import signal
from srsrpy import ServiceRegistryClient
client = ServiceRegistryClient(
'my-service',
registry_address='http://localhost:4214',
service_address='http://localhost:3000'
)
success = client.register()
if success:
# Save the original handler and set up graceful shutdown
prev_handler = signal.getsignal(signal.SIGINT)
def handle_sigint(sig, frame):
client.deregister()
# Call the original handler if it existed
if prev_handler:
prev_handler(sig, frame)
signal.signal(signal.SIGINT, handle_sigint)
Note: When using the context manager pattern, cleanup is automatic and signal handlers are typically not needed for deregistration.
Flask Integration
For Flask applications, srsrpy provides an extension that automatically handles service registration and deregistration with Flask's application lifecycle.
Installation
pip install srsrpy[flask]
Usage
The Flask extension uses environment variables for configuration and automatically registers your Flask application with the service registry on startup and deregisters on shutdown.
from flask import Flask
from srsrpy.contrib.flask import FlaskServiceRegistry
app = Flask(__name__)
FlaskServiceRegistry(app)
@app.route('/')
def hello():
return 'Hello from registered service!'
if __name__ == '__main__':
app.run()
Or with the application factory pattern:
from flask import Flask
from srsrpy.contrib.flask import FlaskServiceRegistry
registry = FlaskServiceRegistry()
def create_app():
app = Flask(__name__)
registry.init_app(app)
@app.route('/')
def hello():
return 'Hello from registered service!'
return app
if __name__ == '__main__':
app = create_app()
app.run()
Configuration
Set environment variables before starting your Flask application:
export SRSR_SERVICE_NAME=my-flask-api
export SRSR_REGISTRY_URL=http://registry:4214 # Optional
export SRSR_SERVICE_ADDRESS=http://localhost:5000 # Optional
export SRSR_HEARTBEAT_INTERVAL=20 # Optional
Graceful Degradation: If SRSR_SERVICE_NAME is not set, the extension silently does nothing, allowing your Flask app to run without service registry integration.
Roadmap
See ROADMAP.md for planned improvements and future enhancements.
Project details
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 srsrpy-1.1.0.tar.gz.
File metadata
- Download URL: srsrpy-1.1.0.tar.gz
- Upload date:
- Size: 11.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a7c0bb23cbf00ca3c4b618702b49d305b25e1168c0c05e7aa201a277a339bf25
|
|
| MD5 |
fcc47efd9fde9efe8b8ab80b610ca935
|
|
| BLAKE2b-256 |
fb3a344b1fe5a001b5bd9f1933dd2b225433eba5eb96c70738db6c1139b33ea4
|
Provenance
The following attestation bundles were made for srsrpy-1.1.0.tar.gz:
Publisher:
srsrpy-release.yml on ifIMust/srsrpy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
srsrpy-1.1.0.tar.gz -
Subject digest:
a7c0bb23cbf00ca3c4b618702b49d305b25e1168c0c05e7aa201a277a339bf25 - Sigstore transparency entry: 611082924
- Sigstore integration time:
-
Permalink:
ifIMust/srsrpy@e926cbc228480acbbf3cb0d7485617e922fa677a -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/ifIMust
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
srsrpy-release.yml@e926cbc228480acbbf3cb0d7485617e922fa677a -
Trigger Event:
release
-
Statement type:
File details
Details for the file srsrpy-1.1.0-py3-none-any.whl.
File metadata
- Download URL: srsrpy-1.1.0-py3-none-any.whl
- Upload date:
- Size: 8.5 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 |
cb8d76155c8e1a353cf1be71a94742ace56e55b9ef81ce8c63850280e319f36d
|
|
| MD5 |
78210a18390d5840803e2ef5802fcf69
|
|
| BLAKE2b-256 |
2c55a79699902349d9abf50e81b30f6ab394555587b1145106ea3f2fbf384ab4
|
Provenance
The following attestation bundles were made for srsrpy-1.1.0-py3-none-any.whl:
Publisher:
srsrpy-release.yml on ifIMust/srsrpy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
srsrpy-1.1.0-py3-none-any.whl -
Subject digest:
cb8d76155c8e1a353cf1be71a94742ace56e55b9ef81ce8c63850280e319f36d - Sigstore transparency entry: 611082925
- Sigstore integration time:
-
Permalink:
ifIMust/srsrpy@e926cbc228480acbbf3cb0d7485617e922fa677a -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/ifIMust
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
srsrpy-release.yml@e926cbc228480acbbf3cb0d7485617e922fa677a -
Trigger Event:
release
-
Statement type: