diff --git a/robot.py b/robot.py index 90978f2..e9d93fd 100644 --- a/robot.py +++ b/robot.py @@ -117,6 +117,7 @@ class Robot: # 初始化插件系统 self.LOG.debug("开始初始化插件系统...") + plugin_bootstrap_started_at = time.perf_counter() self.plugin_registry = PluginRegistry() self.plugin_modules = {} # 存储已加载的插件模块 self.plugins = {} # 存储已加载的插件实例 @@ -132,7 +133,10 @@ class Robot: self.plugin_manager = PluginManager(plugin_dir=getattr(self.config, "plugin_dir", "plugins")) self.plugin_manager.set_system_context(self.system_context) + plugin_load_started_at = time.perf_counter() self.plugins = self.plugin_manager.load_all_plugins() + plugin_load_cost_ms = int((time.perf_counter() - plugin_load_started_at) * 1000) + self.LOG.info(f"插件加载完成: count={len(self.plugins)} cost={plugin_load_cost_ms}ms") # 插件热加载默认关闭: # 1. 它会持续轮询插件目录并调用 discover_plugins,线上运行会产生额外扫盘开销; # 2. 对当前以“稳定运行”为主的场景,这类自动热更新收益远低于成本; @@ -144,20 +148,45 @@ class Robot: self.LOG.info(f"插件热加载监听已启用,轮询间隔 {interval_seconds}s") else: self.LOG.info("插件热加载监听已禁用,启动阶段不再自动扫盘检查插件变更") + system_job_started_at = time.perf_counter() self.system_job_loader = SystemJobLoader(self, self.system_job_db) - self.system_job_loader.init_and_load() + # 启动阶段只做任务注册,不同步补跑历史漏执行任务: + # 1. 旧逻辑会在这里直接补跑系统任务,重任务会把主进程启动拖慢几十秒; + # 2. 用户看到的日志像“卡在插件系统初始化”,实际常常是补偿任务在阻塞; + # 3. 这里先保证主流程快速完成,后续如需人工补跑,可在后台单独触发。 + self.system_job_loader.init_and_load(run_startup_compensation=False) + system_job_cost_ms = int((time.perf_counter() - system_job_started_at) * 1000) + self.LOG.info(f"系统任务装载完成: cost={system_job_cost_ms}ms") + plugin_schedule_started_at = time.perf_counter() self.plugin_schedule_manager = PluginScheduleManager(self.plugin_manager, self.plugin_schedule_db) - self.plugin_schedule_manager.init_and_load() + # 插件调度同样关闭启动期同步补偿,避免某些定时任务在启动时直接执行。 + self.plugin_schedule_manager.init_and_load(run_startup_compensation=False) + plugin_schedule_cost_ms = int((time.perf_counter() - plugin_schedule_started_at) * 1000) + self.LOG.info(f"插件调度装载完成: cost={plugin_schedule_cost_ms}ms") # 将历史业务型系统任务迁移到插件调度配置,避免升级后出现“任务丢失”。 + migration_started_at = time.perf_counter() migration_result = self.plugin_schedule_manager.migrate_from_system_jobs(self.system_job_db) if migration_result.get("migrated", 0) > 0: self.LOG.info(f"系统任务迁移到插件任务完成: {migration_result}") self.plugin_schedule_manager.reload_from_db() + migration_cost_ms = int((time.perf_counter() - migration_started_at) * 1000) + self.LOG.info(f"插件任务迁移检查完成: cost={migration_cost_ms}ms result={migration_result}") # 迁移完成后,清理已下沉到插件层的系统任务,避免后台重复维护两套配置。 + cleanup_started_at = time.perf_counter() self._cleanup_migrated_system_jobs() + cleanup_cost_ms = int((time.perf_counter() - cleanup_started_at) * 1000) # 加载插件 - self.LOG.debug("插件系统初始化完成") + plugin_bootstrap_cost_ms = int((time.perf_counter() - plugin_bootstrap_started_at) * 1000) + self.LOG.info( + "插件系统初始化完成: " + f"total={plugin_bootstrap_cost_ms}ms, " + f"plugin_load={plugin_load_cost_ms}ms, " + f"system_jobs={system_job_cost_ms}ms, " + f"plugin_schedules={plugin_schedule_cost_ms}ms, " + f"migration={migration_cost_ms}ms, " + f"cleanup={cleanup_cost_ms}ms" + ) GroupBotManager.load_local_cache() # 权限模块加载 diff --git a/utils/plugin_schedule_manager.py b/utils/plugin_schedule_manager.py index b9767fd..5f12119 100644 --- a/utils/plugin_schedule_manager.py +++ b/utils/plugin_schedule_manager.py @@ -21,9 +21,9 @@ class PluginScheduleManager: self._schedule_job_map: Dict[int, str] = {} self._compensation_tolerance_seconds = 120 - def init_and_load(self): + def init_and_load(self, *, run_startup_compensation: bool = False): self.db.init_tables() - self.reload_from_db() + self.reload_from_db(run_startup_compensation=run_startup_compensation) def migrate_from_system_jobs(self, system_job_db) -> Dict[str, int]: """把历史系统任务配置迁移到插件任务表(幂等)。""" @@ -252,7 +252,7 @@ class PluginScheduleManager: self.db.create_log(schedule_id, status, summary, detail) return {"success": status == "success", "summary": summary, "detail": detail} - def reload_from_db(self): + def reload_from_db(self, *, run_startup_compensation: bool = True): self.sync_defaults() # 清理旧注册,避免重复 @@ -281,7 +281,7 @@ class PluginScheduleManager: try: trigger_type = row.get("trigger_type", "at_times") trigger_config = row.get("trigger_config", {"time_list": ["09:00"]}) - if self._should_compensate_once(schedule_id, trigger_type, trigger_config): + if run_startup_compensation and self._should_compensate_once(schedule_id, trigger_type, trigger_config): logger.warning( f"插件调度触发漏执行补偿: schedule_id={schedule_id}, " f"plugin={row.get('plugin_name')}, action={row.get('action_key')}" diff --git a/utils/system_jobs.py b/utils/system_jobs.py index 928343e..930a48e 100644 --- a/utils/system_jobs.py +++ b/utils/system_jobs.py @@ -191,10 +191,10 @@ class SystemJobLoader: return False return latest_log_at < (expected_at - timedelta(seconds=self._compensation_tolerance_seconds)) - def init_and_load(self): + def init_and_load(self, *, run_startup_compensation: bool = False): self.db.init_tables() self._seed_defaults() - self.reload_from_db() + self.reload_from_db(run_startup_compensation=run_startup_compensation) def _seed_defaults(self): for item in self._job_defs.values(): @@ -212,7 +212,7 @@ class SystemJobLoader: } ) - def reload_from_db(self): + def reload_from_db(self, *, run_startup_compensation: bool = True): # 每次重载前先补齐默认任务,避免误删后无法恢复 self._seed_defaults() @@ -275,7 +275,7 @@ class SystemJobLoader: try: trigger_type = row.get("trigger_type", definition["trigger_type"]) trigger_config = row.get("trigger_config", definition["trigger_config"]) - if self._should_compensate_once(job_key, trigger_type, trigger_config): + if run_startup_compensation and self._should_compensate_once(job_key, trigger_type, trigger_config): logger.warning(f"系统任务触发漏执行补偿: job_key={job_key}") self._run_coro_blocking(_wrapped_handler()) except Exception as e: