Skip to content

Commit 6e8a88a

Browse files
ADFA-4900: serialized install pipeline (maps proot -> ZIM -> Books) in SetupProgress
Replace the one-shot drain with an ordered, serialized pipeline driven from the finishing-setup screen: run maps (proot/runrole) exclusively first, then ZIM, then Books, auto-continuing between stages here instead of dropping to Home/Library, and auto-advance only once every stage has finished. A race guard treats maps as busy from hand-off until the module queue reports DONE. A failed maps runrole now counts as a failure (Finish), not a false success. Keeps proot/REST mutual exclusion.
1 parent 9a195cd commit 6e8a88a

1 file changed

Lines changed: 51 additions & 13 deletions

File tree

‎controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java‎

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import androidx.core.content.ContextCompat;
3434

3535
import org.iiab.controller.R;
36+
import org.iiab.controller.install.presentation.ModuleQueueRepository;
37+
import org.iiab.controller.install.presentation.ModuleQueueState;
3638
import org.iiab.controller.util.AppExecutors;
3739

3840
public class SetupProgressActivity extends AppCompatActivity {
@@ -56,6 +58,7 @@ public class SetupProgressActivity extends AppCompatActivity {
5658
private boolean redirectScheduled = false;
5759
private boolean showingDetail = false;
5860
private boolean probing = false;
61+
private boolean mapsLaunched = false; // ADFA-4900: maps (proot) stage has been handed to the queue
5962
private int readyPolls = 0; // ADFA-4874: failed readiness polls so far (slow-start message)
6063

6164
private int px(int dp) { return Math.round(dp * getResources().getDisplayMetrics().density); }
@@ -115,35 +118,66 @@ public void onBackPressed() {
115118
else super.onBackPressed();
116119
}
117120

118-
// ---- readiness gate: wait for the REST engine, then drain the wishlists ----
121+
// ---- readiness gate + serialized install pipeline (ADFA-4900) ----
122+
// Once the REST engine is up, run the install tasks as an ORDERED, serialized pipeline:
123+
// maps (proot / runrole) exclusively first, then ZIM, then Books, auto-continuing between
124+
// stages HERE (never dropping to Home/Library mid-sequence). Keep polling until every stage
125+
// has been started and finished; render() then auto-advances (or shows Finish on failure).
119126
private final Runnable readyPoll = new Runnable() {
120127
@Override public void run() {
121-
if (probing || servicesReady) return;
128+
if (probing) return;
122129
probing = true;
123130
AppExecutors.get().io().execute(() -> {
124131
final boolean ready = RestReadiness.apiReady();
125132
main.post(() -> {
126133
probing = false;
127134
if (isFinishing()) return;
128-
if (ready) {
129-
servicesReady = true;
130-
if (!drained) {
131-
if (BooksProvisioner.hasPending(SetupProgressActivity.this)) BooksProvisioner.drain(SetupProgressActivity.this);
132-
if (ZimProvisioner.hasPending(SetupProgressActivity.this)) ZimProvisioner.drain(SetupProgressActivity.this);
133-
if (MapsProvisioner.hasPending(SetupProgressActivity.this)) MapsProvisioner.drain(SetupProgressActivity.this); // ADFA-4900
134-
drained = true;
135-
}
136-
render();
137-
} else {
135+
if (!ready) {
138136
readyPolls++; // ADFA-4874: feeds the slow-start message in render()
139137
render();
140138
main.postDelayed(readyPoll, READY_POLL_MS);
139+
return;
141140
}
141+
servicesReady = true;
142+
boolean moreWork = orchestrateStep();
143+
render();
144+
if (moreWork) main.postDelayed(readyPoll, READY_POLL_MS);
142145
});
143146
});
144147
}
145148
};
146149

150+
/**
151+
* ADFA-4900: one step of the serialized install pipeline. Starts the next stage only when the
152+
* previous one has finished; proot (maps) runs exclusively before any REST download, so Ansible's
153+
* background forks never overlap a live REST job. Returns true while work remains (keep polling),
154+
* false once every stage has been started and is complete.
155+
*/
156+
private boolean orchestrateStep() {
157+
ModuleQueueState mq = ModuleQueueRepository.get().current();
158+
boolean queueRunning = ModuleQueueRepository.get().isRunning();
159+
160+
// Stage 1 — maps (proot), exclusive of all REST work.
161+
if (MapsProvisioner.hasPending(this)) {
162+
if (!queueRunning) { MapsProvisioner.drain(this); mapsLaunched = true; }
163+
return true;
164+
}
165+
if (queueRunning) return true; // maps runrole in flight
166+
if (mapsLaunched && mq.phase != ModuleQueueState.Phase.DONE) return true; // launched; await DONE (race guard)
167+
168+
// Stage 2 — ZIM (REST), only after maps is done.
169+
if (ZimDownloadService.hasSession() && !ZimDownloadService.isComplete()) return true;
170+
if (ZimProvisioner.hasPending(this)) { ZimProvisioner.drain(this); return true; }
171+
172+
// Stage 3 — Books (REST), only after ZIM is done.
173+
if (BooksDownloadService.hasSession() && !BooksDownloadService.isComplete()) return true;
174+
if (BooksProvisioner.hasPending(this)) { BooksProvisioner.drain(this); return true; }
175+
176+
// Every stage has been started and is complete.
177+
drained = true;
178+
return false;
179+
}
180+
147181
// ---- render ----
148182
private void render() {
149183
if (sections == null || showingDetail) return;
@@ -165,8 +199,12 @@ private void render() {
165199
boolean allComplete = drained
166200
&& (!ZimDownloadService.hasSession() || ZimDownloadService.isComplete())
167201
&& (!BooksDownloadService.hasSession() || BooksDownloadService.isComplete());
202+
// ADFA-4900: a failed maps runrole must count as a failure too (Finish, not a false success).
203+
ModuleQueueState mq = ModuleQueueRepository.get().current();
204+
boolean mapsFailed = mq.phase == ModuleQueueState.Phase.DONE && mq.failedModules.contains("maps");
168205
int failedTotal = failedCount(ZimDownloadService.hasSession() ? ZimDownloadService.status() : null, ZimDownloadService.FAILED)
169-
+ failedCount(BooksDownloadService.hasSession() ? BooksDownloadService.status() : null, BooksDownloadService.FAILED);
206+
+ failedCount(BooksDownloadService.hasSession() ? BooksDownloadService.status() : null, BooksDownloadService.FAILED)
207+
+ (mapsFailed ? 1 : 0);
170208

171209
// Status dot + line. While waiting, a long-stuck engine shows a softer "taking longer"
172210
// message instead of "Starting services" so it doesn't look frozen (ADFA-4874).

0 commit comments

Comments
 (0)