From 3d75e7b51f2158174163379219f0c4ecb03d80bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E5=B0=8F=E9=B8=AD?= Date: Mon, 24 Aug 2026 20:38:46 +0800 Subject: [PATCH] fix(ecstore): heap-allocate durable ILM receipt futures (#6527) PR #6369 awaits record_durable_ilm_decommission_progress/terminal inline from save/delete_transition_transaction_record. Their state machines are large and sit on the already-deep transition worker poll chain (worker -> transition -> transaction record -> delete_config -> full store delete fanout), which overflowed the default 2 MiB tokio worker stack in debug builds: app::lifecycle_transition_api_test:: compensation_driven_complete_multipart_upload_still_transitions died with SIGABRT in under a second (first-bad commit via git bisect 1.0.0-rc.3..1ec1a8d90: 34bbc1adb, #6369). 41546dee5 already unblocked the test by moving it onto a dedicated 32 MiB thread; this change removes the underlying stack growth so every caller of the transaction-record helpers keeps its previous headroom. With it, the test also passes on a plain 2 MiB tokio worker. --- .../src/bucket/lifecycle/transition_transaction.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/ecstore/src/bucket/lifecycle/transition_transaction.rs b/crates/ecstore/src/bucket/lifecycle/transition_transaction.rs index 70bf4ed53..8c1c1e22c 100644 --- a/crates/ecstore/src/bucket/lifecycle/transition_transaction.rs +++ b/crates/ecstore/src/bucket/lifecycle/transition_transaction.rs @@ -586,7 +586,10 @@ pub(crate) async fn save_transition_transaction_record( transition_transaction_record_object_name(transaction.transaction_id).map_err(transition_transaction_store_error)?; let data = transaction.encode().map_err(transition_transaction_store_error)?; config_boundary::save_config(api.clone(), &object, data.clone()).await?; - api.record_durable_ilm_decommission_progress(&object, &data).await + // Box::pin: the durable-receipt state machine is large and sits on the + // already-deep transition worker poll chain; keeping it inline overflows + // the default 2 MiB tokio worker stack in debug builds. + Box::pin(api.record_durable_ilm_decommission_progress(&object, &data)).await } pub(crate) async fn load_transition_transaction_record( @@ -605,7 +608,8 @@ pub(crate) async fn delete_transition_transaction_record( let object = transition_transaction_record_object_name(transaction.transaction_id).map_err(transition_transaction_store_error)?; let data = transaction.encode().map_err(transition_transaction_store_error)?; - api.record_durable_ilm_decommission_terminal(&object, &data).await?; + // Box::pin: see save_transition_transaction_record. + Box::pin(api.record_durable_ilm_decommission_terminal(&object, &data)).await?; match config_boundary::delete_config(api, &object).await { Ok(()) | Err(Error::ConfigNotFound) => Ok(()), Err(err) => Err(err),