|
# 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 |