cloud_terrastodon_command 0.36.0

Command running helpers for the Cloud Terrastodon project
Documentation
use bstr::BString;
use cloud_terrastodon_command::CacheKey;
use cloud_terrastodon_command::CacheableWorkRequest;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::time::SystemTime;
use std::time::UNIX_EPOCH;

#[derive(Debug, Clone)]
struct EchoWorkRequest {
    cache_key: CacheKey,
    message: String,
    executions: Arc<AtomicUsize>,
}

#[derive(Debug, Serialize, Deserialize)]
struct EchoRaw {
    message: String,
}

#[cloud_terrastodon_command::async_trait]
impl CacheableWorkRequest for EchoWorkRequest {
    type Raw = EchoRaw;
    type Output = String;

    fn cache_key(&self) -> CacheKey {
        self.cache_key.clone()
    }

    fn context(&self) -> String {
        format!("echo {}", self.message)
    }

    fn debug_inputs(&self) -> BTreeMap<PathBuf, BString> {
        BTreeMap::from([(PathBuf::from("input.txt"), self.message.clone().into())])
    }

    async fn execute_raw(self) -> eyre::Result<Self::Raw> {
        self.executions.fetch_add(1, Ordering::SeqCst);
        Ok(EchoRaw {
            message: self.message,
        })
    }

    fn decode(raw: Self::Raw) -> eyre::Result<Self::Output> {
        Ok(raw.message)
    }
}

cloud_terrastodon_command::impl_cacheable_work_into_future!(EchoWorkRequest);

fn unique_cache_key() -> CacheKey {
    let suffix = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .expect("time went backwards")
        .as_nanos()
        .to_string();
    CacheKey::new(PathBuf::from_iter([
        "tests",
        "cacheable_work",
        suffix.as_str(),
    ]))
}

#[tokio::test]
async fn reuses_cached_in_process_work_without_reexecuting() -> eyre::Result<()> {
    let executions = Arc::new(AtomicUsize::new(0));
    let cache_key = unique_cache_key();

    let first = EchoWorkRequest {
        cache_key: cache_key.clone(),
        message: "hello".to_string(),
        executions: executions.clone(),
    };
    let second = EchoWorkRequest {
        cache_key,
        message: "hello".to_string(),
        executions: executions.clone(),
    };

    assert_eq!(first.await?, "hello");
    assert_eq!(second.await?, "hello");
    assert_eq!(executions.load(Ordering::SeqCst), 1);
    Ok(())
}