From fffe19abb0ff0f8b004615abed1219c6d5a89a21 Mon Sep 17 00:00:00 2001 From: Andrzej Jackowski Date: Tue, 26 May 2026 13:21:39 +0200 Subject: [PATCH 1/2] table_helper: observe detached setup_table() future During shutdown, group0 may be torn down while cache_table_info() has a detached setup_table() future in flight. This causes raft_group_not_found to propagate as an abandoned failed future. Add .handle_exception() to log the failure at debug level instead of leaving the future unobserved. Fixes: SCYLLADB-2224 --- table_helper.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/table_helper.cc b/table_helper.cc index b32d93dbd4..a0208344fb 100644 --- a/table_helper.cc +++ b/table_helper.cc @@ -121,6 +121,8 @@ future<> table_helper::cache_table_info(cql3::query_processor& qp, service::migr //FIXME: discarded future. (void)qp.container().invoke_on(0, [&mm = mm.container(), create_cql = _create_cql] (cql3::query_processor& qp) -> future<> { co_return co_await table_helper::setup_table(qp, mm.local(), create_cql); + }).handle_exception([keyspace = _keyspace, name = _name] (std::exception_ptr ep) { + tlogger.debug("Failed to create {}.{} table in best-effort recovery path: {}", keyspace, name, ep); }); // We throw the bad_column_family exception because the caller From 45ff773466c5e51c5869a0a861fe5feb628979b6 Mon Sep 17 00:00:00 2001 From: Andrzej Jackowski Date: Tue, 26 May 2026 13:21:50 +0200 Subject: [PATCH 2/2] test: table_helper: verify detached setup failure is consumed Add test_best_effort_setup_table_failure_is_consumed which triggers a setup_table() failure via a missing keyspace and asserts no abandoned future escapes. This guards against regressions where the detached future loses its exception handler. Remove the test_skipped_no_error_injection placeholder since the new test runs unconditionally keeping the suite non-empty in all build modes. --- test/boost/table_helper_test.cc | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/test/boost/table_helper_test.cc b/test/boost/table_helper_test.cc index 0f08a9b73f..1092670d5a 100644 --- a/test/boost/table_helper_test.cc +++ b/test/boost/table_helper_test.cc @@ -35,6 +35,23 @@ BOOST_AUTO_TEST_SUITE(table_helper_test) +SEASTAR_TEST_CASE(test_best_effort_setup_table_failure_is_consumed) { + return do_with_cql_env_thread([] (cql_test_env& env) { + auto& qp = env.local_qp(); + auto& mm = env.migration_manager().local(); + + const sstring create_cql = "CREATE TABLE IF NOT EXISTS missing_ks.t (id int PRIMARY KEY)"; + const sstring insert_cql = "INSERT INTO missing_ks.t (id) VALUES (?)"; + + table_helper helper("missing_ks", "t", create_cql, insert_cql); + service::query_state qs(service::client_state::for_internal_calls(), empty_service_permit()); + + BOOST_REQUIRE_THROW(helper.cache_table_info(qp, mm, qs).get(), bad_column_family); + + seastar::yield().get(); + }); +} + #ifdef SCYLLA_ENABLE_ERROR_INJECTION SEASTAR_TEST_CASE(test_concurrent_invalidation) { @@ -98,14 +115,4 @@ SEASTAR_TEST_CASE(test_concurrent_invalidation) { #endif // SCYLLA_ENABLE_ERROR_INJECTION -#ifndef SCYLLA_ENABLE_ERROR_INJECTION -// The only test in this suite requires error injection support. Without this -// dummy case the suite would be empty, which causes boost to report -// "test tree is empty" and pytest to exit with code 5 ("no tests collected"), -// failing CI in modes (e.g. release) where error injection is disabled. -BOOST_AUTO_TEST_CASE(test_skipped_no_error_injection) { - BOOST_TEST_MESSAGE("table_helper_test requires SCYLLA_ENABLE_ERROR_INJECTION; skipping"); -} -#endif - BOOST_AUTO_TEST_SUITE_END()