use std::num::NonZeroU32;
use aion_core::WorkerTransport;
use aion_proto::ProtoRegisterWorker;
use crate::error::ServerError;
use super::{ConnectedWorkerRegistry, RegistryState, WorkerHandle, WorkerId};
impl ConnectedWorkerRegistry {
pub fn set_advertised_capacity(
&self,
worker_id: WorkerId,
max_concurrency: u32,
) -> Result<bool, ServerError> {
let advertised = NonZeroU32::new(max_concurrency).ok_or_else(|| ServerError::Wire {
wire: aion_proto::WireError::backend(
"worker announced max_concurrency 0; a worker that runs no activities could \
never be selected for a dispatch",
),
})?;
{
let mut state = self.state()?;
if !state.workers.contains_key(&worker_id) {
return Ok(false);
}
if let Some(handle) = state.workers.get_mut(&worker_id) {
handle.max_concurrency = Some(advertised);
}
for workers in state.by_activity.values_mut() {
if let Some(handle) = workers.get_mut(&worker_id) {
handle.max_concurrency = Some(advertised);
}
}
}
self.worker_arrived.notify_waiters();
Ok(true)
}
pub(in crate::worker) fn record_dispatch_started(
&self,
worker_id: WorkerId,
) -> Result<(), ServerError> {
let mut state = self.state()?;
if !state.workers.contains_key(&worker_id) {
return Ok(());
}
let held = state.in_flight.entry(worker_id).or_insert(0);
*held = held.saturating_add(1);
Ok(())
}
pub(in crate::worker) fn record_dispatch_finished(
&self,
worker_id: WorkerId,
) -> Result<(), ServerError> {
{
let mut state = self.state()?;
if let Some(held) = state.in_flight.get_mut(&worker_id) {
*held = held.saturating_sub(1);
if *held == 0 {
state.in_flight.remove(&worker_id);
}
}
}
self.worker_arrived.notify_waiters();
if let Some(wake) = &self.capacity_wake {
wake.notify_one();
}
Ok(())
}
pub fn in_flight_for_worker(&self, worker_id: WorkerId) -> Result<u32, ServerError> {
Ok(self
.state()?
.in_flight
.get(&worker_id)
.copied()
.unwrap_or(0))
}
}
pub(super) fn advertised_capacity(
registration: &ProtoRegisterWorker,
transport: WorkerTransport,
) -> Result<Option<u32>, ServerError> {
if let Some(advertised) = registration.max_concurrency {
return Ok(Some(advertised));
}
match transport {
WorkerTransport::Grpc => Err(ServerError::Wire {
wire: aion_proto::WireError::backend(
"worker registration carries no max_concurrency; every worker advertises the \
number of activities it runs at once, and the server will not invent one for it",
),
}),
WorkerTransport::Liminal => Ok(None),
}
}
pub(super) fn worker_is_at_capacity(state: &RegistryState, worker: &WorkerHandle) -> bool {
let Some(advertised) = worker.max_concurrency else {
return true;
};
state
.in_flight
.get(&worker.id)
.is_some_and(|held| *held >= advertised.get())
}