|
21 | 21 | #include "kafka/client/exceptions.h" |
22 | 22 | #include "kafka/data/rpc/deps.h" |
23 | 23 | #include "kafka/protocol/errors.h" |
| 24 | +#include "kafka/protocol/exceptions.h" |
24 | 25 | #include "kafka/protocol/list_offset.h" |
25 | 26 | #include "kafka/server/handlers/topics/types.h" |
26 | 27 | #include "model/fundamental.h" |
|
29 | 30 | #include "pandaproxy/logger.h" |
30 | 31 | #include "pandaproxy/schema_registry/auth.h" |
31 | 32 | #include "pandaproxy/schema_registry/configuration.h" |
| 33 | +#include "pandaproxy/schema_registry/exceptions.h" |
32 | 34 | #include "pandaproxy/schema_registry/handlers.h" |
33 | 35 | #include "pandaproxy/schema_registry/storage.h" |
34 | 36 | #include "pandaproxy/schema_registry/types.h" |
|
43 | 45 |
|
44 | 46 | #include <seastar/core/coroutine.hh> |
45 | 47 | #include <seastar/core/future-util.hh> |
| 48 | +#include <seastar/core/sleep.hh> |
| 49 | +#include <seastar/coroutine/parallel_for_each.hh> |
46 | 50 | #include <seastar/http/api_docs.hh> |
47 | 51 | #include <seastar/util/log.hh> |
48 | 52 | #include <seastar/util/noncopyable_function.hh> |
@@ -381,12 +385,44 @@ ss::future<> service::do_start() { |
381 | 385 | std::current_exception()); |
382 | 386 | throw; |
383 | 387 | } |
384 | | - co_await container().invoke_on_all(_ctx.smp_sg, [](service& s) { |
385 | | - s._is_started = true; |
386 | | - return ss::this_shard_id() == seq_writer::reader_shard |
387 | | - ? s.fetch_internal_topic() |
388 | | - : ss::now(); |
389 | | - }); |
| 388 | + co_await container().invoke_on_all( |
| 389 | + _ctx.smp_sg, [](this auto, service& s) -> ss::future<> { |
| 390 | + s._is_started = true; |
| 391 | + if (ss::this_shard_id() != seq_writer::reader_shard) { |
| 392 | + co_return; |
| 393 | + } |
| 394 | + |
| 395 | + // create_internal_topic returns once the controller commits |
| 396 | + // the topic, but the metadata cache is updated asynchronously. |
| 397 | + // Transient errors during this window — topic not yet visible, |
| 398 | + // leader not yet elected — are retried here. The kafka client |
| 399 | + // transport surfaces these as SR exceptions, while the RPC |
| 400 | + // transport surfaces them as kafka::exceptions. Both use |
| 401 | + // unknown_server_error. |
| 402 | + for (int attempts = 0;; ++attempts) { |
| 403 | + auto fut = co_await ss::coroutine::as_future( |
| 404 | + s.fetch_internal_topic()); |
| 405 | + if (!fut.failed()) { |
| 406 | + co_return; |
| 407 | + } |
| 408 | + auto eptr = fut.get_exception(); |
| 409 | + bool retriable = false; |
| 410 | + try { |
| 411 | + std::rethrow_exception(eptr); |
| 412 | + } catch (const kafka::exception_base& e) { |
| 413 | + retriable = e.error == kafka::error_code::unknown_server_error |
| 414 | + && attempts < 10; |
| 415 | + } catch (const exception& e) { |
| 416 | + retriable = e.code() |
| 417 | + == kafka::error_code::unknown_server_error |
| 418 | + && attempts < 10; |
| 419 | + } |
| 420 | + if (!retriable) { |
| 421 | + std::rethrow_exception(eptr); |
| 422 | + } |
| 423 | + co_await ss::sleep(std::chrono::milliseconds(100)); |
| 424 | + } |
| 425 | + }); |
390 | 426 | } |
391 | 427 |
|
392 | 428 | ss::future<> create_acls(cluster::security_frontend& security_fe) { |
|
0 commit comments