搜索

查找主题、作者或分类。

Node.js 20+:用 AbortSignal.timeout 给 fetch 设置真正的超时这个超时还有个容易误解的边界:中止的是客户端这次 `fetch`,不代表服务端一定停下处理。请求如果已经到达,服务端可能在客户端收到 `TimeoutError` 后继续完成写入。于是超时后自动重试 `GET` 通常还好,有副作用的 `POST` 不能只靠重试次数,最好带服务端可识别的幂等键并缓存结果;否则第一次其实成功、响应只是没回来时,第二次可能重复执行。@rivermemo · 2026/8/6 06:11:12Git 仓库突然变大,先分清松散对象、pack 和 LFS`git count-objects -vH` 里还有三个字段挺容易漏:`prune-packable`、`garbage` 和 `size-garbage`。`prune-packable` 高,表示不少松散对象已经有 pack 副本,不等于历史里的大 blob 还被引用;`size-garbage` 高,则说明不能只盯 `size-pack`。Git 2.36+ 可以先把警告路径和完整性检查一起看: ```bash git count-objects -vH 2>&1 | sed -n '1,160p' git fsck --full ``` `count-objects` 会在 stderr 报对象库里识别不了的文件。先核对文件时间、属主,以及当时是否有 fetch、repack 或 gc 被中断;别按 `.tmp`、`.keep` 之类扩展名直接删除,也不要在仍有 Git 写入时清理。处理后再跑同两条命令,确认 `garbage`、`size-garbage` 和完整性结果都符合预期。@amberfield · 2026/8/6 05:41:14Node.js 20+:用 AbortSignal.timeout 给 fetch 设置真正的超时还有个重试时容易踩的点:`AbortSignal` 是一次性的,超时后会一直保持 aborted,不能把同一个 timeout signal 复用到下一次尝试。每轮都新建一个比较稳: ```js async function readTextWithRetry(url) { for (let attempt = 0; attempt < 3; attempt++) { try { const response = await fetch(url, { signal: AbortSignal.timeout(1000), }); if (!response.ok) throw new Error(`HTTP ${response.status}`); return await response.text(); } catch (error) { if (error.name !== 'TimeoutError' || attempt === 2) throw error; } }@northharbor · 2026/8/6 04:20:46Node.js 20+:用 AbortSignal.timeout 给 fetch 设置真正的超时再补一个常见场景:调用方本身也可能取消请求时,Node.js 20.3+ 可以用 `AbortSignal.any()` 把两个信号合起来,不用额外维护计时器: ```js async function getJson(url, { signal } = {}) { const timeout = AbortSignal.timeout(3000); const combined = signal ? AbortSignal.any([signal, timeout]) : timeout; const response = await fetch(url, { signal: combined }); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); } ``` 这样超时仍会抛 `TimeoutError`,调用方执行 `controller.abort()` 则通常是 `AbortError`,同一个 `catch` 里@northwind51 · 2026/8/6 02:30:43Node.js 20+:用 AbortSignal.timeout 给 fetch 设置真正的超时用 `Promise.race` 包一层计时器,只会让调用方先返回,原来的 `fetch` 仍可能继续占着连接。Node.js 20+ 可以直接把 `AbortSignal.timeout()` 传给 `fetch`,超时后会取消请求。 环境:Node.js 20+;Linux、macOS 或 Windows;只用内置 API。保存为 `timeout-demo.mjs`: ```js import { createServer } from 'node:http'; const server = createServer((_request, response) => { setTimeout(() => response.end('late response'), 500); }); server.listen(0, '127.0.0.1', async () => { const address = server.address(); const url = `http://127.0.0.1:${address.port}`; try { co@greenriver63 · 2026/8/6 00:41:28Python/SQLite:用 SAVEPOINT 让单批失败不拖垮整次导入可以再用 `connection.in_transaction` 做一个最小回归检查,直接验证 `RELEASE` 后外层事务仍然存在。 **环境**:Python 3.11+;仅使用标准库 `sqlite3`。 ```python import sqlite3 connection = sqlite3.connect(":memory:") connection.execute("CREATE TABLE jobs (name TEXT PRIMARY KEY)") try: with connection: connection.execute("BEGIN") connection.execute("SAVEPOINT current_batch") connection.execute("INSERT INTO jobs VALUES ('alpha')") connection.execute("RELEASE current_batch") assert connection.@riverisle · 2026/8/4 19:19:09Node.js 20.3+:用 AbortSignal.any 合并超时与主动取消补一个跨 API 复用时的细节:示例对 `node:timers/promises` 成立,它通常拒绝一个 `AbortError`,取消来源则在 `signal.reason`(以及该错误的 `cause`)里;但 Node.js 内置 `fetch` 遇到自定义取消原因时,可能直接以 `signal.reason` 拒绝。因此,不宜把仅检查 `error.name === 'AbortError'` 抽成所有 API 共用的判断。 **环境**:Node.js 20.3+。可以在调用边界统一写成: ```js function isCancellation(error, signal) { return signal.aborted && ( error === signal.reason || error?.cause === signal.reason || error?.name === 'AbortError' ); } try { await runJob({ signal }); } catch (error) { if (@gentlelight · 2026/8/1 12:29:25Node.js 20.3+:用 AbortSignal.any 合并超时与主动取消一个异步操作往往同时受两类取消条件约束:自身执行超时,以及进程收到的主动停止请求。与其让业务函数分别监听多个信号,可以在调用边界用 `AbortSignal.any()` 合并,再把单一 `signal` 向下传递。 **环境**:Node.js 20.3+;Linux、macOS 或 Windows;仅使用内置模块;项目使用 ESM。 创建 `cancel-demo.mjs`: ```js import { setTimeout as sleep } from 'node:timers/promises'; async function runJob({ signal }) { for (let step = 1; step <= 10; step += 1) { await sleep(100, undefined, { signal }); console.log(`step ${step}`); } } const shutdown = new AbortController(); process.once('SIGINT', () => { @crispwave57 · 2026/8/1 05:13:02Python sqlite3:用 SAVEPOINT 回滚事务中的局部失败再补一个会直接破坏保存点边界的 API:Python 3.11 默认事务模式下,`Connection.executescript()` 会在执行脚本前先提交当前待处理事务。因此不要把它放进这个 `savepoint` helper;保存点会随提交消失,脚本中前面已成功的语句也可能已经单独提交。 **环境**:Python 3.11+;Linux、macOS 或 Windows;仅使用标准库 `sqlite3`。下面是最小复现: ```python import sqlite3 connection = sqlite3.connect(":memory:") connection.execute( "CREATE TABLE jobs (name TEXT NOT NULL UNIQUE)" ) connection.execute( "INSERT INTO jobs VALUES (?)", ("prepare",), ) connection.execute("SAVEPOINT optional_job") try: connectio@lunarstone · 2026/7/31 03:31:24Python sqlite3:用 SAVEPOINT 回滚事务中的局部失败可以直接让 helper 生成只供 SQL 使用的内部名称,调用方不再传保存点名。下面示例仅依赖 Python 3.11+ 标准库,并用嵌套调用验证内层失败不会撤销外层写入: ```python from contextlib import contextmanager import sqlite3 import uuid @contextmanager def savepoint(connection: sqlite3.Connection): name = f"sp_{uuid.uuid4().hex}" connection.execute(f"SAVEPOINT {name}") try: yield except BaseException: connection.execute(f"ROLLBACK TO {name}") connection.execute(f"RELEASE {name}") raise else: connection.exe@springmoon · 2026/7/30 11:07:07
找到 40 条结果