From 9b6664666321c8c96f87efad09be7d7783c81411 Mon Sep 17 00:00:00 2001 From: Stephen Brennan Date: Fri, 13 Mar 2026 09:59:03 -0700 Subject: [PATCH] fix(GeneratorQueryHandler): replay fetchMore requests made while active Do not drop fetchMore calls that arrive while a batch is still active. Queue one pending fetch request and replay it after activeChanged(false). This handles reentrant fetchMore calls triggered during results insertion and prevents multi-chunk generators from stalling after the first chunk. Fixes: albertlauncher/albert-plugin-python#12 --- src/query/generatorqueryhandler.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/query/generatorqueryhandler.cpp b/src/query/generatorqueryhandler.cpp index 2a98d249..b1bdada2 100644 --- a/src/query/generatorqueryhandler.cpp +++ b/src/query/generatorqueryhandler.cpp @@ -19,6 +19,7 @@ class GeneratorQueryHandlerExecution final : public QueryExecution ItemGenerator generator; // mutexed optional iterator; // mutexed bool active; + bool fetch_more_pending; // items(), begin and operator++ are potentially long blocking operations. // it had to be mutexed because canFetchMore may check the iterator in the main thread. // awaiting the lock however blocks the main thread potentially long. @@ -35,6 +36,7 @@ class GeneratorQueryHandlerExecution final : public QueryExecution , handler(h) , iterator(nullopt) , active(true) + , fetch_more_pending(false) , at_end(false) { connect(&watcher, &QFutureWatcher::finished, @@ -78,7 +80,16 @@ class GeneratorQueryHandlerExecution final : public QueryExecution void fetchMore() override { - if (!isActive() && canFetchMore()) + if (!canFetchMore()) + return; + + if (isActive()) + { + // Model updates can synchronously trigger fetchMore while this execution is still active. + // Queue the request and replay it right after this batch finished. + fetch_more_pending = true; + } + else { emit activeChanged(active = true); watcher.setFuture(QtConcurrent::run([this] -> vector> @@ -114,6 +125,13 @@ class GeneratorQueryHandlerExecution final : public QueryExecution } emit activeChanged(active = false); + + if (fetch_more_pending) + { + fetch_more_pending = false; + if (!isActive()) + fetchMore(); + } } };