feat: stabilize multi-region runtime sync and worker orchestration
This commit is contained in:
@@ -14,6 +14,8 @@ REDIS_KEYS = {
|
||||
"proxy_config": "domain_tool:proxy_config",
|
||||
"thread_count": "domain_tool:thread_count",
|
||||
"node_thread_counts": "domain_tool:node_thread_counts",
|
||||
"process_count": "domain_tool:process_count",
|
||||
"node_process_counts": "domain_tool:node_process_counts",
|
||||
"credentials": "domain_tool:credentials",
|
||||
"runtime_settings": "domain_tool:runtime_settings",
|
||||
}
|
||||
@@ -40,6 +42,16 @@ def _normalize_thread_count(value: object, *, field_name: str = "thread_count")
|
||||
return thread_count
|
||||
|
||||
|
||||
def _normalize_process_count(value: object, *, field_name: str = "process_count") -> int:
|
||||
try:
|
||||
process_count = int(value)
|
||||
except Exception as exc:
|
||||
raise ValueError(f"{field_name} must be an integer") from exc
|
||||
if process_count < 1:
|
||||
raise ValueError(f"{field_name} must be >= 1")
|
||||
return process_count
|
||||
|
||||
|
||||
def _normalize_node_thread_counts(payload: object) -> dict[str, int]:
|
||||
if payload in (None, ""):
|
||||
return {}
|
||||
@@ -55,14 +67,32 @@ def _normalize_node_thread_counts(payload: object) -> dict[str, int]:
|
||||
return normalized
|
||||
|
||||
|
||||
def _normalize_node_process_counts(payload: object) -> dict[str, int]:
|
||||
if payload in (None, ""):
|
||||
return {}
|
||||
if not isinstance(payload, dict):
|
||||
raise ValueError("node_process_counts must be an object")
|
||||
|
||||
normalized: dict[str, int] = {}
|
||||
for raw_node_code, raw_process_count in payload.items():
|
||||
node_code = str(raw_node_code or "").strip()
|
||||
if not node_code:
|
||||
raise ValueError("node_process_counts contains empty node code")
|
||||
normalized[node_code] = _normalize_process_count(
|
||||
raw_process_count,
|
||||
field_name=f"node_process_counts.{node_code}",
|
||||
)
|
||||
return normalized
|
||||
|
||||
|
||||
def _load_thread_count_config() -> tuple[int, dict[str, int]]:
|
||||
thread_count_payload = read_json("thread_count.json", default={"thread_count": "2"})
|
||||
thread_count_payload = read_json("thread_count.json", default={"thread_count": "1000"})
|
||||
node_thread_counts_payload = read_json("node_thread_counts.json", default={})
|
||||
|
||||
try:
|
||||
default_thread_count = _normalize_thread_count(thread_count_payload.get("thread_count", 2))
|
||||
default_thread_count = _normalize_thread_count(thread_count_payload.get("thread_count", 1000))
|
||||
except ValueError:
|
||||
default_thread_count = 2
|
||||
default_thread_count = 1000
|
||||
try:
|
||||
node_thread_counts = _normalize_node_thread_counts(node_thread_counts_payload)
|
||||
except ValueError:
|
||||
@@ -86,9 +116,40 @@ def _load_thread_count_config() -> tuple[int, dict[str, int]]:
|
||||
return default_thread_count, node_thread_counts
|
||||
|
||||
|
||||
def _load_process_count_config() -> tuple[int, dict[str, int]]:
|
||||
process_count_payload = read_json("process_count.json", default={"process_count": "80"})
|
||||
node_process_counts_payload = read_json("node_process_counts.json", default={})
|
||||
|
||||
try:
|
||||
default_process_count = _normalize_process_count(process_count_payload.get("process_count", 80))
|
||||
except ValueError:
|
||||
default_process_count = 80
|
||||
try:
|
||||
node_process_counts = _normalize_node_process_counts(node_process_counts_payload)
|
||||
except ValueError:
|
||||
node_process_counts = {}
|
||||
|
||||
redis_client = get_redis()
|
||||
try:
|
||||
if redis_process_count := redis_client.get(REDIS_KEYS["process_count"]):
|
||||
try:
|
||||
default_process_count = _normalize_process_count(redis_process_count)
|
||||
except ValueError:
|
||||
pass
|
||||
if redis_node_process_counts := redis_client.get(REDIS_KEYS["node_process_counts"]):
|
||||
try:
|
||||
node_process_counts = _normalize_node_process_counts(json.loads(redis_node_process_counts))
|
||||
except ValueError:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return default_process_count, node_process_counts
|
||||
|
||||
|
||||
def resolve_thread_count(node_code: str | None = None, settings_payload: dict | None = None) -> dict:
|
||||
payload = settings_payload or get_settings_payload()
|
||||
default_thread_count = int(payload.get("thread_count", 2))
|
||||
default_thread_count = int(payload.get("thread_count", 1000))
|
||||
node_thread_counts = _normalize_node_thread_counts(payload.get("node_thread_counts", {}))
|
||||
normalized_node_code = str(node_code or app_settings.node_code or "").strip()
|
||||
|
||||
@@ -110,10 +171,35 @@ def resolve_thread_count(node_code: str | None = None, settings_payload: dict |
|
||||
}
|
||||
|
||||
|
||||
def resolve_process_count(node_code: str | None = None, settings_payload: dict | None = None) -> dict:
|
||||
payload = settings_payload or get_settings_payload()
|
||||
default_process_count = int(payload.get("process_count", 80))
|
||||
node_process_counts = _normalize_node_process_counts(payload.get("node_process_counts", {}))
|
||||
normalized_node_code = str(node_code or app_settings.node_code or "").strip()
|
||||
|
||||
override_process_count = None
|
||||
source = "default"
|
||||
effective_process_count = default_process_count
|
||||
if normalized_node_code and normalized_node_code in node_process_counts:
|
||||
override_process_count = node_process_counts[normalized_node_code]
|
||||
effective_process_count = override_process_count
|
||||
source = "node_override"
|
||||
|
||||
return {
|
||||
"node_code": normalized_node_code,
|
||||
"default_process_count": default_process_count,
|
||||
"effective_process_count": effective_process_count,
|
||||
"override_process_count": override_process_count,
|
||||
"source": source,
|
||||
"node_process_counts": node_process_counts,
|
||||
}
|
||||
|
||||
|
||||
def get_settings_payload() -> dict:
|
||||
detect_options = read_json("detect_options.json", default={})
|
||||
proxy_config = read_json("proxy_config.json", default={})
|
||||
thread_count, node_thread_counts = _load_thread_count_config()
|
||||
process_count, node_process_counts = _load_process_count_config()
|
||||
|
||||
redis_client = get_redis()
|
||||
try:
|
||||
@@ -129,6 +215,8 @@ def get_settings_payload() -> dict:
|
||||
"proxy_config": proxy_config,
|
||||
"thread_count": thread_count,
|
||||
"node_thread_counts": node_thread_counts,
|
||||
"process_count": process_count,
|
||||
"node_process_counts": node_process_counts,
|
||||
"current_node_code": app_settings.node_code,
|
||||
"runtime_settings": get_runtime_settings(),
|
||||
}
|
||||
@@ -193,12 +281,18 @@ def update_settings_payload(payload: dict) -> dict:
|
||||
proxy_config = payload.get("proxy_config", current["proxy_config"])
|
||||
thread_count = _normalize_thread_count(payload.get("thread_count", current["thread_count"]))
|
||||
node_thread_counts = _normalize_node_thread_counts(payload.get("node_thread_counts", current.get("node_thread_counts", {})))
|
||||
process_count = _normalize_process_count(payload.get("process_count", current.get("process_count", 80)))
|
||||
node_process_counts = _normalize_node_process_counts(
|
||||
payload.get("node_process_counts", current.get("node_process_counts", {}))
|
||||
)
|
||||
runtime_settings = update_runtime_settings(payload.get("runtime_settings", current["runtime_settings"]))
|
||||
|
||||
write_json("detect_options.json", detect_options)
|
||||
write_json("proxy_config.json", proxy_config)
|
||||
write_json("thread_count.json", {"thread_count": str(thread_count)})
|
||||
write_json("node_thread_counts.json", node_thread_counts)
|
||||
write_json("process_count.json", {"process_count": str(process_count)})
|
||||
write_json("node_process_counts.json", node_process_counts)
|
||||
redis_client = get_redis()
|
||||
try:
|
||||
redis_client.set(REDIS_KEYS["detect_options"], json.dumps(detect_options, ensure_ascii=False))
|
||||
@@ -209,12 +303,16 @@ def update_settings_payload(payload: dict) -> dict:
|
||||
redis_client.publish("domain_tool:thread_count:update", str(thread_count))
|
||||
redis_client.set(REDIS_KEYS["node_thread_counts"], json.dumps(node_thread_counts, ensure_ascii=False))
|
||||
redis_client.publish("domain_tool:node_thread_counts:update", json.dumps(node_thread_counts, ensure_ascii=False))
|
||||
redis_client.set(REDIS_KEYS["runtime_settings"], json.dumps(runtime_settings, ensure_ascii=False))
|
||||
redis_client.publish("domain_tool:config_update", "runtime_settings")
|
||||
redis_client.set(REDIS_KEYS["process_count"], process_count)
|
||||
redis_client.publish("domain_tool:process_count:update", str(process_count))
|
||||
redis_client.set(REDIS_KEYS["node_process_counts"], json.dumps(node_process_counts, ensure_ascii=False))
|
||||
redis_client.publish("domain_tool:node_process_counts:update", json.dumps(node_process_counts, ensure_ascii=False))
|
||||
redis_client.publish("domain_tool:config_update", "node_thread_counts")
|
||||
redis_client.publish("domain_tool:config_update", "node_process_counts")
|
||||
redis_client.publish("domain_tool:config_update", "detect_options")
|
||||
redis_client.publish("domain_tool:config_update", "proxy_config")
|
||||
redis_client.publish("domain_tool:config_update", "thread_count")
|
||||
redis_client.publish("domain_tool:config_update", "process_count")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -223,6 +321,8 @@ def update_settings_payload(payload: dict) -> dict:
|
||||
"proxy_config": proxy_config,
|
||||
"thread_count": thread_count,
|
||||
"node_thread_counts": node_thread_counts,
|
||||
"process_count": process_count,
|
||||
"node_process_counts": node_process_counts,
|
||||
"current_node_code": app_settings.node_code,
|
||||
"runtime_settings": runtime_settings,
|
||||
}
|
||||
@@ -254,6 +354,12 @@ def validate_settings_payload(payload: dict) -> None:
|
||||
if "node_thread_counts" in payload:
|
||||
_normalize_node_thread_counts(payload["node_thread_counts"])
|
||||
|
||||
if "process_count" in payload:
|
||||
_normalize_process_count(payload["process_count"])
|
||||
|
||||
if "node_process_counts" in payload:
|
||||
_normalize_node_process_counts(payload["node_process_counts"])
|
||||
|
||||
if "detect_options" in payload:
|
||||
detect_options = payload["detect_options"]
|
||||
if not isinstance(detect_options, dict):
|
||||
|
||||
Reference in New Issue
Block a user