| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- import os
- import sys
- import time
- import json
- import argparse
- from typing import Dict
- from vs_types import GroupConfig
- from gco_wrapper import GCOWrapper
- from logger_setup import setup_app_logger
- from configure import REDIS_CFG
- from sentinel import SentinelGCO
- from utils.cloud_config import load_remote_or_cache, compute_config_hash, fetch_cloud_config, save_local_cache
- def sync_sentinel_groups(
- groups_conf: list,
- active_wrappers: Dict[str, GCOWrapper],
- app_logger
- ):
- new_groups_by_id: Dict[str, GroupConfig] = {}
- for item in groups_conf:
- cfg = GroupConfig.from_json(item)
- new_groups_by_id[cfg.identifier] = cfg
- current_ids = list(active_wrappers.keys())
- for gid in current_ids:
- wrapper = active_wrappers[gid]
- new_cfg = new_groups_by_id.get(gid)
- if not new_cfg or not new_cfg.enable:
- app_logger.info(f"Stopping disabled/removed Sentinel group [{gid}]...")
- try:
- wrapper.stop()
- except Exception as e:
- app_logger.error(f"Error stopping group [{gid}]: {e}")
- del active_wrappers[gid]
- for gid, cfg in new_groups_by_id.items():
- if not cfg.enable:
- continue
- if gid in active_wrappers:
- app_logger.info(f"Updating configuration for active Sentinel group [{gid}]...")
- try:
- active_wrappers[gid].update_config(cfg)
- except Exception as e:
- app_logger.error(f"Error updating config for group [{gid}]: {e}")
- else:
- app_logger.info(f"Starting new wrapper for Sentinel group [{gid}]...")
- try:
- wrapper = GCOWrapper(
- gco_class=SentinelGCO,
- gco_cfg=cfg,
- redis_conf=REDIS_CFG
- )
- wrapper.load()
- wrapper.start()
- active_wrappers[gid] = wrapper
- except Exception as e:
- app_logger.error(f"Failed to start group [{gid}]: {e}")
- def main():
- parser = argparse.ArgumentParser(description="Sentinel Runner")
- parser.add_argument(
- "-c", "--config",
- type=str,
- required=False,
- default=None,
- help="Path to local config.json. If specified, disables cloud config and runs with local file."
- )
- parser.add_argument(
- "--poll-interval",
- type=float,
- required=False,
- default=30.0,
- help="Interval in seconds to poll cloud config (default: 30.0s)"
- )
- args = parser.parse_args()
- # 逻辑 1:默认开启云端配置,除非命令行指定了 -c/--config 本地文件路径
- if args.config is not None:
- config_path = args.config
- use_cloud = False
- else:
- config_path = "config/config_sentinel.json"
- use_cloud = True
- # 逻辑 2:直接从环境变量获取 node_id,默认 node01
- node_id = os.getenv("NODE_ID") or "node01"
- config_key = f"sentinel_config:{node_id}"
- poll_interval = args.poll_interval
- app_logger = setup_app_logger("Sentinel")
- app_logger.info(f"Sentinel Logger is ready! (Node ID: '{node_id}', Cloud Mode: {use_cloud})")
- groups_conf, current_hash, loaded_from_remote = load_remote_or_cache(
- config_key=config_key,
- local_cache_path=config_path,
- use_cloud=use_cloud,
- logger=app_logger.info
- )
- active_wrappers: Dict[str, GCOWrapper] = {}
- sync_sentinel_groups(groups_conf, active_wrappers, app_logger)
- app_logger.info(
- f"Successfully initialized Sentinel with {len(active_wrappers)} active group(s)."
- )
- if use_cloud:
- app_logger.info(f"Cloud config active for key '{config_key}'. Polling every {poll_interval}s.")
- last_poll_time = time.time()
- try:
- while True:
- time.sleep(1)
- now = time.time()
- if use_cloud and (now - last_poll_time >= poll_interval):
- last_poll_time = now
- try:
- new_conf = fetch_cloud_config(config_key)
- if new_conf is not None:
- new_hash = compute_config_hash(new_conf)
- if new_hash != current_hash:
- app_logger.info(
- f"Cloud config change detected (hash: {current_hash[:8]} -> {new_hash[:8]}). Auto-reloading..."
- )
- save_local_cache(config_path, new_conf)
- sync_sentinel_groups(new_conf, active_wrappers, app_logger)
- current_hash = new_hash
- app_logger.info(f"Auto-reload completed. Currently {len(active_wrappers)} group(s) running.")
- except Exception as e:
- app_logger.warning(f"Error polling cloud config key '{config_key}': {e}. Retrying next cycle.")
- except KeyboardInterrupt:
- app_logger.info("Shutting down Sentinels...")
- for gid, wrapper in list(active_wrappers.items()):
- try:
- wrapper.stop()
- except Exception as e:
- app_logger.error(f"Error stopping group [{gid}]: {e}")
- if __name__ == "__main__":
- main()
|