Skip to content

ADFA-4898: surface a failed proot module install and let the user retry it - #490

Open
luisguzman-adfa wants to merge 8 commits into
mainfrom
feat/ADFA-4898-runrole-failure-retry
Open

ADFA-4898: surface a failed proot module install and let the user retry it#490
luisguzman-adfa wants to merge 8 commits into
mainfrom
feat/ADFA-4898-runrole-failure-retry

Conversation

@luisguzman-adfa

Copy link
Copy Markdown
Collaborator

What

A proot module install (a runrole that runs with the server stopped) that fails is
now surfaced honestly and can be retried per-module — no auto-retry. Before, a failed
runrole could read as a clean success and there was no way to re-run just the module
that failed.

Changes

  • Failure signal: ModuleQueueState.didFail(key) / hasFailures() on the DONE
    terminal — one predicate every surface reads (hub pill, module detail, live install
    card, finishing header) so they can't drift. InstallService treats a non-zero or
    [ERROR] runrole exit (incl. exit 137 / PPK kill) as a failure, records it, and posts
    a dismissible "Couldn't install" notification.
  • Finishing screen (SetupProgressActivity): a batch that ends with a failed module
    keeps the amber "installing" header instead of flipping to green "Adding your content"
    (which read a failure as success). No new copy.
  • Where retry lives: the "Couldn't install" pill on the module hub is the entry point
    (no per-row button); the module detail and the live install card offer Retry. On the
    detail it is the primary of a Retry/Back pair; on the live card it reuses the host's
    existing Run-in-background/Back button template (Retry primary + Back secondary),
    recomputed live so it shows on failure and clears when the module returns to RUNNING.
  • One retry action: ModuleRetry.fire(view, key) — busy-gated, single-module — is the
    only start path, called by every surface. It goes through ModuleProvisioner.startBatch,
    the single "save the ordered batch + start the service" method now shared with the
    wishlist drain, so a retry always records the ModuleBatch the install index renders
    (a raw start left the index empty). Retrying from the detail lands on the install index,
    where the re-fired batch shows its rows, progress and log.

Not in scope

No auto-retry (only a user action starts one), no movement-based stall detection, and no
cancel/confirm — follow-ups on this ticket.

Verification

Device: forced a runrole failure (network cut during calibre-web / kolibri). Confirmed the
amber finishing header, the "Couldn't install" pill, Retry on the detail and the live card,
the failure notification, and that Retry re-runs only the failed module and re-converges
(kolibri re-run repeatedly from ~34% with no corruption — the ansible role's idempotency
holds).

…ry it
A module runrole failure was already detected (added to failedModules) but folded
into a success-shaped DONE — no surface, no retry — so a failed install looked
like a silent success and could not be re-run.
- ModuleQueueState: hasFailures() / didFail(module) expose the failure on the DONE
terminal (no new phase, so every existing "queue finished" consumer is unchanged;
only the surfaces that care read it).
- Module management (ModuleHubFragment): a module that failed in the last batch shows
a "Couldn't install" pill and a Retry button (no schedule checkbox in that state);
refreshes live via the module-queue observer.
- Notification: a batch that ends with failures leaves a dismissible "install failed"
notification (distinct id from the foreground one) that opens Module management.
- InstallService.retryModules(ctx, modules): re-fires ACTION_START_MODULES for the
failed module(s) — user action only, no auto-retry; for maps it re-attaches this
session's retained layer selection (EXTRA_MAPS_*). runrole --reinstall re-converges
when the module is healthy upstream.
Reuses existing strings (k2go_mod_phase_failed, k2go_home_retry) — no new translations.
Off-device / non-module flows unchanged.
Follow-ups (same ticket, separate slices — each needs its own device round): movement-
based stall detection, cancel with confirmation + immediate retry, and a "failed" state
on the finishing-setup screen.
…er amber on a failed module
Retry lived on the hub row and the finishing screen flipped to a green
"Adding your content" when a module runrole had failed — reading a failed
batch as success. Move recovery to where the user looks for it, keep the
failure honest, no new copy.
- SetupProgressActivity: a module batch that reaches its terminal with a
failed runrole (server already up) keeps the same amber "installing" header
instead of the green "Adding your content"; the failure and Retry surface
per-module below, not in this batch-level header.
- ModuleDetailFragment: a failed module (per-module didFail(key); installed
outranks it) shows a persistent "Couldn't install" chip and turns the two
actions into Retry (re-fires just this module, user-confirmed, busy-gated,
then bounces to the live hub) + Back — the slot-reuse this switch already
does for Recover.
- ModuleHubFragment: drop the per-row Retry button; the "Couldn't install"
pill is the entry into the detail, so a batch where one of many modules
failed never sprays Retry across the list.
- ModuleInstallFragment: route the progress line's failed check through the
shared ModuleQueueState.didFail(key) instead of a hand-rolled
failedModules.contains, so every surface shares one predicate.
… action
The failed-state Retry was on the module detail but not on the live install
card (the animation + log screen) — exactly where the user watches the runrole
fail. Add it there and factor the action so it isn't duplicated.
- ModuleRetry: one busy-gated, single-module retry action, called by both the
live install card and the module detail so the two can't drift.
- ModuleInstallFragment: a filled Retry under the status line, shown only while
this module reads "failed" and self-hiding on re-fire (the card observes the
queue live). Clears the terminal latch on RUNNING so the status resumes
following the log after a retry.
- ModuleDetailFragment: route its Retry through the shared ModuleRetry action.
…index has its rows
retryModules fired ACTION_START_MODULES raw and never saved the ModuleBatch, so a
retry brought up the install index empty ("Finishing setup" with no rows) while the
queue ran in the background. The wishlist drain got this right; the retry path
duplicated the "fire the service" half and dropped the "save the batch" half.
- ModuleProvisioner.startBatch: one entry point that saves the ordered batch and
hands the keys to InstallService. drain() and retryModules() both go through it,
so a batch can't start without the rows the index needs.
- InstallService.retryModules: delegates to startBatch (maps keeps its retained
per-layer selection as extras) instead of building the intent itself.
…g the Run-in-background/Back template
The Retry button sat mid-card, disconnected from the "Back" the host pins at the
bottom. Move it into the host's existing two-button detail bar so Retry and Back
are one primary/secondary pair, and drop the bespoke in-card button.
- SetupProgressActivity.configureDetailBar(): reconfigures the one existing detail
template — filled primary (k2go_sp_back) over outlined secondary
(k2go_sp_detail_finish). A failed module shows Retry (primary) + Back (secondary);
every other detail keeps Back (primary) + Run in background (secondary, LIVE only).
Recomputed each render, so a Retry that returns the module to RUNNING restores the
normal bar. Retry uses the shared ModuleRetry action and stays on the live card.
- ModuleInstallFragment / fragment_k2go_module_install.xml: remove the in-card Retry
button (now host-owned); keep the terminal-latch reset so the status resumes
following the log after a retry.
…ot the hub
Retrying from a module detail (reached from Module management) called onBackPressed,
dropping the user on the "Add modules" hub, which during an install only shows
"Adding content" with no route to the progress. Route to the install index instead —
the same destination a normal install reaches via openModuleIndex — so the re-fired
batch shows its rows, progress and log. The start action (ModuleRetry) is unchanged;
only the detail's post-retry navigation moves.
Sign up for freeto 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.

1 participant

@luisguzman-adfa