RPKI: ask a cache without data yet again soon
A validator that is still running its first validation answers a query with No Data Available (error code 2). That ended the session, and the next attempt came after the retry interval: 600 seconds when the cache had not yet said otherwise, which it cannot have before it has data. For those ten minutes after a validator started, nothing was validated. No Data Available is now asked again after 30 seconds, or after retry_seconds if that is shorter, and logged as information rather than as a warning. Other failures wait as before, after trying the next cache if there is one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9362ba9e34
commit
52593bb2c2
2 files changed
+54
-7
No files matched your search
@@ -54,6 +54,12 @@ const MAX_RECORDS: usize = 8_000_000;
|
|||||||
/// How long to wait before trying the next cache after one has failed.
|
/// How long to wait before trying the next cache after one has failed.
|
||||||
const NEXT_CACHE_DELAY: Duration = Duration::from_secs(1);
|
const NEXT_CACHE_DELAY: Duration = Duration::from_secs(1);
|
||||||
|
|
||||||
|
/// How long to wait before asking a cache again that said it has no data
|
||||||
|
/// yet, rather than the retry interval: it is up and validating, which
|
||||||
|
/// takes minutes after it starts, and the retry interval is ten unless it
|
||||||
|
/// has said otherwise, which it has not had the chance to.
|
||||||
|
const NO_DATA_RETRY: Duration = Duration::from_secs(30);
|
||||||
|
|
||||||
/// How long a cache that is being left is given to take the reason.
|
/// How long a cache that is being left is given to take the reason.
|
||||||
const ERROR_REPORT_TIMEOUT: Duration = Duration::from_secs(1);
|
const ERROR_REPORT_TIMEOUT: Duration = Duration::from_secs(1);
|
||||||
|
|
||||||
@@ -419,23 +425,29 @@ impl Client {
|
|||||||
self.protocol_version = version;
|
self.protocol_version = version;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
let no_data = matches!(
|
||||||
|
ended,
|
||||||
|
SessionError::Reported {
|
||||||
|
code: error_code::NO_DATA_AVAILABLE,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if no_data {
|
||||||
|
info!(%cache, "RPKI cache has no data yet; asking again soon");
|
||||||
|
} else {
|
||||||
warn!(%cache, err = %ended, "RPKI cache session ended");
|
warn!(%cache, err = %ended, "RPKI cache session ended");
|
||||||
|
}
|
||||||
self.status(|status| {
|
self.status(|status| {
|
||||||
status.state = CacheState::Connecting;
|
status.state = CacheState::Connecting;
|
||||||
status.last_error = Some(ended.to_string());
|
status.last_error = Some(ended.to_string());
|
||||||
});
|
});
|
||||||
|
|
||||||
// The next cache at once; when all have been tried, a rest.
|
|
||||||
attempt += 1;
|
attempt += 1;
|
||||||
// The next cache, or this one when it is back, may speak a
|
// The next cache, or this one when it is back, may speak a
|
||||||
// newer version.
|
// newer version.
|
||||||
self.protocol_version = VERSION_2;
|
self.protocol_version = VERSION_2;
|
||||||
let wait = if attempt.is_multiple_of(self.config.caches.len()) {
|
let all_tried = attempt.is_multiple_of(self.config.caches.len());
|
||||||
self.retry()
|
self.wait(rest(all_tried, no_data, self.retry())).await;
|
||||||
} else {
|
|
||||||
NEXT_CACHE_DELAY
|
|
||||||
};
|
|
||||||
self.wait(wait).await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -889,3 +901,33 @@ enum Answer {
|
|||||||
/// With a request to ask for everything instead.
|
/// With a request to ask for everything instead.
|
||||||
Reset,
|
Reset,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How long to rest after a session ended: the next cache at once; when
|
||||||
|
/// all have been tried, the retry interval, or less if the last one is
|
||||||
|
/// only still validating.
|
||||||
|
fn rest(all_tried: bool, no_data: bool, retry: Duration) -> Duration {
|
||||||
|
match (all_tried, no_data) {
|
||||||
|
(false, _) => NEXT_CACHE_DELAY,
|
||||||
|
(true, true) => NO_DATA_RETRY.min(retry),
|
||||||
|
(true, false) => retry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// A cache that is still validating after it started is asked again
|
||||||
|
/// in half a minute, not the ten the retry interval is by default.
|
||||||
|
#[test]
|
||||||
|
fn a_cache_without_data_yet_is_asked_again_soon() {
|
||||||
|
let ten_minutes = Duration::from_secs(600);
|
||||||
|
assert_eq!(rest(true, true, ten_minutes), NO_DATA_RETRY);
|
||||||
|
assert_eq!(rest(true, false, ten_minutes), ten_minutes);
|
||||||
|
// Never later than the retry interval says.
|
||||||
|
let short = Duration::from_secs(5);
|
||||||
|
assert_eq!(rest(true, true, short), short);
|
||||||
|
// Another cache first, whatever this one said.
|
||||||
|
assert_eq!(rest(false, true, ten_minutes), NEXT_CACHE_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,6 +64,11 @@ rpki {
|
|||||||
When the data expires, Ferrix discards it, and no route is considered
|
When the data expires, Ferrix discards it, and no route is considered
|
||||||
invalid until new data is received.
|
invalid until new data is received.
|
||||||
|
|
||||||
|
A validator that has just started reports that it has no data available
|
||||||
|
until its first validation run is complete, which takes several minutes.
|
||||||
|
Ferrix then asks again after 30 seconds, or after `retry_seconds` if that
|
||||||
|
is shorter, rather than after the retry interval.
|
||||||
|
|
||||||
### Running a Validator
|
### Running a Validator
|
||||||
|
|
||||||
The following command starts Routinator with an RTR server on port 3323:
|
The following command starts Routinator with an RTR server on port 3323:
|
||||||
|
|||||||
Reference in new issue
Block a user