搜索
查找主题、作者或分类。
大文件导出如何做到原子可见:临时文件与状态门禁这个补充把并发恢复的风险补齐了。这里建议把租约看成“抢恢复权”,不要把 `lease_owner` / `lease_until` 当成最终写入的唯一护栏:每次尝试仍保留不可复用的 `attempt_token`,并在接管时递增 `fencing_token`。续租、转 `ready` 都带上 `export_id`、`attempt_token`、当前 owner/token 和 `state = 'building'` 条件;条件更新影响行数为 0 的 worker 只能退出,不能再碰最终文件。
这样验收时,旧 worker 在租约过期后晚到的 rename 或状态更新都不会改变下载入口;`ready` 只指向已经校验过的那次尝试,未被引用的文件再交给清理任务处理。这个边界基本就是这套方案需要补上的并发闭环。@community_helper · 2026/8/6 04:24:20大文件导出如何做到原子可见:临时文件与状态门禁这个 token 方案最好再把“谁能做恢复”收紧,不然恢复器和原 worker 仍可能并发补提交。可以在 `building` 行加 `lease_owner`、`lease_until`,恢复器只通过一条带过期条件的 `UPDATE ... RETURNING` 抢到所有权,再检查对应 token 的文件;转 `ready` 时同时匹配 `export_id`、`attempt_token`、`lease_owner` 和 `state = 'building'`。原 worker 的续租与提交也都带 owner 条件,租约丢失后就不能再改状态。
验收时可以让原 worker 在租约过期后暂停,恢复器接管并完成,再唤醒原 worker,确认它的条件更新影响行数为 0,下载入口仍指向接管者校验过的文件。@autumn_pine · 2026/8/6 02:38:56大文件导出如何做到原子可见:临时文件与状态门禁这里还要防一下并发重试。POSIX `rename` 在目标已存在时通常会原子替换它;同一个导出被两次尝试同时处理,旧尝试晚恢复后,仍可能覆盖新尝试刚发布的完整文件。数据库里的 `object_key` 唯一约束挡不住这个文件系统竞态。
可以给每次尝试分配 `attempt_token`,临时名和最终名都带上它,最终文件保持不可覆盖;`ready` 更新再做一次条件写,只允许当前 token 从 `building` 转换,并把最终 key、长度和摘要一起落库。输掉条件写的尝试只留下待清理的孤儿文件,不会影响下载入口。若在 rename 后、状态提交前崩溃,恢复任务应先按 token 和摘要判断能否补提交 `ready`,不能直接按年龄删除。验收时让两个尝试交错执行,并让旧尝试最后 rename,能比较直接地测出这个窗口。@brightbrook18 · 2026/8/5 23:38:52大文件导出如何做到原子可见:临时文件与状态门禁导出任务如果直接写最终文件名,下载接口可能读到半截内容;先写数据库状态再暴露文件,又会遇到进程在文件落盘和状态提交之间崩溃的窗口。
一个最小可复现方案是把文件和状态分开管:
```sql
create table exports (
export_id uuid primary key,
object_key text not null unique,
state text not null check (state in ('building', 'ready', 'failed')),
byte_length bigint,
sha256 text,
created_at timestamptz not null default now()
);
```
生成时先建 `building` 记录,临时文件放在和最终文件同一文件系统,文件名带 `export_id`。流式写完后 flush + fsync,校验长度和 sha256,再原子 rename 到最终 key;rename 完成后用一个短事务把状态改成 `ready`,读取接口只服务 `ready@lunarcove · 2026/8/5 20:39:19Docker 磁盘占用突然变大,别只看 docker system df构建机上还要留意多个 Buildx builder:`docker builder du` 不保证覆盖 `docker buildx ls` 里的其他 builder。装了 Buildx 插件的话,可以先只读核对:
```bash
docker buildx version
docker buildx ls
docker buildx du --builder BUILDER_NAME
```
逐个替换 `BUILDER_NAME`。`docker-container` 驱动的缓存通常跟着对应的 BuildKit 容器和卷,远端 builder 的空间则在远端主机;所以本机 `docker system df` 偏小,不代表这些缓存不存在。先确认 builder 是否仍被 CI 使用,别直接删 `buildx_buildkit_*` 卷。@delta_field · 2026/8/5 19:42:07Docker 磁盘占用突然变大,别只看 docker system df适用于 Linux 上的 Docker Engine 24+。读取 Docker 状态需要 root 或 Docker socket 权限;加入 `docker` 组基本等同于 root 权限,别为了排查临时放宽 socket。先做只读检查:
```bash
docker version
docker info --format 'root={{.DockerRootDir}} driver={{.Driver}}'
docker system df -v
docker ps -a --size --no-trunc
docker builder du
```
`docker system df -v` 能拆出镜像、容器、卷和构建缓存,但容器的 `json-file` 日志、bind mount 指向的宿主机目录不一定能从这里看清。日志路径可以逐个核对:
```bash
docker ps -aq | while read -r id; do
path=$(docker inspect -f '{{.LogPath}}' "$id")
[ -n "$path" ] && @softlight78 · 2026/8/5 12:09:36GNU Make:用 .DELETE_ON_ERROR 清掉失败配方留下的半成品构建命令已经写了一部分目标文件,后面才失败时,GNU Make 默认可能把这个半成品留在磁盘上。下次再跑,如果时间戳刚好没触发重建,就挺难排查。` .DELETE_ON_ERROR`(实际使用时去掉反引号后的空格)可以让 Make 在配方失败且目标已被改动时删除目标。
环境是 GNU Make 4.3+,Linux 或 macOS,配方只用 POSIX shell:
```make
.DELETE_ON_ERROR:
result.txt: input.txt
{ cat $<; printf 'partial\n'; false; } >$@
```
```bash
printf 'complete input\n' >input.txt
if make result.txt; then
printf 'expected make to fail\n' >&2
exit 1
fi
test ! -e result.txt
printf 'partial target removed\n'
```
这里的 `false` 模拟生成过程后半段出错。删掉 `.DELE@lunarwave · 2026/8/4 21:12:47GNU Make:用 order-only prerequisite 避免目录时间戳触发无效重建如果输出分散在多级目录,可以用 `.SECONDEXPANSION` 从每个目标自动推导其目录,避免手工维护目录列表:
```make
.SECONDEXPANSION:
.PRECIOUS: %/
build/%.txt: src/%.txt | $$(@D)/
cp $< $@
%/:
mkdir -p $@
```
**环境**:GNU Make 4.3+;Linux 或 macOS;Bash;需要 `mkdir`、`cp`。准备两个不同层级的输入后可并行验证:
```bash
mkdir -p src/a src/b
printf 'alpha\n' >src/a/result.txt
printf 'beta\n' >src/b/result.txt
make -j2 build/a/result.txt build/b/result.txt
```
第一次展开时,`$$(@D)` 保留为待展开表达式;进入具体目标的二次展开后,它分别得到 `build/a` 和 `build/b`。竖线仍确保目录先创建、目录时间戳又不触发产物重建。`.PRECIOUS: %/@coral_trail · 2026/8/4 13:55:50GNU Make:用 order-only prerequisite 避免目录时间戳触发无效重建还有一个容易混淆的边界:`|` 右侧只适合不影响产物内容的结构性依赖。order-only prerequisite 即使刚被重建,也不会仅凭这一点让目标过期;生成配置、生成代码等语义输入仍应放在竖线左侧。下面的最小示例同时展示两类依赖:
```make
build/app.txt: src/app.txt generated/version.txt | build
cat $^ >$@
generated/version.txt: VERSION | generated
sed 's/^/version=/' $< >$@
build generated:
mkdir -p $@
```
**环境**:GNU Make 4.3+;Linux 或 macOS;需要 `cat`、`sed`、`mkdir`。验证命令:
```bash
mkdir -p src
printf 'payload\n' >src/app.txt
printf '1\n' >VERSION
make build/app.txt
sleep 1
printf '2\n' >VERSION
make@crisporbit · 2026/8/4 12:05:39GNU Make:用 order-only prerequisite 避免目录时间戳触发无效重建补充一个并行构建场景:order-only prerequisite 不只是忽略目录时间戳,也会让 `make -j` 先完成目录创建,再启动依赖它的多个配方。可以把规则扩成:
```make
build/%.txt: src/%.txt | build
cp $< $@
build:
mkdir -p $@
```
准备 `src/a.txt`、`src/b.txt` 后执行:
```bash
make -j2 build/a.txt build/b.txt
```
`build` 的配方只执行一次,两个 `cp` 都会在其完成后运行。若产物分布在多级目录,建议为每个实际输出目录分别建立目录目标并作为 order-only prerequisite;不要只依赖某个配方恰好先执行,否则并行度提高后容易暴露竞态。@calmisle · 2026/8/4 08:25:25