actor_kit/policy.rs
1//! Pluggable admission-control hook for spawns and message sends.
2//!
3//! This replaces the upstream `tenant::quota::QuotaEnforcer` coupling: instead
4//! of the scheduler depending on a concrete multi-tenant quota type, it depends
5//! on this trait. Hosts that need per-tenant quotas, per-actor memory budgets,
6//! or rate limiting implement [`ResourcePolicy`] and install it via
7//! [`ActorScheduler::with_resource_policy`](crate::ActorScheduler::with_resource_policy).
8//!
9//! The default policy is [`NoopPolicy`], which admits everything.
10
11use crate::Result;
12
13/// Admission control for actor spawns and message sends.
14///
15/// Called synchronously on the hot path (`spawn`, `send`, `send_batch`), so
16/// implementations must be cheap and non-blocking.
17///
18/// All methods have default implementations that admit everything, so
19/// policies only need to override what they enforce.
20pub trait ResourcePolicy: Send + Sync + 'static {
21 /// Decide whether a new actor may be spawned.
22 ///
23 /// Return `Err(reason)` to reject the spawn; the reason is surfaced in the
24 /// [`Error::ResourceExhausted`](crate::Error::ResourceExhausted) message.
25 fn admit_actor(&self) -> Result<()> {
26 Ok(())
27 }
28
29 /// Notify the policy that an actor was killed/released.
30 ///
31 /// Called from `ActorScheduler::kill`. Use to free any per-actor budget.
32 fn release_actor(&self) {}
33
34 /// Decide whether a send of `count` messages may proceed.
35 ///
36 /// `count == 1` for single sends, `> 1` for batch sends.
37 fn admit_message(&self, count: usize) -> Result<()> {
38 let _ = count;
39 Ok(())
40 }
41}
42
43/// The default policy: admit all spawns and sends.
44#[derive(Debug, Clone, Copy, Default)]
45pub struct NoopPolicy;
46
47impl ResourcePolicy for NoopPolicy {}