https://bugs.kde.org/show_bug.cgi?id=524077

            Bug ID: 524077
           Summary: SnapBackend never signals update-check completion with
                    zero upgradeable snaps, leaving Updates page stuck
                    forever
    Classification: Applications
           Product: Discover
      Version First 6.7.4
       Reported In:
          Platform: Other
                OS: Linux
            Status: REPORTED
          Severity: normal
          Priority: NOR
         Component: Snap Backend
          Assignee: [email protected]
          Reporter: [email protected]
                CC: [email protected]
  Target Milestone: ---

## Summary

`SnapBackend::checkForUpdates()` never signals completion of its update check
when there are zero upgradeable snaps — which is the common, everyday case.
This leaves Discover's Updates page permanently stuck on "Fetching updates" for
any user with the Snap backend enabled, independent of bug 521682 (see "See
Also" — that bug's regression is on `master`'s `EmitWhenChanged` refactor and
doesn't exist in the 6.7.x stable branch; this is a different, older mechanism
that predates that refactor).

## Root cause

`libdiscover/backends/SnapBackend/SnapBackend.cpp`, `checkForUpdates()`:

```cpp
void SnapBackend::checkForUpdates()
{
    if (m_updatesFetcher) {
        qWarning() << "Already fetching updates";
        return;
    }

    m_updatesFetcher = new
StoredResultsStream({populate(m_client.findRefreshable())});
    connect(m_updatesFetcher, &StoredResultsStream::finishedResources, this,
[this](const QVector<StreamResult> &resources) {
        for (SnapResource *res : std::as_const(m_resources)) {
            bool contained = kContains(resources, [res](const StreamResult &in)
{
                return in.resource == res;
            });
            if (contained) {
                res->setState(AbstractResource::Upgradeable);
                res->updateSizes();
            }
        }
    });
}
```

If `resources` (from `m_client.findRefreshable()`) is empty, the loop never
calls `res->setState(AbstractResource::Upgradeable)` for anything. That
state-change call is the *only* thing that would trigger
`StandardBackendUpdater::resourcesChanged()`, which starts the timer that
eventually calls `refreshUpdateable()`. `SnapBackend` also never emits
`contentsChanged`/`invalidated` on its own after this callback.

Since `refreshUpdateable()` is the only place that calls `setSettingUp(false)`,
and `setSettingUp(false)` is the only place `m_hasBeenPopulated` gets set
`true`, when there are zero upgradeable snaps `refreshUpdateable()` for the
Snap updater is **never called even once**. `m_hasBeenPopulated` stays `false`
for the life of the process, so `isFetchingUpdates()`
(`fetchingUpdatesProgress() != 100 || m_settingUp || !m_hasBeenPopulated`) is
permanently `true`, and since `ResourcesUpdatesModel::isFetching()` is `true`
if *any* backend updater reports fetching, the whole Updates page hangs forever
— even though every other backend (PackageKit, Flatpak, KNS, fwupd) completes
normally.

Confirmed via a live diagnostic build
(`ResourcesUpdatesModel::refreshFetching()` instrumented to log every updater's
state every 3s): every other backend transitions to `isFetchingUpdates=false`
within seconds; `SnapBackend` alone stays `true` indefinitely, with
`isProgressing=false` and `fetchingUpdatesProgress=100` — the exact signature
of `!m_hasBeenPopulated` never clearing.

`snap refresh --list` on the affected machine reports "All snaps up to date" —
i.e. this reproduces precisely because there's nothing to update, which is
presumably the *normal* steady state for most installations.

## Fix

```diff
--- a/libdiscover/backends/SnapBackend/SnapBackend.cpp
+++ b/libdiscover/backends/SnapBackend/SnapBackend.cpp
@@ checkForUpdates()
             if (contained) {
                 res->setState(AbstractResource::Upgradeable);
                 res->updateSizes();
             }
         }
+        // If nothing is upgradeable, no resource's state changes, so nothing
+        // downstream ever notices this check completed:
StandardBackendUpdater
+        // only reacts to a resource transitioning to/from Upgradeable, or to
+        // contentsChanged/invalidated. Without an explicit signal here,
+        // refreshUpdateable() is never called even once when there are no
+        // pending snap updates, so m_hasBeenPopulated never becomes true and
+        // Discover's Updates page is stuck on "Fetching updates" forever.
+        Q_EMIT contentsChanged();
     });
 }
```

Also added a defensive 15s timeout around the `QSnapdRequest::runSync()` call
in `populateJobsWithFilter()` (unrelated to the above, but `m_threadPool` has
only one thread, so if `runSync()` ever genuinely hangs — observed but not
fully root-caused — it would permanently block every subsequent snap search
too; the timeout gives up and lets the rest of Discover proceed rather than
wedging forever).

## Verification

Built locally as a patched RPM (Fedora 44,
`plasma-discover-6.7.4-9.fc44.local`) and confirmed live: unpatched build stuck
indefinitely on "Fetching updates" with zero snap updates pending; patched
build correctly clears and shows "Up to date" within seconds.

## See Also

Bug 521682 — a different bug with an overlapping symptom (both leave Discover
stuck on "Fetching updates"), but a distinct mechanism specific to an
unreleased `master` refactor. Given how many duplicate reports of 521682
mention Snap specifically, it's plausible some of those reporters are actually
hitting *this* bug rather than 521682's regression — worth checking whether
their Snap backend also has zero pending updates.

Full diff and this write-up: happy to attach the patch here too if useful, same
as I did on 521682.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to