aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2023-01-11 22:35:56 +0100
committerAlex Auvolat <alex@adnab.me>2023-01-11 22:35:56 +0100
commit5f946d485c62feca79e907a2d071a291dcc8c7bf (patch)
treee7ffae5e839e215bcf49ebd90f4954695f02c057
parent7c8dcd7aa757273e908a8ef77e701244c6e6d184 (diff)
downloadD53-5f946d485c62feca79e907a2d071a291dcc8c7bf.tar.gz
D53-5f946d485c62feca79e907a2d071a291dcc8c7bf.zip
Retry DNS updates when they fail
-rw-r--r--src/dns_config.rs4
-rw-r--r--src/dns_updater.rs27
2 files changed, 25 insertions, 6 deletions
diff --git a/src/dns_config.rs b/src/dns_config.rs
index 77153ea..1356fc7 100644
--- a/src/dns_config.rs
+++ b/src/dns_config.rs
@@ -24,7 +24,7 @@ pub struct DnsConfig {
pub entries: HashMap<DnsEntryKey, DnsEntryValue>,
}
-#[derive(Debug, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct DnsEntryKey {
pub dns_path: String,
pub record_type: DnsRecordType,
@@ -35,7 +35,7 @@ pub struct DnsEntryValue {
pub targets: HashSet<String>,
}
-#[derive(Debug, Hash, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
#[allow(clippy::upper_case_acronyms)]
pub enum DnsRecordType {
A,
diff --git a/src/dns_updater.rs b/src/dns_updater.rs
index 98708ce..de9a874 100644
--- a/src/dns_updater.rs
+++ b/src/dns_updater.rs
@@ -1,3 +1,4 @@
+use std::collections::HashSet;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::sync::Arc;
use std::time::Duration;
@@ -10,6 +11,8 @@ use tracing::*;
use crate::dns_config::*;
use crate::DomainProvider;
+const RETRY_DELAY: Duration = Duration::from_secs(600); // 10 minutes
+
pub async fn dns_updater_task(
mut rx_dns_config: watch::Receiver<Arc<DnsConfig>>,
providers: Vec<DomainProvider>,
@@ -30,6 +33,8 @@ pub async fn dns_updater_task(
info!("DNS updater starting");
let mut config = Arc::new(DnsConfig::new());
+ let mut failures = HashSet::new();
+
while !*must_exit.borrow() {
select!(
c = rx_dns_config.changed() => {
@@ -37,19 +42,31 @@ pub async fn dns_updater_task(
break;
}
}
+ _ = tokio::time::sleep(RETRY_DELAY) => {
+ if failures.is_empty() {
+ continue;
+ }
+ }
_ = must_exit.changed() => continue,
);
// Always lag 15 seconds behind actual updates,
// to avoid sending too many at once and hitting rate limits
- // TODO: retry regularly rate limits are hit
tokio::time::sleep(Duration::from_secs(15)).await;
let new_config: Arc<DnsConfig> = rx_dns_config.borrow_and_update().clone();
+ let mut new_failures = HashSet::new();
for (key, value) in new_config.entries.iter() {
- // Skip entries that haven't changed
- if config.entries.get(key) == Some(value) {
+ if failures.contains(key) {
+ info!(
+ record = key.to_string(),
+ target = value.to_string(),
+ "retrying after failure"
+ );
+ } else if config.entries.get(key) == Some(value) {
+ // Skip entries that haven't changed, and that were
+ // successfully updated on the previous iteration
continue;
}
@@ -75,8 +92,9 @@ pub async fn dns_updater_task(
record = key.to_string(),
target = value.to_string(),
error = e.to_string(),
- "unable to update record"
+ "unable to update record, will retry later"
);
+ new_failures.insert(key.clone());
}
} else {
error!(
@@ -87,6 +105,7 @@ pub async fn dns_updater_task(
}
config = new_config;
+ failures = new_failures;
}
}