chore(systemd): remove obsolete systemd service files and update infrastructure documentation
- Remove 8 unused systemd service files from coordinator-api/systemd/ - aitbc-adaptive-learning.service (port 8005) - aitbc-advanced-ai.service - aitbc-enterprise-api.service - aitbc-gpu-multimodal.service (port 8003) - aitbc-marketplace-enhanced.service (port 8006) - aitbc-modality-optimization.service (port 8004) - aitbc-multimodal.service (port 8002) - aitbc-openclaw-enhanced.service (port 8007
This commit is contained in:
18
apps/coordinator-api/scripts/check_coordinator_proxy.sh
Executable file
18
apps/coordinator-api/scripts/check_coordinator_proxy.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
HEALTH_URL="http://127.0.0.1:18000/v1/health"
|
||||
MAX_RETRIES=10
|
||||
RETRY_DELAY=2
|
||||
|
||||
for ((i=1; i<=MAX_RETRIES; i++)); do
|
||||
if curl -fsS --max-time 5 "$HEALTH_URL" >/dev/null 2>&1; then
|
||||
echo "Coordinator proxy healthy: $HEALTH_URL"
|
||||
exit 0
|
||||
fi
|
||||
echo "Attempt $i/$MAX_RETRIES: Coordinator proxy not ready yet, waiting ${RETRY_DELAY}s..."
|
||||
sleep $RETRY_DELAY
|
||||
done
|
||||
|
||||
echo "Coordinator proxy health check FAILED: $HEALTH_URL" >&2
|
||||
exit 1
|
||||
151
apps/coordinator-api/scripts/geo_load_balancer.py
Executable file
151
apps/coordinator-api/scripts/geo_load_balancer.py
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Geographic Load Balancer for AITBC Marketplace
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
from aiohttp import web
|
||||
import json
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
# Regional endpoints configuration
|
||||
regions = {
|
||||
'us-east': {'url': 'http://127.0.0.1:18000', 'weight': 3, 'healthy': True, 'edge_node': 'aitbc-edge-primary'},
|
||||
'us-west': {'url': 'http://127.0.0.1:18001', 'weight': 2, 'healthy': True, 'edge_node': 'aitbc1-edge-secondary'},
|
||||
'eu-central': {'url': 'http://127.0.0.1:8006', 'weight': 2, 'healthy': True, 'edge_node': 'localhost'},
|
||||
'eu-west': {'url': 'http://127.0.0.1:18000', 'weight': 1, 'healthy': True, 'edge_node': 'aitbc-edge-primary'},
|
||||
'ap-southeast': {'url': 'http://127.0.0.1:18001', 'weight': 2, 'healthy': True, 'edge_node': 'aitbc1-edge-secondary'},
|
||||
'ap-northeast': {'url': 'http://127.0.0.1:8006', 'weight': 1, 'healthy': True, 'edge_node': 'localhost'}
|
||||
}
|
||||
|
||||
class GeoLoadBalancer:
|
||||
def __init__(self):
|
||||
self.current_region = 0
|
||||
self.health_check_interval = 30
|
||||
|
||||
async def health_check(self, region_config):
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(f"{region_config['url']}/health/live", timeout=5) as response:
|
||||
region_config['healthy'] = response.status == 200
|
||||
region_config['last_check'] = datetime.now().isoformat()
|
||||
except Exception as e:
|
||||
region_config['healthy'] = False
|
||||
region_config['last_check'] = datetime.now().isoformat()
|
||||
region_config['error'] = str(e)
|
||||
|
||||
async def get_healthy_region(self):
|
||||
healthy_regions = [(name, config) for name, config in regions.items() if config['healthy']]
|
||||
if not healthy_regions:
|
||||
return None, None
|
||||
|
||||
# Simple weighted round-robin
|
||||
total_weight = sum(config['weight'] for _, config in healthy_regions)
|
||||
if total_weight == 0:
|
||||
return healthy_regions[0]
|
||||
|
||||
import random
|
||||
rand = random.randint(1, total_weight)
|
||||
current_weight = 0
|
||||
|
||||
for name, config in healthy_regions:
|
||||
current_weight += config['weight']
|
||||
if rand <= current_weight:
|
||||
return name, config
|
||||
|
||||
return healthy_regions[0]
|
||||
|
||||
async def proxy_request(self, request):
|
||||
region_name, region_config = await self.get_healthy_region()
|
||||
if not region_config:
|
||||
return web.json_response({'error': 'No healthy regions available'}, status=503)
|
||||
|
||||
try:
|
||||
# Forward request to selected region
|
||||
target_url = f"{region_config['url']}{request.path_qs}"
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
# Prepare headers (remove host header)
|
||||
headers = dict(request.headers)
|
||||
headers.pop('Host', None)
|
||||
|
||||
async with session.request(
|
||||
method=request.method,
|
||||
url=target_url,
|
||||
headers=headers,
|
||||
data=await request.read()
|
||||
) as response:
|
||||
# Read response
|
||||
body = await response.read()
|
||||
|
||||
# Create response
|
||||
resp = web.Response(
|
||||
body=body,
|
||||
status=response.status,
|
||||
headers=dict(response.headers)
|
||||
)
|
||||
|
||||
# Add routing headers
|
||||
resp.headers['X-Region'] = region_name
|
||||
resp.headers['X-Backend-Url'] = region_config['url']
|
||||
|
||||
return resp
|
||||
|
||||
except Exception as e:
|
||||
return web.json_response({
|
||||
'error': 'Proxy error',
|
||||
'message': str(e),
|
||||
'region': region_name
|
||||
}, status=502)
|
||||
|
||||
async def handle_all_requests(request):
|
||||
balancer = request.app['balancer']
|
||||
return await balancer.proxy_request(request)
|
||||
|
||||
async def health_check_handler(request):
|
||||
balancer = request.app['balancer']
|
||||
|
||||
# Perform health checks on all regions
|
||||
tasks = [balancer.health_check(config) for config in regions.values()]
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
return web.json_response({
|
||||
'status': 'healthy',
|
||||
'load_balancer': 'geographic',
|
||||
'regions': regions,
|
||||
'timestamp': datetime.now().isoformat()
|
||||
})
|
||||
|
||||
async def status_handler(request):
|
||||
balancer = request.app['balancer']
|
||||
healthy_count = sum(1 for config in regions.values() if config['healthy'])
|
||||
|
||||
return web.json_response({
|
||||
'total_regions': len(regions),
|
||||
'healthy_regions': healthy_count,
|
||||
'health_ratio': healthy_count / len(regions),
|
||||
'current_time': datetime.now().isoformat(),
|
||||
'regions': {name: {
|
||||
'healthy': config['healthy'],
|
||||
'weight': config['weight'],
|
||||
'last_check': config.get('last_check')
|
||||
} for name, config in regions.items()}
|
||||
})
|
||||
|
||||
async def create_app():
|
||||
app = web.Application()
|
||||
balancer = GeoLoadBalancer()
|
||||
app['balancer'] = balancer
|
||||
|
||||
# Add routes
|
||||
app.router.add_route('*', '/{path:.*}', handle_all_requests)
|
||||
app.router.add_get('/health', health_check_handler)
|
||||
app.router.add_get('/status', status_handler)
|
||||
|
||||
return app
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = asyncio.run(create_app())
|
||||
web.run_app(app, host='127.0.0.1', port=8080)
|
||||
Reference in New Issue
Block a user