Skip to content

Commit c85291c

Browse files
authored
[BugFix] fix consume_signals barrier deadlock in PD separation (#8034)
In PD separation mode, different ranks may receive cache_info at different times. When consume_signals gets a layer0 signal, some ranks find the engine_idx already in idx_cache_task_dict (ready) while others don't (pending). This causes different ranks to put different batch_engine_signals into the queue, leading to mismatched finish_send_cache_barrier.wait() calls and deadlock. Fix: route all layer0 signals through pending_layer0_signals uniformly, then immediately recover any that already have cache_info registered. Each recovered signal is put into the queue individually (single-request batch) to ensure all ranks have identical batch granularity regardless of recovery timing.
1 parent 513686d commit c85291c

1 file changed

Lines changed: 12 additions & 16 deletions

File tree

fastdeploy/cache_manager/cache_messager.py

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,8 +1074,6 @@ def consume_signals(self):
10741074
layer_id = kv_signal_data[1].item()
10751075
if layer_id == self.num_layers - 1:
10761076
logger.info(f"tasks_count: {tasks_count}, layer_id: {layer_id} self.rank_id {self.rank_id}")
1077-
ready_engine_signals = []
1078-
pending_engine_signals = []
10791077
# format for signal to put in cache_prefilled_engine_ids_queue: [(engine_idx1, prefilled_token_num1), (engine_idx2, prefilled_token_num2)]
10801078
with self.engine_cache_task_thread_lock:
10811079
for bi in range(tasks_count):
@@ -1086,21 +1084,19 @@ def consume_signals(self):
10861084
self.engine_cache_tasks[engine_idx]["prefilled_layer_idx"] = layer_id
10871085
self.engine_cache_tasks[engine_idx]["prefilled_token_num"] = prefilled_token_num
10881086
if layer_id == 0:
1089-
if engine_idx in self.idx_cache_task_dict:
1090-
ready_engine_signals.append((engine_idx, prefilled_token_num))
1091-
else:
1092-
pending_engine_signals.append((engine_idx, prefilled_token_num))
1093-
if pending_engine_signals:
1094-
with self.pending_layer0_signal_lock:
1095-
for engine_idx, prefilled_token_num in pending_engine_signals:
1087+
with self.pending_layer0_signal_lock:
10961088
self.pending_layer0_signals[engine_idx] = (engine_idx, prefilled_token_num)
1097-
if pending_engine_signals:
1098-
logger.debug(f"cache_task_pending_layer0_signal: {pending_engine_signals}")
1099-
if ready_engine_signals:
1100-
logger.info(
1101-
f"Put batch_engine_signals {ready_engine_signals} into cache_prefilled_engine_ids_queue"
1102-
)
1103-
self.cache_prefilled_engine_ids_queue.put(ready_engine_signals)
1089+
# Recover signals for engine_idxs that already have cache_info registered.
1090+
# This handles the case where cache_info arrives before layer0 signal.
1091+
recovered_signals = []
1092+
with self.pending_layer0_signal_lock:
1093+
for engine_idx in list(self.pending_layer0_signals.keys()):
1094+
if engine_idx in self.idx_cache_task_dict:
1095+
recovered_signals.append(self.pending_layer0_signals.pop(engine_idx))
1096+
if recovered_signals:
1097+
for signal in recovered_signals:
1098+
logger.info(f"consume_signals recovered signal: {signal}")
1099+
self.cache_prefilled_engine_ids_queue.put([signal])
11041100
except Exception as e:
11051101
logger.error(f"Consume signals get exception: {e}, {traceback.format_exc()}")
11061102

0 commit comments

Comments
 (0)