-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Fix: hot reload state synchronization issue in ProviderManager #2796
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -384,41 +384,52 @@ async def load_provider(self, provider_config: dict): | |
| f"实例化 {provider_config['type']}({provider_config['id']}) 提供商适配器失败:{e}" | ||
| ) | ||
|
|
||
| def _sync_current_provider(self, inst_list, curr_attr_name, provider_name): | ||
| """同步当前提供商实例,确保其有效性并在必要时自动选择第一个可用实例""" | ||
| curr = getattr(self, curr_attr_name) | ||
| # 如果当前实例无效(不在inst_map中),则置为None | ||
| if curr and curr.meta().id not in self.inst_map: | ||
| curr = None | ||
| # 如果当前没有实例但列表中有实例,则自动选择第一个 | ||
| if curr is None: | ||
| if inst_list: | ||
| curr = inst_list[0] | ||
| logger.info( | ||
| f"自动选择 {curr.meta().id} 作为当前{provider_name}提供商适配器。" | ||
| ) | ||
| else: | ||
| curr = None | ||
| setattr(self, curr_attr_name, curr) | ||
|
|
||
| async def reload(self, provider_config: dict): | ||
| await self.terminate_provider(provider_config["id"]) | ||
| if provider_config["enable"]: | ||
| await self.load_provider(provider_config) | ||
|
|
||
| # 重新获取最新的配置,增加错误处理 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
async def post_update_provider(self):
update_provider_config = await request.json
provider_id = update_provider_config.get("id", None)
new_config = update_provider_config.get("config", None)
if not provider_id or not new_config:
return Response().error("参数错误").__dict__
for i, provider in enumerate(self.config["provider"]):
if provider["id"] == provider_id:
self.config["provider"][i] = new_config
break
else:
return Response().error("未找到对应服务提供商").__dict__
try:
save_config(self.config, self.config, is_core=True)
await self.core_lifecycle.provider_manager.reload(new_config)
except Exception as e:
return Response().error(str(e)).__dict__
return Response().ok(None, "更新成功,已经实时生效~").__dict__是直接对 self.config["provider"] 列表对象修改的
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #2763 根据我log输出的结果是,增减之后他的列表provider仍然是初始化的列表,而不是修改后的provider。 更改provider信息的时候,provider实例本身是马上更新了,但是provider列表没有更新。导致找不到这个provider的id。 项目太庞大了,我没有很认真的研究,我是局限于我认识空间想办法解决,大佬觉得最佳的更新方法是什么?应该有一行代码立刻更新这个列表的方法,但是我没找到准确位置。
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
经过我的多重分析。 提供商有3个方法。 但是新增的时候,如果不合法(比如没有api key),他会添加一个不存在于inst_mapd的提供商。 我这个补丁是在更新方法里,每次更新的时候强制加入所有提供商,只是一个亡羊补牢。 这个交由您来判断,这个pr作废。 但是这个涉及到了设计逻辑,我认为这个需要大佬您亲自决定应该如何修改。
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
其实我也一直有遇到过这个问题,包括社区群里面也有不少人反馈这个问题,但是由于不是必现所以我一直没排查出来。 |
||
| try: | ||
| latest_config = self.acm.get_conf("default") | ||
| self.providers_config = latest_config.get("provider", []) | ||
| except Exception as e: | ||
| logger.error(f"获取最新配置时出错: {e}") | ||
| # 使用空列表作为后备方案 | ||
| self.providers_config = [] | ||
|
|
||
| # 和配置文件保持同步 | ||
| config_ids = [provider["id"] for provider in self.providers_config] | ||
| logger.debug(f"providers in user's config: {config_ids}") | ||
| for key in list(self.inst_map.keys()): | ||
| if key not in config_ids: | ||
| await self.terminate_provider(key) | ||
|
|
||
| if len(self.provider_insts) == 0: | ||
| self.curr_provider_inst = None | ||
| elif self.curr_provider_inst is None and len(self.provider_insts) > 0: | ||
| self.curr_provider_inst = self.provider_insts[0] | ||
| logger.info( | ||
| f"自动选择 {self.curr_provider_inst.meta().id} 作为当前提供商适配器。" | ||
| ) | ||
|
|
||
| if len(self.stt_provider_insts) == 0: | ||
| self.curr_stt_provider_inst = None | ||
| elif self.curr_stt_provider_inst is None and len(self.stt_provider_insts) > 0: | ||
| self.curr_stt_provider_inst = self.stt_provider_insts[0] | ||
| logger.info( | ||
| f"自动选择 {self.curr_stt_provider_inst.meta().id} 作为当前语音转文本提供商适配器。" | ||
| ) | ||
|
|
||
| if len(self.tts_provider_insts) == 0: | ||
| self.curr_tts_provider_inst = None | ||
| elif self.curr_tts_provider_inst is None and len(self.tts_provider_insts) > 0: | ||
| self.curr_tts_provider_inst = self.tts_provider_insts[0] | ||
| logger.info( | ||
| f"自动选择 {self.curr_tts_provider_inst.meta().id} 作为当前文本转语音提供商适配器。" | ||
| ) | ||
| # 使用辅助函数同步各个提供商实例 | ||
| self._sync_current_provider(self.provider_insts, "curr_provider_inst", "提供商") | ||
| self._sync_current_provider( | ||
| self.stt_provider_insts, "curr_stt_provider_inst", "语音转文本" | ||
| ) | ||
| self._sync_current_provider( | ||
| self.tts_provider_insts, "curr_tts_provider_inst", "文本转语音" | ||
| ) | ||
|
|
||
| def get_insts(self): | ||
| return self.provider_insts | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么不直接引用 self.curr_provider_inst 这些