Summary
TaskProcessor (crates/asterisk-core/src/taskprocessor/mod.rs:36) backs its
serial executor with a mpsc::unbounded_channel, and push()
(:72) always enqueues and returns true — there is no high-water mark,
congestion signal, or backpressure. A producer that outpaces the single serial
consumer grows the queue (and process memory) without bound.
let (sender, mut receiver) = mpsc::unbounded_channel::<BoxedTask>();
...
pub fn push<F>(&self, task: F) -> bool {
if let Some(sender) = &self.sender {
self.task_count.fetch_add(1, Ordering::Relaxed);
sender.send(Box::pin(task)).is_ok() // never fails on capacity
} else { false }
}
Real Asterisk's ast_taskprocessor has congestion control (a high-water alert
and overload shedding, tps_alert / AST_TASKPROCESSOR_HIGH_WATER_LEVEL); this
port has none.
Impact
Latent today: TaskProcessor is only referenced by the test framework and the
asterisk-core re-export — no production per-call path submits to it yet. But
the moment it is wired into a hot path (channel-op serialization, a media or
signaling fan-in), a slow task + fast producer is an unbounded memory growth
under the M5 soak, with no shedding and no observability beyond pending().
Recommendation
Before wiring TaskProcessor into any per-call path:
- Use a bounded channel (or track depth against a configurable high-water mark)
and make push shed / signal congestion instead of silently growing.
- Surface an overload flag (mirror
tps_alert) so callers can back off.
Filed as a hardening recommendation (not fixed here): adding backpressure to a
general primitive is a design choice for the owner, and the primitive is not yet
on a live path. Axis: concurrency / resource lifetime — unbounded queue.
Summary
TaskProcessor(crates/asterisk-core/src/taskprocessor/mod.rs:36) backs itsserial executor with a
mpsc::unbounded_channel, andpush()(
:72) always enqueues and returnstrue— there is no high-water mark,congestion signal, or backpressure. A producer that outpaces the single serial
consumer grows the queue (and process memory) without bound.
Real Asterisk's
ast_taskprocessorhas congestion control (a high-water alertand overload shedding,
tps_alert/AST_TASKPROCESSOR_HIGH_WATER_LEVEL); thisport has none.
Impact
Latent today:
TaskProcessoris only referenced by the test framework and theasterisk-corere-export — no production per-call path submits to it yet. Butthe moment it is wired into a hot path (channel-op serialization, a media or
signaling fan-in), a slow task + fast producer is an unbounded memory growth
under the M5 soak, with no shedding and no observability beyond
pending().Recommendation
Before wiring
TaskProcessorinto any per-call path:and make
pushshed / signal congestion instead of silently growing.tps_alert) so callers can back off.Filed as a hardening recommendation (not fixed here): adding backpressure to a
general primitive is a design choice for the owner, and the primitive is not yet
on a live path. Axis: concurrency / resource lifetime — unbounded queue.