Files
MoviePilot/app/runtime/extensions/plugin/database.py
Aqr-K d7c5955031 fix(plugin): 插件自有数据库释放与销毁全程容错,并修正建表去重与 schema 命名
release/destroy 统一经 _close_handle 先清线程局部会话再 dispose,两步失败都
只记日志:单个插件的连接池故障不再让 close_database 跳过宿主同步与异步引擎的
释放,release_all_databases 也逐插件隔离。按模型建表对 __table__ 去重,单表
继承的父子类一并声明时不再对同一张表建两次。

卸载编排先删插件数据、后停插件,停机钩子里的 get_database() 会把刚销毁的库
重新建出来:注册表记下已销毁的插件标识,其后的 release 改为再次销毁并清除
标记,ensure 则撤销标记,宿主编排代码不动。PostgreSQL schema 名在归一改写过
标识或超长时追加插件标识哈希并截到 63 字节,My-Plugin、My_Plugin 与
my_plugin 不再折叠到同一个 schema 而在卸载时互相 DROP。

start 的失败分支释放已经建立、却进不了运行态的句柄,整体停止把只登记在
_classes 里的插件一并释放。声明的迁移目录不存在时在建句柄之前抛
FileNotFoundError,不再留下空库;SQLite 迁移 URL 改由引擎渲染;
_get_sqlite_engine 的连接参数下沉到实际使用它的异步分支。
2026-09-02 02:14:19 -04:00

74 lines
2.2 KiB
Python

"""插件运行时自有数据库端口。"""
from __future__ import annotations
from collections.abc import Callable, Sequence
from pathlib import Path
PluginDatabaseEnsure = Callable[[str, Sequence[type], Path | None], None]
PluginDatabaseRelease = Callable[[str], None]
PluginDatabaseDestroy = Callable[[str], None]
def _ignore_ensure(
_plugin_id: str,
_models: Sequence[type],
_migrations: Path | None,
) -> None:
"""组合根尚未装配时忽略插件建库。"""
def _ignore_release(_plugin_id: str) -> None:
"""组合根尚未装配时忽略插件数据库释放。"""
def _ignore_destroy(_plugin_id: str) -> None:
"""组合根尚未装配时忽略插件数据库销毁。"""
class PluginDatabase:
"""封装插件自有数据库的建立、释放与销毁能力。"""
def __init__(
self,
*,
ensure: PluginDatabaseEnsure = _ignore_ensure,
release: PluginDatabaseRelease = _ignore_release,
destroy: PluginDatabaseDestroy = _ignore_destroy,
) -> None:
"""保存由启动组合根提供的建库、释放与销毁函数。"""
self._ensure = ensure
self._release = release
self._destroy = destroy
def ensure(
self,
plugin_id: str,
models: Sequence[type],
migrations: Path | None,
) -> None:
"""按插件声明建立自有数据库,两项声明都为空时不建库。"""
self._ensure(plugin_id, models, migrations)
def release(self, plugin_id: str) -> None:
"""释放插件自有数据库的连接,保留数据。"""
self._release(plugin_id)
def destroy(self, plugin_id: str) -> None:
"""销毁插件自有数据库,仅限删除插件数据的路径调用。"""
self._destroy(plugin_id)
_plugin_database = PluginDatabase()
def configure_plugin_database(database: PluginDatabase) -> None:
"""由启动组合根替换插件自有数据库实现。"""
global _plugin_database
_plugin_database = database
def get_plugin_database() -> PluginDatabase:
"""返回当前插件自有数据库端口。"""
return _plugin_database