215 lines
5.6 KiB
Python
Raw Normal View History

2026-07-23 01:15:04 +02:00
# retoor <retoor@molodetz.nl>
from __future__ import annotations
from dataclasses import dataclass
from typing import Literal
WorkersSpec = int | Literal["auto"]
@dataclass(frozen=True)
class ServiceSpec:
name: str
module: str
port: int
tier: int
workers: WorkersSpec
stateful: bool
depends_on: tuple[str, ...]
health_client_timeout: float = 2.0
@dataclass(frozen=True)
class IngressRoute:
prefix: str
service: str
websocket: bool = False
SERVICE_SPECS: tuple[ServiceSpec, ...] = (
ServiceSpec("database", "devplacepy_services.database.main:app", 10601, 1, 1, True, ()),
ServiceSpec("pubsub", "devplacepy_services.pubsub.main:app", 10602, 1, 1, True, ("database",)),
ServiceSpec(
"web",
"devplacepy_services.web.main:app",
10500,
2,
"auto",
False,
("database", "pubsub"),
health_client_timeout=4.0,
),
ServiceSpec(
"gateway",
"devplacepy_services.gateway.main:app",
10620,
2,
"auto",
False,
("database",),
health_client_timeout=4.0,
),
ServiceSpec(
"jobs",
"devplacepy_services.jobs.main:app",
10630,
3,
1,
True,
("database", "pubsub", "gateway"),
health_client_timeout=8.0,
),
ServiceSpec(
"devii",
"devplacepy_services.devii.main:app",
10631,
3,
2,
True,
("database", "pubsub", "gateway"),
health_client_timeout=4.0,
),
ServiceSpec("bot", "devplacepy_services.bot.main:app", 10632, 3, 1, True, ("database", "gateway")),
ServiceSpec("backup", "devplacepy_services.backup.main:app", 10633, 3, 1, True, ("database",)),
ServiceSpec(
"containers",
"devplacepy_services.containers.main:app",
10634,
3,
1,
True,
("database",),
health_client_timeout=4.0,
),
ServiceSpec("telegram", "devplacepy_services.telegram.main:app", 10635, 3, 1, True, ("database", "pubsub")),
ServiceSpec("email", "devplacepy_services.email.main:app", 10636, 3, 1, True, ("database",)),
ServiceSpec(
"news",
"devplacepy_services.news.main:app",
10637,
3,
1,
True,
("database", "gateway"),
),
ServiceSpec("gitea", "devplacepy_services.gitea.main:app", 10638, 3, 1, True, ("database", "gateway")),
ServiceSpec("audit", "devplacepy_services.audit.main:app", 10639, 3, 1, True, ("database",)),
ServiceSpec("xmlrpc", "devplacepy_services.xmlrpc.main:app", 10649, 3, 1, True, ("database",)),
)
SERVICES: dict[str, ServiceSpec] = {spec.name: spec for spec in SERVICE_SPECS}
TIER_ORDER: dict[int, tuple[str, ...]] = {
1: ("database", "pubsub"),
2: ("web", "gateway"),
3: (
"jobs",
"devii",
"bot",
"backup",
"containers",
"telegram",
"email",
"news",
"gitea",
"audit",
"xmlrpc",
),
}
SERVICE_URL_ENV: dict[str, str] = {
"web": "DEVPLACE_WEB_URL",
"database": "DEVPLACE_DB_SERVICE_URL",
"pubsub": "DEVPLACE_PUBSUB_URL",
"gateway": "DEVPLACE_GATEWAY_URL",
"jobs": "DEVPLACE_JOBS_URL",
"devii": "DEVPLACE_DEVII_URL",
"bot": "DEVPLACE_BOT_URL",
"backup": "DEVPLACE_BACKUP_URL",
"containers": "DEVPLACE_CONTAINERS_URL",
"telegram": "DEVPLACE_TELEGRAM_URL",
"email": "DEVPLACE_EMAIL_URL",
"news": "DEVPLACE_NEWS_URL",
"gitea": "DEVPLACE_GITEA_URL",
"audit": "DEVPLACE_AUDIT_URL",
"xmlrpc": "DEVPLACE_XMLRPC_URL",
}
INGRESS_ROUTES: tuple[IngressRoute, ...] = (
IngressRoute("/openai", "gateway"),
IngressRoute("/devii", "devii", websocket=True),
IngressRoute("/pubsub", "pubsub", websocket=True),
IngressRoute("/zips", "jobs"),
IngressRoute("/forks", "jobs"),
IngressRoute("/tools", "jobs", websocket=True),
IngressRoute("/xmlrpc", "xmlrpc"),
)
INGRESS_WS_PREFIXES: tuple[tuple[str, str], ...] = (
(
"/projects/",
"containers",
),
)
FORBIDDEN_GAPS: tuple[tuple[int, int], ...] = (
(10520, 10599),
(10610, 10619),
(10650, 10699),
(10750, 10799),
(20550, 20599),
(20650, 20699),
)
PORT_HINTS: dict[int, str] = {
10500: "web service",
20500: "test orchestrator",
10502: "locust",
}
_MICRO_DEV_PORTS: dict[str, int] = {spec.name: spec.port for spec in SERVICE_SPECS}
XMLRPC_RAW_SOCKET_PORT_DEV = 10648
def xmlrpc_raw_socket_port(profile: str) -> int:
if profile == "micro-test":
return XMLRPC_RAW_SOCKET_PORT_DEV + 10000
if profile == "micro-prod":
return XMLRPC_RAW_SOCKET_PORT_DEV + 100
return XMLRPC_RAW_SOCKET_PORT_DEV
def build_profiles() -> dict[str, dict[str, int]]:
return {
"micro-dev": dict(_MICRO_DEV_PORTS),
"micro-test": {
k: (20500 if k == "web" else v + 10000) for k, v in _MICRO_DEV_PORTS.items()
},
"micro-prod": {
k: (10500 if k == "web" else v + 100) for k, v in _MICRO_DEV_PORTS.items()
},
"locust": {"app": 10502, "ui": 10503},
}
def orchestrator_services_dict() -> dict[str, dict]:
return {
spec.name: {
"module": spec.module,
"port": spec.port,
"tier": spec.tier,
"workers": spec.workers,
"stateful": spec.stateful,
"depends_on": list(spec.depends_on),
}
for spec in SERVICE_SPECS
}
def health_client_timeout(name: str) -> float:
spec = SERVICES.get(name)
if spec is None:
return 2.0
return spec.health_client_timeout