A Dead PID Held My Lock for 2 Hours: One Missing Line, Zero Output, exit 0 Every Time

2026年8月19日2 次浏览来源:Dev.to阅读原文

For 30 straight days as a college student earning ¥100k/month, I posted to Instagram by hand, and then I burned out and stopped.

Today the same job runs on a Claude Code autonomous environment, I touch nothing, and it holds up ¥1.2M/month in revenue.

Except for the two hours when it quietly stopped: three consecutive launchd runs, zero pieces of content generated, every single time, and not one alert.

The cause was a process that had already been killed, holding a lock file nobody would take away from it.

Why this setup works From "doing the work" to "building the environment" The problem with updating social media by hand is that it burns willpower.

No matter how motivated you are, sleep, health, and mood all fluctuate.

During the period when I was laid off and my income went to zero, I had no mental slack for posting at all.

The autonomous environment I spent six months building with Claude Code runs regardless of my emotional state. launchd calls a script, the script generates content with (MAX plan quota; paid APIs are off-limits), the output is queued for auto-posting, and it goes out to Instagram every day at 19:30.

As long as this machinery keeps working, ¥1.2M/month in sales holds up without me lifting a finger.

The mental model I want to hand you A lot of people think "automation = writing scripts," and that's only half right.

A script is correct at the moment you write it.

Given time, external dependencies break, processes die for reasons you didn't anticipate, and lock files turn into debris that blocks every future run.

An autonomous environment that actually works is one that assumes breakage and carries a layer that repairs it.

The lock story here is a textbook case. is a script launched on a schedule by launchd that auto-generates Instagram feature articles.

A single run takes a long time (up to three calls, plus image generation, adding up to tens of minutes), so it has a lock mechanism to prevent the next run from overlapping with one that hasn't finished.

Mishandling that lock file () meant that pid 94799 held the lock without releasing it even though it had already been killed, every subsequent run was skipped with "lock held — 終了", and generation stopped for about two hours.

Why "2 hours" The lock check has a constant (2 hours) (line 57 of gen_feature.py).

It's a safety valve: "even if the lock exists, steal it if the mtime is older than 2 hours." But the original implementation only looked at mtime, without checking whether the pid was alive.

Even with a killed pid sitting in , as long as the mtime was within 2 hours it kept deciding "still running" and skipping. launchd could fire a third and a fourth time — all of them "lock held — 終了" until the two hours elapsed.

The worst possible state — automation that is "running" but produces nothing — continued silently for two hours.

What the "build the environment" side requires With manual work, you notice: "huh, nothing got generated today," and you run it by hand.

But building an autonomous environment means taking on responsibility for it continuing to work correctly while nobody is watching.

A pid liveness check looks like belt-and-suspenders, but in practice "the script gets killed and the lock stays behind" happens routinely.

If you kill it instantly with SIGKILL, the in the block never runs at all.

Same thing when you stop it by hand during development.

If you're scheduling a long-running script with launchd, a pid liveness check is mandatory.

The overall flow System architecture The queue targets a standing inventory of 3 items (gen_feature.py line 60, ; line 61, ).

With 3 in stock, posting doesn't break even if generation fails for one or two days in a row.

What the lock is responsible for When you manage a script with a long single run (up to seconds × 3 calls, plus image downloads) via scheduled launchd starts, these problems appear: The next instance starts before the previous run has finished and double-generates the same brand Concurrent writes to

分享
Baike.dev

baike.dev helps you discover great languages, frameworks, databases, DevOps and cloud-native tools.

Quick links

About

Contribute

Found a great developer tool? Share it with the community.

Submit a tool
© 2026 baike.dev Developer EncyclopediaUpdated daily · Discover great developer tools