You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Deno 2中KV测试出现‘close resource’错误的原因

Deno Kv测试资源泄漏报错的原因及解决方法

问题描述

我针对Deno Kv数据库编写了数据查询测试,通过beforeAll打开数据库并添加测试数据,afterAll关闭连接并删除数据库文件。所有测试用例均通过,但describe层级测试抛出资源泄漏错误:

getUserActions => https://jsr.io/@std/testing/1.0.4/_test_suite.ts:218:10
error: Leaks detected:
  - "database" was created during the test, but not cleaned up during the test. Close the resource before the end of the test.

已确认Kv数据文件确实被删除,但测试框架仍提示资源未清理,请问错误原因是什么?

相关代码片段:

测试代码

import { expect } from "jsr:@std/expect";
import { afterAll, beforeAll, describe, it } from "jsr:@std/testing/bdd";

describe("getUserActions", () => {
  let kv: Deno.Kv;

  beforeAll(async () => {
    kv = await Deno.openKv("./test_data");
    await seedTestUserActionData();
  });

  afterAll(async () => {
    await kv.close();
    console.log("start delete");
    await deleteTestKv();
    console.log("end delete");
  });

  // 后续测试用例...
});

数据库删除函数

export async function deleteTestKv(
  dbPath: string = "./test_data"
): Promise<void> {
  await closeDb(dbPath);

  try {
    // 删除前检查文件是否存在
    await Deno.stat(dbPath);
    await Deno.remove(dbPath);
    await Deno.remove(dbPath + "-shm");
    await Deno.remove(dbPath + "-wal");
  } catch (error) {
    if (error instanceof Deno.errors.NotFound) {
      console.log(`Database file ${dbPath} not found`);
    } else {
      console.log("Remove error:", error);
    }
  }
}

async function closeDb(dbPath: string): Promise<void> {
  try {
    // 尝试关闭现有连接
    const kv = await Deno.openKv(dbPath);
    await kv.close();
  } catch (error) {
    console.log("Close error:", error);
  }
}

错误原因

问题出在deleteTestKv函数调用的closeDb方法中:

  • 你已经在afterAll里关闭了kv变量对应的数据库连接,但closeDb又重新调用Deno.openKv(dbPath)创建了一个新的数据库连接。
  • 虽然这个临时连接被立即关闭,但Deno的测试框架资源泄漏检测会捕捉到这次创建的数据库资源,判定为未清理的资源,从而抛出错误。
  • 数据库文件被删除只是磁盘文件的清理,但测试框架检测的是内存中未释放的资源句柄,这次临时创建的连接触发了检测逻辑。

解决方法

方法一:移除重复的连接关闭逻辑

既然已经在afterAll中关闭了数据库连接,无需在删除文件前重复尝试关闭。修改deleteTestKv函数:

export async function deleteTestKv(
  dbPath: string = "./test_data"
): Promise<void> {
  try {
    // 直接删除数据库相关文件
    await Deno.remove(dbPath);
    await Deno.remove(dbPath + "-shm");
    await Deno.remove(dbPath + "-wal");
  } catch (error) {
    if (error instanceof Deno.errors.NotFound) {
      console.log(`Database file ${dbPath} not found`);
    } else {
      console.log("Remove error:", error);
    }
  }
}

方法二:使用临时目录管理测试数据库

推荐使用Deno的临时目录功能,避免手动管理单个文件,同时彻底隔离测试环境:

describe("getUserActions", () => {
  let kv: Deno.Kv;
  let tempDir: string;

  beforeAll(async () => {
    // 创建临时目录
    tempDir = await Deno.makeTempDir();
    kv = await Deno.openKv(`${tempDir}/test_data`);
    await seedTestUserActionData();
  });

  afterAll(async () => {
    await kv.close();
    // 递归删除整个临时目录
    await Deno.remove(tempDir, { recursive: true });
  });

  // 测试用例...
});

这种方式无需手动处理单个数据库文件,测试结束后直接删除整个目录,既干净又能避免资源泄漏问题。

内容的提问来源于stack exchange,提问作者Clayton Ingalls

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 13:35:01