add: Plugin 基类支持 [workers.config.database] 配置接入 PostgreSQL(url 优先,SQLite 回落)
This commit is contained in:
@@ -45,11 +45,11 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class MyPlugin(Plugin):
|
class MyPlugin(Plugin):
|
||||||
type = "my_plugin"
|
type = "my_plugin"
|
||||||
db_name = "my_plugin.db" # 自动在 data_dir 下建 SQLite 库;不需要则置 None
|
db_name = "my_plugin.db" # SQLite:自动在 data_dir 下建库;config 含 database.url 时优先走 PostgreSQL;不需要则置 None
|
||||||
auto_bind = True # 首次初始化时自动 auto_bind_models(self.type)
|
auto_bind = True # 首次初始化时自动 auto_bind_models(self.type)
|
||||||
|
|
||||||
async def on_init(self):
|
async def on_init(self):
|
||||||
# 数据库已由基类自动初始化(self.db)
|
# 数据库已由基类自动初始化(self.db,SQLite 或 PostgreSQL)
|
||||||
self.set_var("db", self.db) # 写入插件 global_var 模块
|
self.set_var("db", self.db) # 写入插件 global_var 模块
|
||||||
# self.spawn_task(self._background_loop()) # 后台任务(cleanup 自动取消)
|
# self.spawn_task(self._background_loop()) # 后台任务(cleanup 自动取消)
|
||||||
# self.register_cleanup(self._close_client) # 注册清理钩子(逆序执行)
|
# self.register_cleanup(self._close_client) # 注册清理钩子(逆序执行)
|
||||||
@@ -59,6 +59,15 @@ class MyPlugin(Plugin):
|
|||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# PostgreSQL 接入(可选):在插件 config.toml 配置 database 段后,
|
||||||
|
# 基类 init_database() 检测到 url 即走 Database.from_config 接入 PG::
|
||||||
|
#
|
||||||
|
# # config/workers/my_plugin/config.toml
|
||||||
|
# [workers.config.database]
|
||||||
|
# type = "postgresql"
|
||||||
|
# url = "postgresql+asyncpg://user:pwd@127.0.0.1:5432/mydb"
|
||||||
|
# generate_schemas = true
|
||||||
|
|
||||||
# 暴露给 app lifespan 的模块级入口(bound method,签名与旧写法一致)
|
# 暴露给 app lifespan 的模块级入口(bound method,签名与旧写法一致)
|
||||||
plugin = MyPlugin()
|
plugin = MyPlugin()
|
||||||
create_workers = plugin.create_workers
|
create_workers = plugin.create_workers
|
||||||
@@ -70,7 +79,7 @@ cleanup = plugin.cleanup
|
|||||||
| 属性 / 方法 | 说明 |
|
| 属性 / 方法 | 说明 |
|
||||||
| -------------- | ---------------------------------------------------------------------------- |
|
| -------------- | ---------------------------------------------------------------------------- |
|
||||||
| `type` | 插件类型(worker type),匹配 subject 前缀与 `config/workers/<type>`(必填) |
|
| `type` | 插件类型(worker type),匹配 subject 前缀与 `config/workers/<type>`(必填) |
|
||||||
| `db_name` | 默认 SQLite 文件名(放 `data_dir` 下);`None` 表示不自动建库 |
|
| `db_name` | 默认 SQLite 文件名(放 `data_dir` 下);config 含 `database.url` 时优先走 PostgreSQL;`None` 表示不自动建库 |
|
||||||
| `auto_bind` | 首次初始化时是否自动 `auto_bind_models(self.type)` |
|
| `auto_bind` | 首次初始化时是否自动 `auto_bind_models(self.type)` |
|
||||||
| `on_init()` | 首次 `create_workers` 时调用一次,初始化资源 |
|
| `on_init()` | 首次 `create_workers` 时调用一次,初始化资源 |
|
||||||
| `on_cleanup()` | `cleanup` 时调用,清理自定义资源 |
|
| `on_cleanup()` | `cleanup` 时调用,清理自定义资源 |
|
||||||
@@ -79,7 +88,7 @@ cleanup = plugin.cleanup
|
|||||||
|
|
||||||
- **幂等**:重复 `create_workers` 只初始化一次(`asyncio.Lock` 守卫,并发调用安全)
|
- **幂等**:重复 `create_workers` 只初始化一次(`asyncio.Lock` 守卫,并发调用安全)
|
||||||
- **统一日志**:`logger` 自动带 `[type]` 前缀
|
- **统一日志**:`logger` 自动带 `[type]` 前缀
|
||||||
- **数据库**:`init_database()` 统一建路径、建表、记录,`cleanup` 自动 `dispose()`
|
- **数据库**:`init_database()` 统一建库建表、记录,`cleanup` 自动 `dispose()`(SQLite 按 `db_name`;config 含 `database.url` 时走 PostgreSQL)
|
||||||
- **global_var**:`set_var()` / `get_var()` 统一读写插件 `global_var` 模块;`cleanup` 时自动将已发布的变量重置为 `None`,避免业务代码拿到已释放的资源
|
- **global_var**:`set_var()` / `get_var()` 统一读写插件 `global_var` 模块;`cleanup` 时自动将已发布的变量重置为 `None`,避免业务代码拿到已释放的资源
|
||||||
- **后台任务**:`spawn_task()` 跟踪,`cleanup` 时自动取消并 `gather`
|
- **后台任务**:`spawn_task()` 跟踪,`cleanup` 时自动取消并 `gather`
|
||||||
- **清理钩子**:`register_cleanup()` 注册,`cleanup` 时逆序执行
|
- **清理钩子**:`register_cleanup()` 注册,`cleanup` 时逆序执行
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ requires = ["hatchling"]
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "chongming-worker"
|
name = "chongming-worker"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
description = "chongming worker"
|
description = "chongming worker"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ Plugin 基类 — 统一 Worker 插件初始化与清理生命周期
|
|||||||
|
|
||||||
class MyPlugin(Plugin):
|
class MyPlugin(Plugin):
|
||||||
type = "myname"
|
type = "myname"
|
||||||
db_name = "myname.db" # 自动在 data_dir 下建库;不需要则置 None
|
db_name = "myname.db" # SQLite:自动在 data_dir 下建库;config 含 database.url 时优先走 PostgreSQL;不需要则置 None
|
||||||
auto_bind = True # 首次初始化时自动 auto_bind_models("myname")
|
auto_bind = True # 首次初始化时自动 auto_bind_models("myname")
|
||||||
|
|
||||||
async def on_init(self):
|
async def on_init(self):
|
||||||
# 数据库已由基类 _bootstrap 初始化(self.db)
|
# 数据库已由基类 _bootstrap 初始化(self.db,SQLite 或 PostgreSQL)
|
||||||
self.set_var("db", self.db)
|
self.set_var("db", self.db)
|
||||||
# 需要后台任务时:
|
# 需要后台任务时:
|
||||||
# self.spawn_task(self._background_loop())
|
# self.spawn_task(self._background_loop())
|
||||||
@@ -31,6 +31,15 @@ Plugin 基类 — 统一 Worker 插件初始化与清理生命周期
|
|||||||
# 关闭自定义客户端等(后台任务与数据库由基类统一处理)
|
# 关闭自定义客户端等(后台任务与数据库由基类统一处理)
|
||||||
...
|
...
|
||||||
|
|
||||||
|
# PostgreSQL 接入(可选):在插件 config.toml 配置 database 段后,
|
||||||
|
# 基类 init_database() 检测到 url 即走 Database.from_config 接入 PG::
|
||||||
|
#
|
||||||
|
# # config/workers/<name>/config.toml
|
||||||
|
# [workers.config.database]
|
||||||
|
# type = "postgresql"
|
||||||
|
# url = "postgresql+asyncpg://user:pwd@127.0.0.1:5432/mydb"
|
||||||
|
# generate_schemas = true
|
||||||
|
|
||||||
# 暴露给 app lifespan 的模块级入口(bound method,签名与旧写法一致)
|
# 暴露给 app lifespan 的模块级入口(bound method,签名与旧写法一致)
|
||||||
plugin = MyPlugin()
|
plugin = MyPlugin()
|
||||||
create_workers = plugin.create_workers
|
create_workers = plugin.create_workers
|
||||||
@@ -39,7 +48,8 @@ Plugin 基类 — 统一 Worker 插件初始化与清理生命周期
|
|||||||
框架自动处理:
|
框架自动处理:
|
||||||
- 幂等:重复 ``create_workers`` 只会初始化一次
|
- 幂等:重复 ``create_workers`` 只会初始化一次
|
||||||
- 统一日志:``logger`` 自动带 ``[type]`` 前缀
|
- 统一日志:``logger`` 自动带 ``[type]`` 前缀
|
||||||
- 数据库:``_bootstrap()`` / ``init_database()`` 统一建路径、建表、记录,``cleanup`` 自动 dispose
|
- 数据库:``_bootstrap()`` / ``init_database()`` 统一建库建表、记录,``cleanup`` 自动 dispose
|
||||||
|
(SQLite 按 ``db_name`` 建库;config 含 ``database.url`` 时优先走 PostgreSQL)
|
||||||
- global_var:``set_var()`` 写入插件自己的 ``global_var`` 模块(白名单由插件决定)
|
- global_var:``set_var()`` 写入插件自己的 ``global_var`` 模块(白名单由插件决定)
|
||||||
- 后台任务:``spawn_task()`` 跟踪,``cleanup`` 时自动取消
|
- 后台任务:``spawn_task()`` 跟踪,``cleanup`` 时自动取消
|
||||||
- 清理钩子:``register_cleanup()`` 注册,``cleanup`` 时逆序执行
|
- 清理钩子:``register_cleanup()`` 注册,``cleanup`` 时逆序执行
|
||||||
@@ -70,7 +80,7 @@ class Plugin:
|
|||||||
|
|
||||||
#: 插件类型(worker type),必须被子类覆盖
|
#: 插件类型(worker type),必须被子类覆盖
|
||||||
type: str = "default"
|
type: str = "default"
|
||||||
#: 默认数据库文件名(data_dir 下);None 表示不自动建库
|
#: 默认 SQLite 文件名(data_dir 下);config 含 database.url 时优先走 PostgreSQL;None 表示不自动建库
|
||||||
db_name: str | None = None
|
db_name: str | None = None
|
||||||
#: 首次初始化时自动调用 auto_bind_models
|
#: 首次初始化时自动调用 auto_bind_models
|
||||||
auto_bind: bool = True
|
auto_bind: bool = True
|
||||||
@@ -94,11 +104,11 @@ class Plugin:
|
|||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
async def _bootstrap(self) -> None:
|
async def _bootstrap(self) -> None:
|
||||||
"""
|
"""
|
||||||
默认资源引导:按 db_name 初始化数据库。
|
默认资源引导:按 db_name(SQLite)或 database.url(PostgreSQL)初始化数据库。
|
||||||
|
|
||||||
由基类在 on_init 之前自动调用;子类需要完全自定义建库逻辑时覆写此方法。
|
由基类在 on_init 之前自动调用;子类需要完全自定义建库逻辑时覆写此方法。
|
||||||
"""
|
"""
|
||||||
if self.db_name:
|
if self.db_name or self._database_config().get("url"):
|
||||||
await self.init_database(self.db_name)
|
await self.init_database(self.db_name)
|
||||||
|
|
||||||
async def on_init(self) -> None:
|
async def on_init(self) -> None:
|
||||||
@@ -195,15 +205,38 @@ class Plugin:
|
|||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# 辅助方法
|
# 辅助方法
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
def _database_config(self) -> dict:
|
||||||
|
"""提取运行时配置中的 database 段(不存在或非 dict 时返回空 dict)。"""
|
||||||
|
db_conf = self.config.get("database") if isinstance(self.config, dict) else None
|
||||||
|
if isinstance(db_conf, dict):
|
||||||
|
return db_conf
|
||||||
|
return {}
|
||||||
|
|
||||||
async def init_database(self, filename: str | None = None) -> Any:
|
async def init_database(self, filename: str | None = None) -> Any:
|
||||||
"""
|
"""
|
||||||
在 data_dir 下初始化 SQLite 数据库,返回 Database 实例并存入 self.db。
|
初始化数据库并存入 self.db,支持两种后端:
|
||||||
|
|
||||||
|
- PostgreSQL:config 含 ``database.url``(如插件 config.toml 的
|
||||||
|
``[workers.config.database]`` 配置 type/url)时优先走 ``Database.from_config``;
|
||||||
|
- SQLite:否则在 data_dir 下按文件名建库(现有插件零改动)。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
filename: 数据库文件名(默认取 self.db_name)
|
filename: SQLite 数据库文件名(默认取 self.db_name)
|
||||||
"""
|
"""
|
||||||
from chongming_database import Database
|
from chongming_database import Database
|
||||||
|
|
||||||
|
db_conf = self._database_config()
|
||||||
|
if db_conf.get("url"):
|
||||||
|
db = Database.from_config(db_conf)
|
||||||
|
await db.initialize(
|
||||||
|
generate_schemas=db_conf.get("generate_schemas", True)
|
||||||
|
)
|
||||||
|
self.db = db
|
||||||
|
self.logger.info(
|
||||||
|
"[%s] 数据库已初始化 (PostgreSQL): %s", self.type, db_conf["url"]
|
||||||
|
)
|
||||||
|
return db
|
||||||
|
|
||||||
filename = filename or self.db_name
|
filename = filename or self.db_name
|
||||||
if not filename:
|
if not filename:
|
||||||
raise ValueError("未指定数据库文件名(请设置 db_name 或传入 filename)")
|
raise ValueError("未指定数据库文件名(请设置 db_name 或传入 filename)")
|
||||||
|
|||||||
Reference in New Issue
Block a user