Skip to content

建议:添加 Worker 级别的数据库连接清理机制 #24

Description

@21307369

问题背景

在 webman + Swoole 环境下,当 Worker 进程退出时,ThinkPHP ORM 的 PDOConnection::__destruct() 会触发 Swoole 协程错误(详见 top-think/think-orm#853)。

虽然这是上游 think-orm 的 bug,但 webman 的 think-orm 插件可以在 DbManager 层面提供防御性清理机制。

当前行为

DbManager 使用 Context::onDestroy() 在请求结束时将连接返回连接池:

// vendor/webman/think-orm/src/DbManager.php:76-82
Context::onDestroy(function () use ($connection, $name) {
    try {
        $connection && static::$pools[$name]->put($connection);
    } catch (Throwable) {
        // ignore
    }
});

但这只处理请求级清理,不处理 Worker 级退出。

建议方案

DbManager 中添加静态方法,用于在 Worker 停止前清理所有连接:

/**
 * 关闭所有连接池(Worker 停止时调用)
 */
public static function closeAllPools(): void
{
    foreach (static::$pools as $name => $pool) {
        // 关闭 Context 中持有的连接
        $key = "think-orm.connections.$name";
        $connection = \Webman\Context::get($key);
        if ($connection) {
            try {
                $connection->close();
            } catch (\Throwable $e) {
                // ignore
            }
            \Webman\Context::set($key, null);
        }

        // 关闭池中的空闲连接
        try {
            $pool->closeConnections();
        } catch (\Throwable $e) {
            // ignore
        }
    }
}

然后在 ThinkOrm bootstrap 类中注册 onWorkerStop 回调:

// vendor/webman/think-orm/src/ThinkOrm.php
public static function start($worker): void
{
    // ... 现有初始化代码 ...

    if ($worker) {
        $worker->onWorkerStop = function () {
            DbManager::closeAllPools();
        };
    }
}

优势

  1. 集中管理:连接清理逻辑在插件内部,用户无需手动处理
  2. 防御性编程:即使上游 think-orm 未修复,也能避免错误
  3. 向后兼容:不影响现有功能,只是增加了 Worker 退出时的清理

环境信息

  • PHP: 8.4.22
  • Swoole: 6.2.1
  • webman: 2.2.1
  • webman/think-orm: 2.1.x
  • topthink/think-orm: 4.0.51

相关 Issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions