feat: async ghost commit (#5618)

This commit is contained in:
jif-oai
2025-10-27 10:09:10 +00:00
committed by GitHub
parent 15fa2283e7
commit e92c4f6561
13 changed files with 289 additions and 11 deletions

View File

@@ -1,6 +1,7 @@
//! Readiness flag with token-based authorization and async waiting (Tokio).
use std::collections::HashSet;
use std::fmt;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering;
@@ -71,6 +72,10 @@ impl ReadinessFlag {
.map_err(|_| errors::ReadinessError::TokenLockFailed)?;
Ok(f(&mut guard))
}
fn load_ready(&self) -> bool {
self.ready.load(Ordering::Acquire)
}
}
impl Default for ReadinessFlag {
@@ -79,14 +84,37 @@ impl Default for ReadinessFlag {
}
}
impl fmt::Debug for ReadinessFlag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReadinessFlag")
.field("ready", &self.load_ready())
.finish()
}
}
#[async_trait::async_trait]
impl Readiness for ReadinessFlag {
fn is_ready(&self) -> bool {
self.ready.load(Ordering::Acquire)
if self.load_ready() {
return true;
}
if let Ok(tokens) = self.tokens.try_lock()
&& tokens.is_empty()
{
let was_ready = self.ready.swap(true, Ordering::AcqRel);
drop(tokens);
if !was_ready {
let _ = self.tx.send(true);
}
return true;
}
self.load_ready()
}
async fn subscribe(&self) -> Result<Token, errors::ReadinessError> {
if self.is_ready() {
if self.load_ready() {
return Err(errors::ReadinessError::FlagAlreadyReady);
}
@@ -97,7 +125,7 @@ impl Readiness for ReadinessFlag {
// check above and inserting the token.
let inserted = self
.with_tokens(|tokens| {
if self.is_ready() {
if self.load_ready() {
return false;
}
tokens.insert(token);
@@ -113,7 +141,7 @@ impl Readiness for ReadinessFlag {
}
async fn mark_ready(&self, token: Token) -> Result<bool, errors::ReadinessError> {
if self.is_ready() {
if self.load_ready() {
return Ok(false);
}
if token.0 == 0 {
@@ -202,7 +230,8 @@ mod tests {
async fn mark_ready_rejects_unknown_token() -> Result<(), ReadinessError> {
let flag = ReadinessFlag::new();
assert!(!flag.mark_ready(Token(42)).await?);
assert!(!flag.is_ready());
assert!(!flag.load_ready());
assert!(flag.is_ready());
Ok(())
}
@@ -233,6 +262,19 @@ mod tests {
Ok(())
}
#[tokio::test]
async fn is_ready_without_subscribers_marks_flag_ready() -> Result<(), ReadinessError> {
let flag = ReadinessFlag::new();
assert!(flag.is_ready());
assert!(flag.is_ready());
assert_matches!(
flag.subscribe().await,
Err(ReadinessError::FlagAlreadyReady)
);
Ok(())
}
#[tokio::test]
async fn subscribe_returns_error_when_lock_is_held() {
let flag = ReadinessFlag::new();