agentq 0.1.0

An embeddable job queue with idempotency keys, per-lane backpressure and bounded concurrency, for agent tool calls.
Documentation
use std::sync::Arc;

use tokio::sync::Semaphore;
use tokio::sync::mpsc::Receiver;

use crate::handle::Outcome;
use crate::job::Job;
use crate::state::{JobGuard, State, StateMap, WaiterMap};

pub(crate) fn spawn_worker(
    mut receiver: Receiver<Job>,
    semaphore: Arc<Semaphore>,
    statemap: StateMap,
    waiters: WaiterMap,
) {
    tokio::spawn(async move {
        while let Some(job) = receiver.recv().await {
            let Ok(permit) = semaphore.clone().acquire_owned().await else {
                break;
            };
            let statemap = statemap.clone();
            let waiters = waiters.clone();

            tokio::spawn(async move {
                let _permit = permit;
                {
                    let mut statemap = statemap.lock().unwrap_or_else(|e| e.into_inner());
                    statemap.insert(job.key.clone(), State::Processing);
                }

                let mut guard = JobGuard {
                    statemap,
                    waiters,
                    key: job.key.clone(),
                    outcome: None,
                };

                guard.outcome = Some(match (job.func)().await {
                    Ok(output) => Outcome::Completed { output },
                    Err(e) => Outcome::Failed {
                        reason: e.to_string(),
                    },
                });
            });
        }
    });
}