A systemctl --user service kept starting, then stopping ~12s later, every 5 minutes — flooding a notification channel each time. But crontab -l was empty and systemctl --user list-timers had no matching timer. So who was cycling it?
Usually it's not a scheduled job. A user-level service's lifetime is tied to the per-user systemd manager (user@<uid>.service), and without linger that manager only runs while the user has at least one login session:
- Someone logs in (even a 2-second SSH/rsync) → the manager starts → it reaches
default.target → your WantedBy=default.target service gets pulled up.
- ~10s after the last session exits → the manager tears down → your service stops with it.
- Next login repeats the whole dance.
So the service's "restart cadence" is really the login cadence. The system journal makes it obvious:
journalctl --since "-15min" | grep -iE "Accepted publickey|New session|Removed session|Reached target exit.target"
In my case the culprit was another box running */5 * * * * rsync … host:/backup/… — a short SSH connection every 5 minutes that lit up the entire user manager and dropped it again. The moment the host had a persistent session (a lingering tmux), the symptom vanished — which is the strongest tell: it only happens when nobody is logged in.
The fix is to detach the manager from login so it stays resident:
sudo loginctl enable-linger <user>
# verify
loginctl show-user <user> --property=Linger # Linger=yes
With linger on, the manager starts at boot and no longer stops when sessions end, so the service becomes a real background daemon. For a user-level service that must run while no one is logged in, enable --now is not enough — enable-linger is the missing prerequisite.
一个 systemctl --user 服务莫名每 5 分钟启动、十几秒后又停,反复刷屏。crontab -l 空的,systemctl --user list-timers 也没有对应 timer——那到底是谁在动它?
答案往往不是定时任务,而是 user 级服务的生命周期绑在 per-user systemd manager(user@<uid>.service)上。没开 linger 时,这个 manager 只在该用户"至少有一个登录会话"时存活:
- 有人(哪怕一条 2 秒的 SSH/rsync)登录 → manager 启动 → 到达
default.target → 你那个 WantedBy=default.target 的服务被拉起。
- 会话退出约 10 秒后 → manager 拆除 → 服务跟着停。
- 下次登录再来一遍。
所以服务的"重启节奏"其实是登录节奏。用系统 journal 一看就露馅:
journalctl --since "-15min" | grep -iE "Accepted publickey|New session|Removed session|Reached target exit.target"
我这次的真凶是另一台机器上的 */5 * * * * rsync … host:/backup/…——每 5 分钟一条短 SSH 连接,把整个 user manager 点起来又放下。一旦本机有了常驻会话(比如一个挂着的 tmux),现象立刻消失——这就是最强的判定线索:只在"没人登录"时发生。
治本是让 manager 脱离登录、常驻:
sudo loginctl enable-linger <user>
# 确认
loginctl show-user <user> --property=Linger # Linger=yes
开 linger 后 manager 开机即起、不随会话退出而停,服务真正变成后台常驻。要让一个 user 级服务在无人登录时也长跑,enable --now 是不够的,enable-linger 才是前提。
Need to restart an ECS service to pick up a changed SSM Parameter Store value (env vars/secrets are resolved when a task starts, so any fresh task picks up the new value). Two ways to force a restart look equivalent but aren't.
aws ecs update-service --force-new-deployment runs a normal rolling deployment, governed by the service's deploymentConfiguration:
aws ecs update-service --cluster my-cluster --service my-service --force-new-deployment
desiredCount never changes. If maximumPercent is above 100 (e.g. 200%), ECS starts the new task first, waits for it to pass the ALB health check, then drains and stops the old one — new and old run side by side for a moment, so there's effectively zero downtime.
Scaling desiredCount to 0 and back to 1 is a hard stop-then-start: every running task is killed first, the target group is empty until the new task comes up and passes health checks, and anything hitting the service in that window fails. It also completely bypasses the rolling-deployment logic — there's no overlap to make it graceful.
Same end state (new task, new config), different path to get there. Two things to check before relying on force-new-deployment for a "safe" restart: maximumPercent needs to allow >100%, or you get the same stop-then-start behavior with the failure mode you were trying to avoid; and deploymentCircuitBreaker — if it's disabled, a broken new task version just cycles and retries forever without rolling back, while the old task quietly keeps serving traffic, so the deployment looks non-disruptive but never actually finishes.
You're migrating a GitHub Pages site from your personal account to an org. You verify the custom domain for the org, the org's Pages settings show it green "Verified", and then binding it to the repo fails — over and over:
You must verify your domain app.example.com before being able to use it.
Every route is blocked. The API returns 400:
gh api -X PUT repos/<org>/<repo>/pages -f cname=app.example.com
# => "Invalid cname" / "You must verify your domain..."
The repo's Settings → Pages custom-domain box throws the same error. Switching to legacy "Deploy from a branch" with a CNAME file already in the branch? The cname stays null. You can't even unpublish to reset — DELETE /repos/<org>/<repo>/pages comes back 422 Deactivating GitHub Pages for this repository is not allowed.
The verified-domains list says green. The cname check says unverified. Both are telling the truth.
The domain is also verified under your personal account. It's a leftover from when the site lived there and pointed at <user>.github.io. That personal verified claim silently takes precedence and blocks the org repo from binding the cname. GitHub never says "this domain is claimed elsewhere" — just the generic must-verify error, which sends you down a rabbit hole of re-verifying on the org side that never helps.
Fix: remove the verified domain from the personal account (user Settings → Pages → verified domains → remove), then bind the cname on the org repo. It goes through immediately.
A tell that this is your problem: the custom domain used to resolve to <user>.github.io before the migration.
One related trap: apex-domain verification does not auto-cover subdomains for cname binding, despite the docs implying it does. app.example.com needs its own _gh-<org>-o.app.example.com TXT even when example.com is already verified — otherwise the same must-verify wall.
Moving a vagrant-libvirt VM between Linux hosts looks like a two-step
(vagrant package then vagrant up on the other side), and that's exactly
what I tried. Both steps died in the same place: fog-libvirt's stream
upload/download of a large qcow2 from/to libvirt's storage pool reset
mid-flight (Cannot recv data: Connection reset by peer, hung at 0%).
The streaming bug is in fog-libvirt's vol upload/download. The fix is to
bypass vagrant-libvirt's vol-upload/vol-download entirely: flatten
the overlay qcow2 against its backing file, drop the result in a libvirt
storage pool by hand, then virsh define + virsh start. Treat
vagrant-libvirt as the boot-time scaffolding only; the running VM is plain
libvirt after that.
1. Make the box self-contained
vagrant package exists to bake the VM's disk + metadata into a .box
file. With a libvirt provider the disk is usually a qcow2 with a backing
file (qemu-img info ... | grep "backing file"), and vol-download only
streams the overlay — you'd ship an incomplete box. Skip it and flatten
manually:
…more