status bar
git clone https://git.lucas.co/cce-status-interface.git
fix: back off reconnects to a status topic the compositor does not know
The listener retried every second flat. A compositor that does not
recognize a subscription drops it on sight without a word, so an
unrecognized topic became a permanent once-a-second reconnect from every
module process — nine of them, plus a log line each.
That is not hypothetical: `backdrop` lands in cce-fx and here as separate
commits to separate repos, and cce-fx only restarts at login, so a bar
installed first spends the rest of the session talking to a compositor
that has never heard of the topic.
Doubling to a 30s cap, reset by any line actually received — a topic that
works is unaffected, including one whose connection drops mid-session.
Co-Authored-By: Claude Opus 5 <[email protected]>
src/listeners.rs | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/src/listeners.rs b/src/listeners.rs
index b39e463..483c0af 100644
--- a/src/listeners.rs
+++ b/src/listeners.rs
@@ -12,6 +12,14 @@ use crate::CustomEvent;
pub(crate) async fn spawn_status_listener(sub: String, sender: calloop::channel::Sender<CustomEvent>) {
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::UnixStream;
+ // Retry delay, doubling while connections keep ending without ever
+ // delivering a line and reset the moment one does. A compositor that
+ // does not know this topic drops the subscription on sight, so the flat
+ // 1s retry turned an unrecognized topic into a permanent once-a-second
+ // reconnect from every module process — which is exactly what a bar
+ // running ahead of its compositor does with `backdrop` (the two halves
+ // deploy separately, and cce-fx only restarts at login).
+ let mut retry_s = 1u64;
loop {
let socket_path = match std::env::var("WAYLAND_DISPLAY") {
Ok(display) => {
@@ -37,6 +45,8 @@ pub(crate) async fn spawn_status_listener(sub: String, sender: calloop::channel:
let mut reader = BufReader::new(stream);
let mut line = String::new();
while reader.read_line(&mut line).await.unwrap_or(0) > 0 {
+ // Anything at all means the topic is understood.
+ retry_s = 1;
let val = line.trim().to_string();
log::debug!("[status-listener] received '{}' update: '{}'", sub, val);
if !val.is_empty() {
@@ -60,7 +70,8 @@ pub(crate) async fn spawn_status_listener(sub: String, sender: calloop::channel:
}
}
}
- tokio::time::sleep(std::time::Duration::from_secs(1)).await;
+ tokio::time::sleep(std::time::Duration::from_secs(retry_s)).await;
+ retry_s = (retry_s * 2).min(30);
}
}