Skip to content

Commit 871e3a3

Browse files
committed
Release job map lock before queue sends
A full state-machine queue caused controller RPC handlers to wait while holding the global job map mutex. One stalled job could therefore prevent messages from reaching every other job. Clone the selected job's sender under the map lock, then release the lock before waiting for channel capacity. This preserves per-job backpressure without making it controller-wide.
1 parent 36e1873 commit 871e3a3

2 files changed

Lines changed: 26 additions & 16 deletions

File tree

crates/arroyo-controller/src/lib.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -651,22 +651,28 @@ impl ControllerServer {
651651
}
652652

653653
async fn send_to_job_queue(&self, job_id: &str, msg: JobMessage) -> Result<(), Status> {
654-
let mut jobs = self.job_state.lock().await;
655-
656-
if let Some(sm) = jobs.get_mut(job_id) {
657-
if let Err(e) = sm.send(msg).await {
658-
Err(Status::failed_precondition(format!(
659-
"Cannot handle message for {job_id}: {e}"
660-
)))
661-
} else {
662-
Ok(())
663-
}
664-
} else {
665-
warn!(message = "Received message for unknown job id", job_id);
666-
Err(Status::failed_precondition(format!(
667-
"No job with id {job_id}"
668-
)))
669-
}
654+
// Keep per-job backpressure from holding the global job map lock.
655+
let tx = {
656+
let jobs = self.job_state.lock().await;
657+
let Some(sm) = jobs.get(job_id) else {
658+
warn!(message = "Received message for unknown job id", job_id);
659+
return Err(Status::failed_precondition(format!(
660+
"No job with id {job_id}"
661+
)));
662+
};
663+
664+
sm.sender().ok_or_else(|| {
665+
Status::failed_precondition(format!(
666+
"Cannot handle message for {job_id}: State machine is inactive"
667+
))
668+
})?
669+
};
670+
671+
tx.send(msg).await.map_err(|_| {
672+
Status::failed_precondition(format!(
673+
"Cannot handle message for {job_id}: State machine is inactive"
674+
))
675+
})
670676
}
671677

672678
fn start_updater(&self, guard: ShutdownGuard) {

crates/arroyo-controller/src/states/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,10 @@ impl StateMachine {
12071207
}
12081208
}
12091209

1210+
pub(crate) fn sender(&self) -> Option<Sender<JobMessage>> {
1211+
self.tx.clone()
1212+
}
1213+
12101214
pub fn done(&self) -> bool {
12111215
if let Some(tx) = &self.tx {
12121216
tx.is_closed()

0 commit comments

Comments
 (0)