feat: on-demand RDP - connect xfreerdp only when session opens

Replaces always-on xfreerdp with on-demand model (load 12 to under 1 at idle).
- rdp-proxy/manager.py: HTTP server port 7001 managing xfreerdp lifecycle
- rdp-proxy/entrypoint.sh: starts Xvfb+x11vnc+websockify+manager, no auto-connect
- rdp-proxy/Dockerfile: adds python3, copies manager.py, exposes 7001
- runtime.py: connect_rdp_slot and disconnect_rdp_slot via manager HTTP API
- terminate_session_record: disconnect instead of container restart
- main.py: calls connect_rdp_slot in background thread on session create
- maintenance.py: cleanup_loop disconnects on expire, run_maintenance_service
  includes RDP slot init, maintenance_runner fixed to import maintenance
This commit is contained in:
2026-05-01 10:12:52 +00:00
parent 82024a36c4
commit 58cb8b1035
7 changed files with 204 additions and 72 deletions
+33 -2
View File
@@ -670,6 +670,37 @@ def stop_rdp_slot_container(container_name: str) -> None:
logger.exception("rdp_slot_container_stop_failed container=%s", container_name)
def _call_rdp_manager(container_name: str, endpoint: str) -> bool:
url = f"http://{container_name}:7001{endpoint}"
try:
resp = requests.post(url, timeout=10)
logger.info("rdp_manager_%s container=%s status=%s", endpoint.strip('/'), container_name, resp.status_code)
return resp.ok
except Exception:
logger.exception("rdp_manager_call_failed container=%s endpoint=%s", container_name, endpoint)
return False
def connect_rdp_slot(slot_id: int) -> None:
db = SessionLocal()
try:
slot = db.get(RdpSlot, slot_id)
if slot and slot.container_name:
_call_rdp_manager(slot.container_name, "/connect")
finally:
db.close()
def disconnect_rdp_slot(slot_id: int) -> None:
db = SessionLocal()
try:
slot = db.get(RdpSlot, slot_id)
if slot and slot.container_name:
_call_rdp_manager(slot.container_name, "/disconnect")
finally:
db.close()
def _restart_rdp_slot_bg(slot_id: int) -> None:
db = SessionLocal()
try:
@@ -719,9 +750,9 @@ def terminate_session_record(
if cid.startswith("RDPSLOT:"):
try:
slot_id = int(cid.split(":", 1)[1])
threading.Thread(target=_restart_rdp_slot_bg, args=(slot_id,), daemon=True).start()
threading.Thread(target=disconnect_rdp_slot, args=(slot_id,), daemon=True).start()
except Exception:
logger.exception("rdp_slot_restart_schedule_failed cid=%s", cid)
logger.exception("rdp_slot_disconnect_failed cid=%s", cid)
sess.status = new_status
sess.last_access_at = now_utc()
log_event(