Skip to content

fix(pulls): skip the recreate when the pull didn't produce a new image - #154

Merged
nzxl101 merged 1 commit into
Notifiarr:developfrom
genomez:verify-pull-before-recreate
Oct 21, 2026
Merged

nzxl101 merged 1 commit into
Notifiarr:developfrom
genomez:verify-pull-before-recreate

Conversation

@genomez

@genomez genomez commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Problem

In crons/pulls.php, an auto update calls $docker->pullImage($image) and goes straight on to stop, remove and recreate the container. pullImage() returns only the command output (shell_exec), and the result isn't checked, so a failed pull still recreates the container from the image it was already running. The pull data is then marked as updated and an "updated" notification is queued with the registry digest as the new version.

Because the registry digest check (regctl) keeps succeeding while the layer download fails, this repeats on every scheduled run. I hit it with lscr.io/linuxserver/* images: since late September the registry has been answering layer downloads with toomanyrequests: retry-after: ..., allowed: 44000/minute, while manifest lookups still work. Containers on a 3-hour schedule (tautulli, sonarr, radarr) were restarted 7–8 times a day for weeks, all from the same old image, and the logs and notifications reported every run as a successful update.

Change

After the pull, inspect the image again and only continue if its ID differs from the image the container is running. The container's image comes from the fresh $inspect taken just before the pull, not the cached state, which can be behind. If the IDs match, or either one can't be read, the container is left as it is. An error is logged with the pull output (plus the inspect output if the image couldn't be inspected), and the switch is exited, so nothing is marked as updated and no "updated" notification is sent. The next scheduled run tries again.

This only stops the recreate when there's no different local image to use. It doesn't try to prove the pull succeeded or that the image is the newest one. Comparing image IDs rather than digests means a tag that moves between the regctl check and the pull still updates normally, and a second container on the same image in the same run still gets recreated.

The skipped container is added to $notify['failed'], the same as the existing "Invalid hash length" branch. Neither notification branch currently sends failed entries, so this doesn't add a failure notification by itself.

Related, not changed here

The manual update in ajax/containers.php (around lines 587–599) stops and removes the container, removes the old image, and only then pulls and creates. If that pull fails after the old image was removed, the create has no image to use and the container is gone. It may be what #103 describes. It probably needs the same kind of check, done before the destructive steps; I've kept it out of this PR so the change stays small.

Testing

  • php -l on the changed file inside the ghcr.io/notifiarr/dockwatch:develop container: no syntax errors.
  • Checked on a running install that the container's cached inspect[0].Image, docker inspect <container> .Image, and the image's .Id from docker inspect <image> --format="{{json . }}" | jq -s are all the same sha256: value, so the comparison works as written.

The auto update ignored the pullImage() result, so a failed pull still
stopped, removed and recreated the container from the image it was
already running, and recorded the update as done. Compare the
container's image ID with the local image after the pull, and leave the
container alone if they match or either one can't be read.
@nzxl101
nzxl101 merged commit 59be6ea into Notifiarr:develop Oct 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants