Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions PR_CONNECTION_DRAINING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Connection Draining for Zero-Downtime Deployments

### Summary
Implements connection draining to enable zero-downtime rolling deployments by allowing in-flight requests to complete before shutdown.

### Changes
- Added `/ready` endpoint (separate from `/health`) for Kubernetes readiness probes
- Returns 200 when accepting traffic, 503 during drain
- On SIGTERM: immediately stops accepting new connections, waits up to 30s for in-flight requests

### New Files
- `src/readiness.rs` - AtomicBool-based readiness state
- `tests/readiness_unit_test.rs` - Unit tests
- `tests/connection_draining_test.rs` - Integration tests

### Modified Files
- `src/config.rs` - Added `DRAIN_TIMEOUT_SECS` config
- `src/handlers/mod.rs` - Added `/ready` handler
- `src/lib.rs` - Wired readiness into AppState
- `src/main.rs` - Added SIGTERM handler with graceful shutdown

### Configuration
- `DRAIN_TIMEOUT_SECS` - Drain timeout in seconds (default: 30)
41 changes: 41 additions & 0 deletions PR_ERROR_CODES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
## Structured Error Codes & Error Catalog

### Summary
Added machine-readable error codes to enable API consumers to programmatically handle specific failure scenarios.

### Changes
- Every AppError variant now has a unique stable error code (e.g., ERR_VALIDATION_001)
- JSON error responses now include the code field: `{ "error": "message", "code": "ERR_VALIDATION_001", "status": 400 }`
- Added GET /errors endpoint returning error catalog as JSON
- Created static error catalog at docs/error-catalog.md

### New Files
- `docs/error-catalog.md` - Static error catalog with all 19 error codes

### Modified Files
- `src/error.rs` - Added code() method, error code constants, ErrorCode struct
- `src/handlers/mod.rs` - Added error_catalog handler
- `src/main.rs` - Added /errors route
- `src/lib.rs` - Added /errors route

### Error Codes (19 total)
- ERR_DATABASE_001/002 - Database errors
- ERR_VALIDATION_001 - Validation errors
- ERR_NOT_FOUND_001 - Not found errors
- ERR_INTERNAL_001 - Internal errors
- ERR_BAD_REQUEST_001 - Bad request errors
- ERR_AUTH_001/002 - Authentication errors
- ERR_UNAUTHORIZED_001 - Unauthorized errors
- ERR_TRANSACTION_001-005 - Transaction errors
- ERR_WEBHOOK_001/002 - Webhook errors
- ERR_SETTLEMENT_001/002 - Settlement errors
- ERR_RATE_LIMIT_001 - Rate limiting

### Example Response
```json
{
"error": "Validation error: invalid email",
"code": "ERR_VALIDATION_001",
"status": 400
}
```
132 changes: 132 additions & 0 deletions docs/error-catalog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Error Catalog

This document lists all stable error codes used by the Synapse Core API. Error codes are stable and should never be renamed or reused for different errors.

## Error Response Format

All error responses follow this format:

```json
{
"error": "Human readable error message",
"code": "ERR_CATEGORY_NNN",
"status": 400
}
```

## Error Codes

### Database Errors (ERR_DATABASE_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_DATABASE_001 | 500 | Database connection error |
| ERR_DATABASE_002 | 500 | Database query execution error |

### Validation Errors (ERR_VALIDATION_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_VALIDATION_001 | 400 | Validation error - invalid input |

### Not Found Errors (ERR_NOT_FOUND_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_NOT_FOUND_001 | 404 | Resource not found |

### Internal Errors (ERR_INTERNAL_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_INTERNAL_001 | 500 | Internal server error |

### Bad Request Errors (ERR_BAD_REQUEST_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_BAD_REQUEST_001 | 400 | Bad request - invalid parameters |

### Authentication Errors (ERR_AUTH_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_AUTH_001 | 401 | Invalid authentication credentials |
| ERR_AUTH_002 | 403 | Insufficient permissions |

### Unauthorized Errors (ERR_UNAUTHORIZED_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_UNAUTHORIZED_001 | 401 | Unauthorized - authentication required |

### Transaction Errors (ERR_TRANSACTION_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_TRANSACTION_001 | 400 | Invalid transaction amount |
| ERR_TRANSACTION_002 | 400 | Transaction amount below minimum |
| ERR_TRANSACTION_003 | 400 | Invalid Stellar address |
| ERR_TRANSACTION_004 | 409 | Transaction already processed (idempotency) |
| ERR_TRANSACTION_005 | 400 | Invalid transaction status transition |

### Webhook Errors (ERR_WEBHOOK_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_WEBHOOK_001 | 401 | Invalid webhook signature |
| ERR_WEBHOOK_002 | 400 | Malformed webhook payload |

### Settlement Errors (ERR_SETTLEMENT_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_SETTLEMENT_001 | 400 | Invalid settlement amount |
| ERR_SETTLEMENT_002 | 409 | Settlement already exists |

### Rate Limiting Errors (ERR_RATE_LIMIT_xxx)

| Code | HTTP Status | Description |
|------|-------------|-------------|
| ERR_RATE_LIMIT_001 | 429 | Rate limit exceeded |

## Using Error Codes

### Programmatic Retry Logic

Clients can use error codes to implement intelligent retry logic:

```python
# Example: Retry on transient errors
TRANSIENT_ERRORS = ["ERR_DATABASE_001", "ERR_INTERNAL_001"]

def handle_error(response):
error_code = response["code"]
if error_code in TRANSIENT_ERRORS:
# Retry with exponential backoff
return retry_with_backoff()
elif error_code == "ERR_RATE_LIMIT_001":
# Retry after waiting for rate limit reset
return retry_after_delay()
else:
# Don't retry for client errors
return handle_failure(response)
```

### Idempotency Handling

Clients can detect idempotent operations that have already been processed:

```python
if response["code"] == "ERR_TRANSACTION_004":
# Transaction was already processed
return get_existing_result()
```

## Version

This error catalog is version 1.0.0. API consumers can retrieve the latest version via the `/errors` endpoint.

## Changelog

- 1.0.0 - Initial error catalog with 19 error codes
Loading
Loading