BatchStore.store held the range's row (SELECT … FOR UPDATE) for the whole batch transaction (15-20 s on the HDD), so the prefetcher's spooled_chunks updates and the heartbeats of that range waited on it (0.5 s on average): the prefetcher's NNTP connections sat idle. Now an advisory lock per range serializes its batches, and the resume point is checked again in the final, conditional update. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>