Skip to content

Commit 13ac919

Browse files
committed
fix(shared): prevent infinite loop in ThrottledFetchingService
The pagination loop in `ThrottledFetchingService` was vulnerable to an infinite loop if the API returned `hasMore: true` with a `null` cursor. This change makes the loop condition more robust by ensuring it terminates if the cursor becomes null, thus preventing the service from repeatedly re-fetching the first page. Additionally, a large block of dead code and confusing comments related to a non-functional batching strategy has been removed to improve code clarity and maintainability.
1 parent bc0a2f0 commit 13ac919

File tree

1 file changed

+4
-46
lines changed

1 file changed

+4
-46
lines changed

lib/shared/services/throttled_fetching_service.dart

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -50,52 +50,10 @@ class ThrottledFetchingService {
5050
cursor = initialResponse.cursor;
5151
hasMore = initialResponse.hasMore;
5252

53-
// If there are more pages, proceed with batched fetching.
54-
if (hasMore) {
55-
final pageFutures = <Future<PaginatedResponse<T>>>[];
56-
do {
57-
pageFutures.add(
58-
repository.readAll(
59-
sort: sort,
60-
pagination: PaginationOptions(cursor: cursor),
61-
filter: {'status': ContentStatus.active.name},
62-
),
63-
);
64-
// This is a simplification. A real implementation would need to know
65-
// the next cursor before creating the future. The logic below handles
66-
// this correctly by fetching sequentially but processing in batches.
67-
} while (false); // Placeholder for a more complex pagination discovery
68-
69-
// Correct implementation: Sequentially discover cursors, but
70-
// fetch pages in parallel batches.
71-
while (hasMore) {
72-
final batchFutures = <Future<PaginatedResponse<T>>>[];
73-
for (var i = 0; i < batchSize && hasMore; i++) {
74-
final future = repository.readAll(
75-
sort: sort,
76-
pagination: PaginationOptions(cursor: cursor),
77-
filter: {'status': ContentStatus.active.name},
78-
);
79-
80-
// This is tricky because we need the result of the PREVIOUS future
81-
// to get the cursor for the NEXT one.
82-
// A truly parallel approach requires knowing page numbers or total
83-
// count. Given the cursor-based API, a sequential-discovery,
84-
// batched-execution is the best we can do. Let's simplify to a
85-
// more robust sequential fetch, as true parallelism isn't possible
86-
// without more API info. The primary goal is to centralize this
87-
// robust sequential logic.
88-
89-
// Reverting to a robust sequential loop, which is the correct pattern
90-
// for cursor-based pagination when total pages are unknown.
91-
// The "throttling" is inherent in its sequential nature.
92-
break; // Exit the batch loop, the logic below is better.
93-
}
94-
}
95-
}
96-
97-
// Correct, robust sequential fetching loop.
98-
while (hasMore) {
53+
// Sequentially fetch all remaining pages. The loop is resilient to a
54+
// misbehaving API by also checking if the cursor is null, which would
55+
// otherwise cause an infinite loop by re-fetching the first page.
56+
while (hasMore && cursor != null) {
9957
final response = await repository.readAll(
10058
sort: sort,
10159
pagination: PaginationOptions(cursor: cursor),

0 commit comments

Comments
 (0)