"""Legacy scheduler scoring — kept for backward compatibility. Re-exported by :mod:`backend.scheduler` so existing callers (``from backend.scheduler import score_node, build_distcc_hosts``) keep working. """ from __future__ import annotations import logging from typing import Any, List, Mapping from backend.governor import thermal_cap log = logging.getLogger(__name__) def score_node(node: Mapping[str, Any]) -> float: """Return a 0..N scheduling score for ``node`` (higher = better).""" if node["state"] == "offline": return 0.0 agent = node.get("agent") or {} try: load = float(str(agent.get("load", "1 1 1")).split()[0]) except (ValueError, IndexError, AttributeError): log.debug("could not parse load=%r from node %s; falling back to 1.0", agent.get("load"), node.get("name")) load = 1.0 base = 10.0 capacity = node.get("max_jobs", 8) score = (base + capacity) - (load * 3.0) return max(score, 0.1) * thermal_cap(agent) def build_distcc_hosts(nodes: List[Mapping[str, Any]]) -> str: """Build a ``DISTCC_HOSTS`` string weighted by :func:`score_node`.""" scored = [(n, score_node(n)) for n in nodes] total = sum(s for _, s in scored) or 1.0 hosts: List[str] = [] for node, score in scored: if node["state"] == "offline": continue weight = int((score / total) * 64) weight = max(1, weight) hosts.append(f"{node['host']}/{weight}") return " ".join(hosts)