Skip to content

Commit 9243d37

Browse files
committed
fix: switch to apply the fix only on startup
1 parent ceabf3b commit 9243d37

2 files changed

Lines changed: 43 additions & 25 deletions

File tree

crates/node/src/indexer.rs

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -425,40 +425,58 @@ const INTERVAL: Duration = Duration::from_millis(500);
425425
const REQUIRED_STABLE_POLLS: u32 = 4;
426426

427427
impl IndexerClient {
428+
/// Polls sync status, yielding `(syncing, head_height)`, or `None` on a
429+
/// failed request.
430+
async fn sync_info(&self) -> Option<(bool, BlockHeight)> {
431+
let status_request = Status {
432+
is_health_check: false,
433+
detailed: false,
434+
};
435+
let Ok(Ok(status)) = self
436+
.client
437+
.send_async(
438+
near_o11y::span_wrapped_msg::SpanWrappedMessageExt::span_wrap(status_request),
439+
)
440+
.await
441+
else {
442+
return None;
443+
};
444+
Some((
445+
status.sync_info.syncing,
446+
status.sync_info.latest_block_height,
447+
))
448+
}
449+
450+
/// Returns once neard clears its `syncing` flag.
428451
async fn wait_for_full_sync(&self) {
429-
let mut progress = SyncProgress::default();
430452
loop {
431453
tokio::time::sleep(INTERVAL).await;
454+
if matches!(self.sync_info().await, Some((false, _))) {
455+
return;
456+
}
457+
}
458+
}
432459

433-
let status_request = Status {
434-
is_health_check: false,
435-
detailed: false,
436-
};
437-
let status_response = self
438-
.client
439-
.send_async(
440-
near_o11y::span_wrapped_msg::SpanWrappedMessageExt::span_wrap(status_request),
441-
)
442-
.await;
443-
444-
let Ok(Ok(status)) = status_response else {
445-
continue;
446-
};
447-
448-
if progress.observe(
449-
status.sync_info.syncing,
450-
status.sync_info.latest_block_height,
451-
) {
460+
/// Returns once the node is confirmed following the chain tip. Used only at
461+
/// startup: neard can report `syncing == false` while still behind (fresh
462+
/// genesis, after downtime, or while disconnected from all peers), so we
463+
/// confirm via [`SyncProgress`] before binding the streamer's cursor.
464+
async fn ensure_head_follows_tip(&self) {
465+
let mut progress = SyncProgress::default();
466+
loop {
467+
tokio::time::sleep(INTERVAL).await;
468+
if let Some((syncing, head_height)) = self.sync_info().await
469+
&& progress.observe(syncing, head_height)
470+
{
452471
return;
453472
}
454473
}
455474
}
456475
}
457476

458-
/// Detects catch-up from head progress alone: a freshly state-syncing node
459-
/// briefly reports `syncing == false` at the genesis head, and returning then
460-
/// pins the streamer's `LatestSynced` cursor at that stale head. So we require a
461-
/// run of non-syncing polls over which the head actually advances.
477+
/// Reports the node as caught up only after a run of non-syncing polls over
478+
/// which the head actually advances, filtering out the transient
479+
/// `syncing == false` a behind node reports before its head starts moving.
462480
#[derive(Default)]
463481
struct SyncProgress {
464482
run_start_head: Option<BlockHeight>,

crates/node/src/indexer/real.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ pub fn spawn_real_indexer(
147147
// at genesis, below the block tail it can never reach. Raced against
148148
// shutdown so a SIGTERM during state sync still tears down cleanly.
149149
if !await_sync_or_shutdown(
150-
indexer_state.client.wait_for_full_sync(),
150+
indexer_state.client.ensure_head_follows_tip(),
151151
&shutdown_token,
152152
)
153153
.await

0 commit comments

Comments
 (0)