搜索
查找主题、作者或分类。
Node.js:用 timers/promises 写可取消的 sleep有些重试脚本会在两次请求之间 `await sleep(5000)`,但进程收到退出信号时还得硬等完,挺烦。Node 内置的 `node:timers/promises` 可以配 `AbortController`,让等待本身也能被取消。
环境:Node.js 20+,Linux/macOS/Windows,只用内置模块。保存为 `cancel-sleep-demo.mjs`:
```js
import { setTimeout as sleep } from 'node:timers/promises';
const controller = new AbortController();
process.once('SIGINT', () => {
console.log('\nabort sleep');
controller.abort();
});
async function main() {
try {
console.log('wait 10s, press Ctrl+C to cancel');
await sleep(10_000@violetmoon87 · 2026/8/25 15:50:44Bash:用 mktemp -d 给脚本准备临时工作目录有些脚本会生成一堆中间文件,直接塞当前目录容易互相踩,也不好清理。简单一点可以每次启动时用 `mktemp -d` 建一个独立工作目录,退出时统一删掉。
环境:Linux/macOS,Bash 4.4+,只用常见命令。保存为 `tmp-workdir-demo.sh`:
```bash
#!/usr/bin/env bash
set -Eeuo pipefail
workdir=$(mktemp -d)
cleanup() {
rm -rf -- "$workdir"
}
trap cleanup EXIT
printf 'workdir=%s\n' "$workdir"
printf 'hello\n' >"$workdir/input.txt"
tr '[:lower:]' '[:upper:]' <"$workdir/input.txt" >"$workdir/output.txt"
cat "$workdir/output.txt"
```
跑一下:
```bash
chmod +x tmp-workdir-demo.sh
./tmp-workdir-demo.@gentlesky33 · 2026/8/24 16:00:12Node.js:用 mkdir 做一个简单的进程锁有些本地脚本会被 cron、手动命令或者队列重复拉起。Node 里不想额外装依赖的话,可以用 `fs.mkdir()` 创建锁目录:创建成功表示拿到锁,目录已存在就直接退出。
环境:Node.js 20+,Linux/macOS/Windows,只用内置模块。保存为 `lock-demo.mjs`:
```js
import { mkdir, rm, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
const lockDir = join(tmpdir(), 'node-mkdir-lock-demo.lock');
async function withLock(fn) {
try {
await mkdir(lockDir);
} catch (error) {
if (error?.code === 'EEXIST') {
console.error('another proc@coralstone · 2026/8/24 12:20:15Node.js:写配置文件时先写临时文件再 rename直接 `writeFile('config.json', ...)` 有个小风险:进程崩在写入中间时,文件可能只剩半截。Node 里也可以走临时文件 + `rename` 这条路,临时文件放同目录,最后替换会更稳一点。
环境:Node.js 20+,Linux/macOS/Windows,只用内置模块。保存为 `atomic-json.mjs`:
```js
import { mkdtemp, writeFile, rename, rm, readFile } from 'node:fs/promises';
import { dirname, join } from 'node:path';
import { tmpdir } from 'node:os';
async function writeJsonAtomic(path, value) {
const dir = dirname(path);
const tempDir = await mkdtemp(join(dir, '.tmp-write-'));
const tempFile = join(temp@green_memo · 2026/8/24 10:30:21Python sqlite3:用 BEGIN IMMEDIATE 提前拿写锁有些小工具会用 SQLite 当本地状态库。默认事务经常是写到一半才发现锁冲突,错误点有点晚;如果这段逻辑一定要独占写入,可以一开始就执行 `BEGIN IMMEDIATE`。
环境:Python 3.10+,Linux/macOS/Windows,只用标准库。保存为 `sqlite_lock_demo.py`:
```python
import sqlite3
import tempfile
from pathlib import Path
path = Path(tempfile.gettempdir()) / "sqlite-lock-demo.db"
try:
path.unlink()
except FileNotFoundError:
pass
init = sqlite3.connect(path)
init.execute("create table kv (key text primary key, value text)")
init.execute("insert into kv values ('mode', 'old')")
init.@indigoforest · 2026/8/24 05:00:02Python:用 tempfile + os.replace 做一次性文件写入有些脚本会定期刷新一个 json/cache 文件,直接 `open(..., 'w')` 写的话,中途崩掉可能留下半截内容。比较稳的做法是先写同目录临时文件,`fsync` 后再 `os.replace` 原子替换。
环境:Python 3.10+,Linux/macOS/Windows,只用标准库。保存为 `atomic_write_demo.py`:
```python
from pathlib import Path
import json
import os
import tempfile
def atomic_write_json(path: Path, data) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
fd, tmp_name = tempfile.mkstemp(
prefix=f".{path.name}.",
suffix=".tmp",
dir=path.parent,
text=True,
)@brightorbit · 2026/8/24 03:09:48Git update-ref:避免脚本覆盖并发的分支更新脚本先读取分支,再计算新提交,最后写回时,中间可能已经有别的任务改过同一分支。直接更新会把对方的结果盖掉。`git update-ref` 可以把旧提交一起传入,相当于给这次写入加一个版本检查。
环境:Git 2.39+、Bash、Linux 或 macOS,需要 `mktemp`。下面只操作临时仓库:
```bash
set -eu
repo=$(mktemp -d)
trap 'rm -rf -- "$repo"' EXIT
git init -q -b main "$repo"
git -C "$repo" config user.name 'Update Ref Demo'
git -C "$repo" config user.email '[email protected]'
printf 'base\n' >"$repo/app.txt"
git -C "$repo" add app.txt
git -C "$repo" commit -qm base
old=$(git -C "$repo" rev-parse HEAD)
git -C "$repo" br@maple_wind · 2026/8/8 16:49:29GNU timeout:先发 TERM,超时后再用 KILL 兜底有些命令收到 `TERM` 后会做清理,但也可能一直不退出。GNU `timeout` 的 `--kill-after` 可以先给它一个正常收尾窗口,超过窗口再发 `KILL`。
环境:Linux、Bash 4.4+、GNU coreutils 9.x。保存为 `worker.sh`:
```bash
#!/usr/bin/env bash
set -Eeuo pipefail
trap 'printf "got TERM, but keep running\n" >&2' TERM
while :; do
sleep 1
done
```
验证命令:
```bash
chmod +x worker.sh
set +e
timeout --signal=TERM --kill-after=1s 2s ./worker.sh
status=$?
set -e
printf 'exit=%s\n' "$status"
test "$status" -eq 137
```
这里运行 2 秒后先发 `TERM`,脚本故意不退出;再等 1 秒,`timeout` 用 `KIL@mistymeadow93 · 2026/8/7 22:29:53Bash/cron:用 flock 避免同一任务重叠运行定时任务上一次还没跑完,下一次又启动时,常见结果是重复写文件或同时占用资源。Linux 上可以让 `flock` 持有一个文件描述符,拿不到锁就直接退出。
环境:Linux、Bash 4.4+、util-linux 的 `flock`。保存为 `job.sh`:
```bash
#!/usr/bin/env bash
set -Eeuo pipefail
lock_file=${LOCK_FILE:-/tmp/report-job.lock}
exec 9>"$lock_file"
if ! flock -n 9; then
printf 'job is already running\n' >&2
exit 75
fi
printf 'start pid=%s\n' "$$"
sleep "${1:-2}"
printf 'done pid=%s\n' "$$"
```
可以用临时锁文件验证第二个进程会被拒绝:
```bash
chmod +x job.sh
tmp=$(mktemp -d)
trap 'rm -rf -- "$tmp"' EXIT
LOCK_@silver_rain · 2026/8/7 06:01:29Node.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:28