1use common_error::define_into_tonic_status;
16use common_error::ext::{BoxedError, ErrorExt, RetryHint};
17use common_error::status_code::StatusCode;
18use common_macro::stack_trace_debug;
19use common_meta::DatanodeId;
20use common_procedure::ProcedureId;
21use common_runtime::JoinError;
22use common_wal::kafka::rskafka_client_error_to_retry_hint;
23use snafu::{Location, Snafu};
24use store_api::storage::RegionId;
25use table::metadata::TableId;
26use tokio::sync::mpsc::error::SendError;
27use tonic::codegen::http;
28use uuid::Uuid;
29
30use crate::metasrv::SelectTarget;
31use crate::pubsub::Message;
32use crate::service::mailbox::Channel;
33
34#[derive(Snafu)]
35#[snafu(visibility(pub))]
36#[stack_trace_debug]
37pub enum Error {
38 #[snafu(display("Failed to choose items"))]
39 ChooseItems {
40 #[snafu(implicit)]
41 location: Location,
42 #[snafu(source)]
43 error: rand::distr::weighted::Error,
44 },
45
46 #[snafu(display("Exceeded deadline, operation: {}", operation))]
47 ExceededDeadline {
48 #[snafu(implicit)]
49 location: Location,
50 operation: String,
51 },
52
53 #[snafu(display("The target peer is unavailable temporally: {}", peer_id))]
54 PeerUnavailable {
55 #[snafu(implicit)]
56 location: Location,
57 peer_id: u64,
58 },
59
60 #[snafu(display("Failed to list active frontends"))]
61 ListActiveFrontends {
62 #[snafu(implicit)]
63 location: Location,
64 source: common_meta::error::Error,
65 },
66
67 #[snafu(display("Failed to list active datanodes"))]
68 ListActiveDatanodes {
69 #[snafu(implicit)]
70 location: Location,
71 source: common_meta::error::Error,
72 },
73
74 #[snafu(display("Failed to list active flownodes"))]
75 ListActiveFlownodes {
76 #[snafu(implicit)]
77 location: Location,
78 source: common_meta::error::Error,
79 },
80
81 #[snafu(display("No available frontend"))]
82 NoAvailableFrontend {
83 #[snafu(implicit)]
84 location: Location,
85 },
86
87 #[snafu(display("Another migration procedure is running for region: {}", region_id))]
88 MigrationRunning {
89 #[snafu(implicit)]
90 location: Location,
91 region_id: RegionId,
92 },
93
94 #[snafu(display(
95 "The region migration procedure is completed for region: {}, target_peer: {}",
96 region_id,
97 target_peer_id
98 ))]
99 RegionMigrated {
100 #[snafu(implicit)]
101 location: Location,
102 region_id: RegionId,
103 target_peer_id: u64,
104 },
105
106 #[snafu(display("The region migration procedure aborted, reason: {}", reason))]
107 MigrationAbort {
108 #[snafu(implicit)]
109 location: Location,
110 reason: String,
111 },
112
113 #[snafu(display(
114 "Another procedure is operating the region: {} on peer: {}",
115 region_id,
116 peer_id
117 ))]
118 RegionOperatingRace {
119 #[snafu(implicit)]
120 location: Location,
121 peer_id: DatanodeId,
122 region_id: RegionId,
123 },
124
125 #[snafu(display("Failed to init ddl manager"))]
126 InitDdlManager {
127 #[snafu(implicit)]
128 location: Location,
129 source: common_meta::error::Error,
130 },
131
132 #[snafu(display("Failed to init reconciliation manager"))]
133 InitReconciliationManager {
134 #[snafu(implicit)]
135 location: Location,
136 source: common_meta::error::Error,
137 },
138
139 #[snafu(display("Failed to create default catalog and schema"))]
140 InitMetadata {
141 #[snafu(implicit)]
142 location: Location,
143 source: common_meta::error::Error,
144 },
145
146 #[snafu(display("Failed to allocate next sequence number"))]
147 NextSequence {
148 #[snafu(implicit)]
149 location: Location,
150 source: common_meta::error::Error,
151 },
152
153 #[snafu(display("Failed to set next sequence number"))]
154 SetNextSequence {
155 #[snafu(implicit)]
156 location: Location,
157 source: common_meta::error::Error,
158 },
159
160 #[snafu(display("Failed to peek sequence number"))]
161 PeekSequence {
162 #[snafu(implicit)]
163 location: Location,
164 source: common_meta::error::Error,
165 },
166
167 #[snafu(display("Failed to start telemetry task"))]
168 StartTelemetryTask {
169 #[snafu(implicit)]
170 location: Location,
171 source: common_runtime::error::Error,
172 },
173
174 #[snafu(display("Failed to submit ddl task"))]
175 SubmitDdlTask {
176 #[snafu(implicit)]
177 location: Location,
178 source: common_meta::error::Error,
179 },
180
181 #[snafu(display("Failed to submit reconcile procedure"))]
182 SubmitReconcileProcedure {
183 #[snafu(implicit)]
184 location: Location,
185 source: common_meta::error::Error,
186 },
187
188 #[snafu(display("Failed to invalidate table cache"))]
189 InvalidateTableCache {
190 #[snafu(implicit)]
191 location: Location,
192 source: common_meta::error::Error,
193 },
194
195 #[snafu(display("Failed to list catalogs"))]
196 ListCatalogs {
197 #[snafu(implicit)]
198 location: Location,
199 source: BoxedError,
200 },
201
202 #[snafu(display("Failed to list {}'s schemas", catalog))]
203 ListSchemas {
204 #[snafu(implicit)]
205 location: Location,
206 catalog: String,
207 source: BoxedError,
208 },
209
210 #[snafu(display("Failed to list {}.{}'s tables", catalog, schema))]
211 ListTables {
212 #[snafu(implicit)]
213 location: Location,
214 catalog: String,
215 schema: String,
216 source: BoxedError,
217 },
218
219 #[snafu(display("Failed to join a future"))]
220 Join {
221 #[snafu(implicit)]
222 location: Location,
223 #[snafu(source)]
224 error: JoinError,
225 },
226
227 #[snafu(display(
228 "Failed to request {}, required: {}, but only {} available",
229 select_target,
230 required,
231 available
232 ))]
233 NoEnoughAvailableNode {
234 #[snafu(implicit)]
235 location: Location,
236 required: usize,
237 available: usize,
238 select_target: SelectTarget,
239 },
240
241 #[snafu(display("Failed to send shutdown signal"))]
242 SendShutdownSignal {
243 #[snafu(source)]
244 error: SendError<()>,
245 },
246
247 #[snafu(display("Failed to shutdown {} server", server))]
248 ShutdownServer {
249 #[snafu(implicit)]
250 location: Location,
251 source: servers::error::Error,
252 server: String,
253 },
254
255 #[snafu(display("Empty key is not allowed"))]
256 EmptyKey {
257 #[snafu(implicit)]
258 location: Location,
259 },
260
261 #[snafu(display("Failed to execute via Etcd"))]
262 EtcdFailed {
263 #[snafu(source)]
264 error: etcd_client::Error,
265 #[snafu(implicit)]
266 location: Location,
267 },
268
269 #[snafu(display("Failed to connect to Etcd"))]
270 ConnectEtcd {
271 #[snafu(source)]
272 error: etcd_client::Error,
273 #[snafu(implicit)]
274 location: Location,
275 },
276
277 #[snafu(display("Failed to read file: {}", path))]
278 FileIo {
279 #[snafu(source)]
280 error: std::io::Error,
281 #[snafu(implicit)]
282 location: Location,
283 path: String,
284 },
285
286 #[snafu(display("Failed to bind address {}", addr))]
287 TcpBind {
288 addr: String,
289 #[snafu(source)]
290 error: std::io::Error,
291 #[snafu(implicit)]
292 location: Location,
293 },
294
295 #[snafu(display("Failed to start gRPC server"))]
296 StartGrpc {
297 #[snafu(source)]
298 error: tonic::transport::Error,
299 #[snafu(implicit)]
300 location: Location,
301 },
302
303 #[snafu(display("Failed to start http server"))]
304 StartHttp {
305 #[snafu(implicit)]
306 location: Location,
307 source: servers::error::Error,
308 },
309
310 #[snafu(display("Failed to parse address {}", addr))]
311 ParseAddr {
312 addr: String,
313 #[snafu(source)]
314 error: std::net::AddrParseError,
315 },
316
317 #[snafu(display("Invalid lease key: {}", key))]
318 InvalidLeaseKey {
319 key: String,
320 #[snafu(implicit)]
321 location: Location,
322 },
323
324 #[snafu(display("Invalid datanode stat key: {}", key))]
325 InvalidStatKey {
326 key: String,
327 #[snafu(implicit)]
328 location: Location,
329 },
330
331 #[snafu(display("Invalid inactive region key: {}", key))]
332 InvalidInactiveRegionKey {
333 key: String,
334 #[snafu(implicit)]
335 location: Location,
336 },
337
338 #[snafu(display("Invalid node scheduling key: {}", key))]
339 InvalidNodeSchedulingKey {
340 #[snafu(implicit)]
341 location: Location,
342 key: String,
343 },
344
345 #[snafu(display("Failed to parse lease key from utf8"))]
346 LeaseKeyFromUtf8 {
347 #[snafu(source)]
348 error: std::string::FromUtf8Error,
349 #[snafu(implicit)]
350 location: Location,
351 },
352
353 #[snafu(display("Failed to parse lease value from utf8"))]
354 LeaseValueFromUtf8 {
355 #[snafu(source)]
356 error: std::string::FromUtf8Error,
357 #[snafu(implicit)]
358 location: Location,
359 },
360
361 #[snafu(display("Failed to parse invalid region key from utf8"))]
362 InvalidRegionKeyFromUtf8 {
363 #[snafu(source)]
364 error: std::string::FromUtf8Error,
365 #[snafu(implicit)]
366 location: Location,
367 },
368
369 #[snafu(display("Failed to serialize to json: {}", input))]
370 SerializeToJson {
371 input: String,
372 #[snafu(source)]
373 error: serde_json::error::Error,
374 #[snafu(implicit)]
375 location: Location,
376 },
377
378 #[snafu(display("Failed to deserialize from json payload of length {}", input_len))]
379 DeserializeFromJson {
380 input_len: usize,
381 #[snafu(source)]
382 error: serde_json::error::Error,
383 #[snafu(implicit)]
384 location: Location,
385 },
386
387 #[snafu(display("Failed to serialize config"))]
388 SerializeConfig {
389 #[snafu(source)]
390 error: serde_json::error::Error,
391 #[snafu(implicit)]
392 location: Location,
393 },
394
395 #[snafu(display("Failed to parse number: {}", err_msg))]
396 ParseNum {
397 err_msg: String,
398 #[snafu(source)]
399 error: std::num::ParseIntError,
400 #[snafu(implicit)]
401 location: Location,
402 },
403
404 #[snafu(display("Failed to parse bool: {}", err_msg))]
405 ParseBool {
406 err_msg: String,
407 #[snafu(source)]
408 error: std::str::ParseBoolError,
409 #[snafu(implicit)]
410 location: Location,
411 },
412
413 #[snafu(display("Failed to downgrade region leader, region: {}", region_id))]
414 DowngradeLeader {
415 region_id: RegionId,
416 #[snafu(implicit)]
417 location: Location,
418 #[snafu(source)]
419 source: BoxedError,
420 },
421
422 #[snafu(display("Region's leader peer changed: {}", msg))]
423 LeaderPeerChanged {
424 msg: String,
425 #[snafu(implicit)]
426 location: Location,
427 },
428
429 #[snafu(display("Invalid arguments: {}", err_msg))]
430 InvalidArguments {
431 err_msg: String,
432 #[snafu(implicit)]
433 location: Location,
434 },
435
436 #[snafu(display("Manual GC is rejected because maintenance mode is enabled"))]
437 ManualGcRejectedByMaintenanceMode {
438 #[snafu(implicit)]
439 location: Location,
440 },
441
442 #[cfg(feature = "mysql_kvbackend")]
443 #[snafu(display("Failed to parse mysql url: {}", mysql_url))]
444 ParseMySqlUrl {
445 #[snafu(source)]
446 error: sqlx::error::Error,
447 mysql_url: String,
448 #[snafu(implicit)]
449 location: Location,
450 },
451
452 #[cfg(feature = "mysql_kvbackend")]
453 #[snafu(display("Failed to decode sql value"))]
454 DecodeSqlValue {
455 #[snafu(source)]
456 error: sqlx::error::Error,
457 #[snafu(implicit)]
458 location: Location,
459 },
460
461 #[snafu(display("Failed to find table route for {table_id}"))]
462 TableRouteNotFound {
463 table_id: TableId,
464 #[snafu(implicit)]
465 location: Location,
466 },
467
468 #[snafu(display("Failed to find table route for {region_id}"))]
469 RegionRouteNotFound {
470 region_id: RegionId,
471 #[snafu(implicit)]
472 location: Location,
473 },
474
475 #[snafu(display("Table info not found: {}", table_id))]
476 TableInfoNotFound {
477 table_id: TableId,
478 #[snafu(implicit)]
479 location: Location,
480 },
481
482 #[snafu(display("Datanode table not found: {}, datanode: {}", table_id, datanode_id))]
483 DatanodeTableNotFound {
484 table_id: TableId,
485 datanode_id: DatanodeId,
486 #[snafu(implicit)]
487 location: Location,
488 },
489
490 #[snafu(display("Metasrv has no leader at this moment"))]
491 NoLeader {
492 #[snafu(implicit)]
493 location: Location,
494 },
495
496 #[snafu(display("Leader lease expired"))]
497 LeaderLeaseExpired {
498 #[snafu(implicit)]
499 location: Location,
500 },
501
502 #[snafu(display("Leader lease changed during election"))]
503 LeaderLeaseChanged {
504 #[snafu(implicit)]
505 location: Location,
506 },
507
508 #[snafu(display("Table {} not found", name))]
509 TableNotFound {
510 name: String,
511 #[snafu(implicit)]
512 location: Location,
513 },
514
515 #[snafu(display("Unsupported selector type, {}", selector_type))]
516 UnsupportedSelectorType {
517 selector_type: String,
518 #[snafu(implicit)]
519 location: Location,
520 },
521
522 #[snafu(display("Unexpected, violated: {violated}"))]
523 Unexpected {
524 violated: String,
525 #[snafu(implicit)]
526 location: Location,
527 },
528
529 #[snafu(display("Failed to create gRPC channel"))]
530 CreateChannel {
531 #[snafu(implicit)]
532 location: Location,
533 source: common_grpc::error::Error,
534 },
535
536 #[snafu(display("Failed to batch get KVs from leader's in_memory kv store"))]
537 BatchGet {
538 #[snafu(source)]
539 error: tonic::Status,
540 #[snafu(implicit)]
541 location: Location,
542 },
543
544 #[snafu(display("Failed to batch range KVs from leader's in_memory kv store"))]
545 Range {
546 #[snafu(source)]
547 error: tonic::Status,
548 #[snafu(implicit)]
549 location: Location,
550 },
551
552 #[snafu(display("Response header not found"))]
553 ResponseHeaderNotFound {
554 #[snafu(implicit)]
555 location: Location,
556 },
557
558 #[snafu(display("The requested meta node is not leader, node addr: {}", node_addr))]
559 IsNotLeader {
560 node_addr: String,
561 #[snafu(implicit)]
562 location: Location,
563 },
564
565 #[snafu(display("Invalid http body"))]
566 InvalidHttpBody {
567 #[snafu(source)]
568 error: http::Error,
569 #[snafu(implicit)]
570 location: Location,
571 },
572
573 #[snafu(display(
574 "The number of retries for the grpc call {} exceeded the limit, {}",
575 func_name,
576 retry_num
577 ))]
578 ExceededRetryLimit {
579 func_name: String,
580 retry_num: usize,
581 #[snafu(implicit)]
582 location: Location,
583 },
584
585 #[snafu(display("Invalid utf-8 value"))]
586 InvalidUtf8Value {
587 #[snafu(source)]
588 error: std::string::FromUtf8Error,
589 #[snafu(implicit)]
590 location: Location,
591 },
592
593 #[snafu(display("Missing required parameter, param: {:?}", param))]
594 MissingRequiredParameter { param: String },
595
596 #[snafu(display("Failed to start procedure manager"))]
597 StartProcedureManager {
598 #[snafu(implicit)]
599 location: Location,
600 source: common_procedure::Error,
601 },
602
603 #[snafu(display("Failed to stop procedure manager"))]
604 StopProcedureManager {
605 #[snafu(implicit)]
606 location: Location,
607 source: common_procedure::Error,
608 },
609
610 #[snafu(display("Failed to wait procedure done"))]
611 WaitProcedure {
612 #[snafu(implicit)]
613 location: Location,
614 source: common_procedure::Error,
615 },
616
617 #[snafu(display("Failed to query procedure state"))]
618 QueryProcedure {
619 #[snafu(implicit)]
620 location: Location,
621 source: common_procedure::Error,
622 },
623
624 #[snafu(display("Procedure not found: {pid}"))]
625 ProcedureNotFound {
626 #[snafu(implicit)]
627 location: Location,
628 pid: String,
629 },
630
631 #[snafu(display("Failed to submit procedure"))]
632 SubmitProcedure {
633 #[snafu(implicit)]
634 location: Location,
635 source: common_procedure::Error,
636 },
637
638 #[snafu(display("A prune task for topic {} is already running", topic))]
639 PruneTaskAlreadyRunning {
640 topic: String,
641 #[snafu(implicit)]
642 location: Location,
643 },
644
645 #[snafu(display("Schema already exists, name: {schema_name}"))]
646 SchemaAlreadyExists {
647 schema_name: String,
648 #[snafu(implicit)]
649 location: Location,
650 },
651
652 #[snafu(display("Table already exists: {table_name}"))]
653 TableAlreadyExists {
654 table_name: String,
655 #[snafu(implicit)]
656 location: Location,
657 },
658
659 #[snafu(display("Pusher not found: {pusher_id}"))]
660 PusherNotFound {
661 pusher_id: String,
662 #[snafu(implicit)]
663 location: Location,
664 },
665
666 #[snafu(display("Failed to push message: {err_msg}"))]
667 PushMessage {
668 err_msg: String,
669 #[snafu(implicit)]
670 location: Location,
671 },
672
673 #[snafu(display("Mailbox already closed: {id}"))]
674 MailboxClosed {
675 id: u64,
676 #[snafu(implicit)]
677 location: Location,
678 },
679
680 #[snafu(display("Mailbox timeout: {id}"))]
681 MailboxTimeout {
682 id: u64,
683 #[snafu(implicit)]
684 location: Location,
685 },
686
687 #[snafu(display("Mailbox receiver got an error: {id}, {err_msg}"))]
688 MailboxReceiver {
689 id: u64,
690 err_msg: String,
691 #[snafu(implicit)]
692 location: Location,
693 },
694
695 #[snafu(display("Mailbox channel closed: {channel}"))]
696 MailboxChannelClosed {
697 channel: Channel,
698 #[snafu(implicit)]
699 location: Location,
700 },
701
702 #[snafu(display("Missing request header"))]
703 MissingRequestHeader {
704 #[snafu(implicit)]
705 location: Location,
706 },
707
708 #[snafu(display("Failed to register procedure loader, type name: {}", type_name))]
709 RegisterProcedureLoader {
710 type_name: String,
711 #[snafu(implicit)]
712 location: Location,
713 source: common_procedure::error::Error,
714 },
715
716 #[snafu(display(
717 "Received unexpected instruction reply, mailbox message: {}, reason: {}",
718 mailbox_message,
719 reason
720 ))]
721 UnexpectedInstructionReply {
722 mailbox_message: String,
723 reason: String,
724 #[snafu(implicit)]
725 location: Location,
726 },
727
728 #[snafu(display("Expected to retry later, reason: {}", reason))]
729 RetryLater {
730 reason: String,
731 #[snafu(implicit)]
732 location: Location,
733 },
734
735 #[snafu(display("Expected to retry later, reason: {}", reason))]
736 RetryLaterWithSource {
737 reason: String,
738 #[snafu(implicit)]
739 location: Location,
740 source: BoxedError,
741 },
742
743 #[snafu(display("Failed to convert proto data"))]
744 ConvertProtoData {
745 #[snafu(implicit)]
746 location: Location,
747 source: common_meta::error::Error,
748 },
749
750 #[snafu(display("Other error"))]
753 Other {
754 source: BoxedError,
755 #[snafu(implicit)]
756 location: Location,
757 },
758
759 #[snafu(display("Table metadata manager error"))]
760 TableMetadataManager {
761 source: common_meta::error::Error,
762 #[snafu(implicit)]
763 location: Location,
764 },
765
766 #[snafu(display("Runtime switch manager error"))]
767 RuntimeSwitchManager {
768 source: common_meta::error::Error,
769 #[snafu(implicit)]
770 location: Location,
771 },
772
773 #[snafu(display("Keyvalue backend error"))]
774 KvBackend {
775 source: common_meta::error::Error,
776 #[snafu(implicit)]
777 location: Location,
778 },
779
780 #[snafu(display("Failed to publish message"))]
781 PublishMessage {
782 #[snafu(source)]
783 error: SendError<Message>,
784 #[snafu(implicit)]
785 location: Location,
786 },
787
788 #[snafu(display("Too many partitions"))]
789 TooManyPartitions {
790 #[snafu(implicit)]
791 location: Location,
792 },
793
794 #[snafu(display("Failed to create repartition subtasks"))]
795 RepartitionCreateSubtasks {
796 source: partition::error::Error,
797 #[snafu(implicit)]
798 location: Location,
799 },
800
801 #[snafu(display("Failed to manage the repartition GC requirement"))]
802 RepartitionGcRequirement {
803 source: common_meta::error::Error,
804 #[snafu(implicit)]
805 location: Location,
806 },
807
808 #[snafu(display("Failed to inspect persisted repartition procedures"))]
809 InspectRepartitionProcedures {
810 source: common_procedure::Error,
811 #[snafu(implicit)]
812 location: Location,
813 },
814
815 #[snafu(display(
816 "Metasrv GC must be enabled because the cluster has durable repartition state"
817 ))]
818 RepartitionGcRequired {
819 #[snafu(implicit)]
820 location: Location,
821 },
822
823 #[snafu(display(
824 "Source partition expression '{}' does not match any existing region",
825 expr
826 ))]
827 RepartitionSourceExprMismatch {
828 expr: String,
829 #[snafu(implicit)]
830 location: Location,
831 },
832
833 #[snafu(display(
834 "Failed to get the state receiver for repartition subprocedure {}",
835 procedure_id
836 ))]
837 RepartitionSubprocedureStateReceiver {
838 procedure_id: ProcedureId,
839 #[snafu(source)]
840 source: common_procedure::Error,
841 #[snafu(implicit)]
842 location: Location,
843 },
844
845 #[snafu(display("Unsupported operation {}", operation))]
846 Unsupported {
847 operation: String,
848 #[snafu(implicit)]
849 location: Location,
850 },
851
852 #[snafu(display("Unexpected table route type: {}", err_msg))]
853 UnexpectedLogicalRouteTable {
854 #[snafu(implicit)]
855 location: Location,
856 err_msg: String,
857 source: common_meta::error::Error,
858 },
859
860 #[snafu(display("Failed to save cluster info"))]
861 SaveClusterInfo {
862 #[snafu(implicit)]
863 location: Location,
864 source: common_meta::error::Error,
865 },
866
867 #[snafu(display("Invalid cluster info format"))]
868 InvalidClusterInfoFormat {
869 #[snafu(implicit)]
870 location: Location,
871 source: common_meta::error::Error,
872 },
873
874 #[snafu(display("Invalid datanode stat format"))]
875 InvalidDatanodeStatFormat {
876 #[snafu(implicit)]
877 location: Location,
878 source: common_meta::error::Error,
879 },
880
881 #[snafu(display("Invalid node info format"))]
882 InvalidNodeInfoFormat {
883 #[snafu(implicit)]
884 location: Location,
885 source: common_meta::error::Error,
886 },
887
888 #[snafu(display("Failed to serialize options to TOML"))]
889 TomlFormat {
890 #[snafu(implicit)]
891 location: Location,
892 #[snafu(source(from(common_config::error::Error, Box::new)))]
893 source: Box<common_config::error::Error>,
894 },
895
896 #[cfg(feature = "pg_kvbackend")]
897 #[snafu(display("Failed to execute via postgres, sql: {}", sql))]
898 PostgresExecution {
899 #[snafu(source)]
900 error: tokio_postgres::Error,
901 sql: String,
902 #[snafu(implicit)]
903 location: Location,
904 },
905
906 #[cfg(feature = "pg_kvbackend")]
907 #[snafu(display("Failed to get Postgres client"))]
908 GetPostgresClient {
909 #[snafu(implicit)]
910 location: Location,
911 #[snafu(source)]
912 error: deadpool::managed::PoolError<tokio_postgres::Error>,
913 },
914
915 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
916 #[snafu(display("Sql execution timeout, sql: {}, duration: {:?}", sql, duration))]
917 SqlExecutionTimeout {
918 #[snafu(implicit)]
919 location: Location,
920 sql: String,
921 duration: std::time::Duration,
922 },
923
924 #[cfg(feature = "pg_kvbackend")]
925 #[snafu(display("Failed to create connection pool for Postgres"))]
926 CreatePostgresPool {
927 #[snafu(source)]
928 error: deadpool_postgres::CreatePoolError,
929 #[snafu(implicit)]
930 location: Location,
931 },
932
933 #[cfg(feature = "pg_kvbackend")]
934 #[snafu(display("Failed to get connection from Postgres pool: {}", reason))]
935 GetPostgresConnection {
936 reason: String,
937 #[snafu(implicit)]
938 location: Location,
939 },
940
941 #[cfg(feature = "mysql_kvbackend")]
942 #[snafu(display("Failed to execute via mysql, sql: {}", sql))]
943 MySqlExecution {
944 #[snafu(source)]
945 error: sqlx::Error,
946 #[snafu(implicit)]
947 location: Location,
948 sql: String,
949 },
950
951 #[cfg(feature = "mysql_kvbackend")]
952 #[snafu(display("Failed to create mysql pool"))]
953 CreateMySqlPool {
954 #[snafu(source)]
955 error: sqlx::Error,
956 #[snafu(implicit)]
957 location: Location,
958 },
959
960 #[cfg(feature = "mysql_kvbackend")]
961 #[snafu(display("Failed to acquire mysql client from pool"))]
962 AcquireMySqlClient {
963 #[snafu(source)]
964 error: sqlx::Error,
965 #[snafu(implicit)]
966 location: Location,
967 },
968
969 #[snafu(display("Handler not found: {}", name))]
970 HandlerNotFound {
971 name: String,
972 #[snafu(implicit)]
973 location: Location,
974 },
975
976 #[snafu(display("Flow state handler error"))]
977 FlowStateHandler {
978 #[snafu(implicit)]
979 location: Location,
980 source: common_meta::error::Error,
981 },
982
983 #[snafu(display("Failed to build wal provider"))]
984 BuildWalProvider {
985 #[snafu(implicit)]
986 location: Location,
987 source: common_meta::error::Error,
988 },
989
990 #[snafu(display("Failed to build kafka client."))]
991 BuildKafkaClient {
992 #[snafu(implicit)]
993 location: Location,
994 #[snafu(source)]
995 error: common_meta::error::Error,
996 },
997
998 #[snafu(display(
999 "Failed to build a Kafka partition client, topic: {}, partition: {}",
1000 topic,
1001 partition
1002 ))]
1003 BuildPartitionClient {
1004 topic: String,
1005 partition: i32,
1006 #[snafu(implicit)]
1007 location: Location,
1008 #[snafu(source)]
1009 error: rskafka::client::error::Error,
1010 },
1011
1012 #[snafu(display(
1013 "Failed to delete records from Kafka, topic: {}, partition: {}, offset: {}",
1014 topic,
1015 partition,
1016 offset
1017 ))]
1018 DeleteRecords {
1019 #[snafu(implicit)]
1020 location: Location,
1021 #[snafu(source)]
1022 error: rskafka::client::error::Error,
1023 topic: String,
1024 partition: i32,
1025 offset: u64,
1026 },
1027
1028 #[snafu(display("Failed to get offset from Kafka, topic: {}", topic))]
1029 GetOffset {
1030 topic: String,
1031 #[snafu(implicit)]
1032 location: Location,
1033 #[snafu(source)]
1034 error: rskafka::client::error::Error,
1035 },
1036
1037 #[snafu(display("Failed to update the TopicNameValue in kvbackend, topic: {}", topic))]
1038 UpdateTopicNameValue {
1039 topic: String,
1040 #[snafu(implicit)]
1041 location: Location,
1042 #[snafu(source)]
1043 source: common_meta::error::Error,
1044 },
1045
1046 #[snafu(display("Failed to build tls options"))]
1047 BuildTlsOptions {
1048 #[snafu(implicit)]
1049 location: Location,
1050 #[snafu(source)]
1051 source: common_meta::error::Error,
1052 },
1053
1054 #[snafu(display(
1055 "Repartition group {} source region missing, region id: {}",
1056 group_id,
1057 region_id
1058 ))]
1059 RepartitionSourceRegionMissing {
1060 group_id: Uuid,
1061 region_id: RegionId,
1062 #[snafu(implicit)]
1063 location: Location,
1064 },
1065
1066 #[snafu(display(
1067 "Repartition group {} target region missing, region id: {}",
1068 group_id,
1069 region_id
1070 ))]
1071 RepartitionTargetRegionMissing {
1072 group_id: Uuid,
1073 region_id: RegionId,
1074 #[snafu(implicit)]
1075 location: Location,
1076 },
1077
1078 #[snafu(display("Failed to serialize partition expression"))]
1079 SerializePartitionExpr {
1080 #[snafu(source)]
1081 source: partition::error::Error,
1082 #[snafu(implicit)]
1083 location: Location,
1084 },
1085
1086 #[snafu(display("Failed to deserialize partition expression"))]
1087 DeserializePartitionExpr {
1088 #[snafu(source)]
1089 source: partition::error::Error,
1090 #[snafu(implicit)]
1091 location: Location,
1092 },
1093
1094 #[snafu(display("Empty partition expression"))]
1095 EmptyPartitionExpr {
1096 #[snafu(implicit)]
1097 location: Location,
1098 },
1099
1100 #[snafu(display(
1101 "Partition expression mismatch, region id: {}, expected: {}, actual: {}",
1102 region_id,
1103 expected,
1104 actual
1105 ))]
1106 PartitionExprMismatch {
1107 region_id: RegionId,
1108 expected: String,
1109 actual: String,
1110 #[snafu(implicit)]
1111 location: Location,
1112 },
1113
1114 #[snafu(display("Failed to allocate regions for table: {}", table_id))]
1115 AllocateRegions {
1116 #[snafu(implicit)]
1117 location: Location,
1118 table_id: TableId,
1119 #[snafu(source)]
1120 source: common_meta::error::Error,
1121 },
1122
1123 #[snafu(display("Failed to deallocate regions for table: {}", table_id))]
1124 DeallocateRegions {
1125 #[snafu(implicit)]
1126 location: Location,
1127 table_id: TableId,
1128 #[snafu(source)]
1129 source: common_meta::error::Error,
1130 },
1131
1132 #[snafu(display("Failed to build create request for table: {}", table_id))]
1133 BuildCreateRequest {
1134 #[snafu(implicit)]
1135 location: Location,
1136 table_id: TableId,
1137 #[snafu(source)]
1138 source: common_meta::error::Error,
1139 },
1140
1141 #[snafu(display("Failed to allocate region routes for table: {}", table_id))]
1142 AllocateRegionRoutes {
1143 #[snafu(implicit)]
1144 location: Location,
1145 table_id: TableId,
1146 #[snafu(source)]
1147 source: common_meta::error::Error,
1148 },
1149
1150 #[snafu(display("Failed to allocate wal options for table: {}", table_id))]
1151 AllocateWalOptions {
1152 #[snafu(implicit)]
1153 location: Location,
1154 table_id: TableId,
1155 #[snafu(source)]
1156 source: common_meta::error::Error,
1157 },
1158}
1159
1160impl Error {
1161 pub fn is_retryable(&self) -> bool {
1163 self.retry_hint().is_retryable()
1164 }
1165}
1166
1167pub type Result<T> = std::result::Result<T, Error>;
1168
1169define_into_tonic_status!(Error);
1170
1171impl ErrorExt for Error {
1172 fn status_code(&self) -> StatusCode {
1173 match self {
1174 Error::EtcdFailed { .. }
1175 | Error::ConnectEtcd { .. }
1176 | Error::FileIo { .. }
1177 | Error::TcpBind { .. }
1178 | Error::SerializeConfig { .. }
1179 | Error::SerializeToJson { .. }
1180 | Error::DeserializeFromJson { .. }
1181 | Error::NoLeader { .. }
1182 | Error::LeaderLeaseExpired { .. }
1183 | Error::LeaderLeaseChanged { .. }
1184 | Error::CreateChannel { .. }
1185 | Error::BatchGet { .. }
1186 | Error::Range { .. }
1187 | Error::ResponseHeaderNotFound { .. }
1188 | Error::InvalidHttpBody { .. }
1189 | Error::ExceededRetryLimit { .. }
1190 | Error::SendShutdownSignal { .. }
1191 | Error::PushMessage { .. }
1192 | Error::MailboxClosed { .. }
1193 | Error::MailboxReceiver { .. }
1194 | Error::StartGrpc { .. }
1195 | Error::PublishMessage { .. }
1196 | Error::Join { .. }
1197 | Error::ChooseItems { .. }
1198 | Error::FlowStateHandler { .. }
1199 | Error::BuildWalProvider { .. }
1200 | Error::BuildPartitionClient { .. }
1201 | Error::BuildKafkaClient { .. } => StatusCode::Internal,
1202
1203 Error::DeleteRecords { .. }
1204 | Error::GetOffset { .. }
1205 | Error::PeerUnavailable { .. }
1206 | Error::PusherNotFound { .. } => StatusCode::Unexpected,
1207 Error::MailboxTimeout { .. } | Error::ExceededDeadline { .. } => StatusCode::Cancelled,
1208 Error::PruneTaskAlreadyRunning { .. }
1209 | Error::RetryLater { .. }
1210 | Error::MailboxChannelClosed { .. }
1211 | Error::IsNotLeader { .. } => StatusCode::IllegalState,
1212 Error::RetryLaterWithSource { source, .. } => source.status_code(),
1213 Error::SerializePartitionExpr { source, .. }
1214 | Error::DeserializePartitionExpr { source, .. } => source.status_code(),
1215
1216 Error::Unsupported { .. } => StatusCode::Unsupported,
1217
1218 Error::SchemaAlreadyExists { .. } => StatusCode::DatabaseAlreadyExists,
1219
1220 Error::TableAlreadyExists { .. } => StatusCode::TableAlreadyExists,
1221 Error::EmptyKey { .. }
1222 | Error::MissingRequiredParameter { .. }
1223 | Error::MissingRequestHeader { .. }
1224 | Error::InvalidLeaseKey { .. }
1225 | Error::InvalidStatKey { .. }
1226 | Error::InvalidInactiveRegionKey { .. }
1227 | Error::InvalidNodeSchedulingKey { .. }
1228 | Error::ParseNum { .. }
1229 | Error::ParseBool { .. }
1230 | Error::ParseAddr { .. }
1231 | Error::UnsupportedSelectorType { .. }
1232 | Error::InvalidArguments { .. }
1233 | Error::ManualGcRejectedByMaintenanceMode { .. }
1234 | Error::ProcedureNotFound { .. }
1235 | Error::TooManyPartitions { .. }
1236 | Error::TomlFormat { .. }
1237 | Error::HandlerNotFound { .. }
1238 | Error::LeaderPeerChanged { .. }
1239 | Error::RepartitionSourceRegionMissing { .. }
1240 | Error::RepartitionTargetRegionMissing { .. }
1241 | Error::PartitionExprMismatch { .. }
1242 | Error::RepartitionSourceExprMismatch { .. }
1243 | Error::EmptyPartitionExpr { .. } => StatusCode::InvalidArguments,
1244 Error::LeaseKeyFromUtf8 { .. }
1245 | Error::LeaseValueFromUtf8 { .. }
1246 | Error::InvalidRegionKeyFromUtf8 { .. }
1247 | Error::TableRouteNotFound { .. }
1248 | Error::TableInfoNotFound { .. }
1249 | Error::DatanodeTableNotFound { .. }
1250 | Error::InvalidUtf8Value { .. }
1251 | Error::UnexpectedInstructionReply { .. }
1252 | Error::Unexpected { .. }
1253 | Error::RegionOperatingRace { .. }
1254 | Error::RegionRouteNotFound { .. }
1255 | Error::MigrationAbort { .. }
1256 | Error::MigrationRunning { .. }
1257 | Error::RegionMigrated { .. } => StatusCode::Unexpected,
1258 Error::TableNotFound { .. } => StatusCode::TableNotFound,
1259 Error::SaveClusterInfo { source, .. }
1260 | Error::InvalidClusterInfoFormat { source, .. }
1261 | Error::InvalidDatanodeStatFormat { source, .. }
1262 | Error::InvalidNodeInfoFormat { source, .. } => source.status_code(),
1263 Error::InvalidateTableCache { source, .. } => source.status_code(),
1264 Error::SubmitProcedure { source, .. }
1265 | Error::WaitProcedure { source, .. }
1266 | Error::QueryProcedure { source, .. } => source.status_code(),
1267 Error::ShutdownServer { source, .. } | Error::StartHttp { source, .. } => {
1268 source.status_code()
1269 }
1270 Error::StartProcedureManager { source, .. }
1271 | Error::StopProcedureManager { source, .. } => source.status_code(),
1272
1273 Error::ListCatalogs { source, .. }
1274 | Error::ListSchemas { source, .. }
1275 | Error::ListTables { source, .. } => source.status_code(),
1276 Error::StartTelemetryTask { source, .. } => source.status_code(),
1277
1278 Error::NextSequence { source, .. }
1279 | Error::SetNextSequence { source, .. }
1280 | Error::PeekSequence { source, .. } => source.status_code(),
1281 Error::DowngradeLeader { source, .. } => source.status_code(),
1282 Error::RegisterProcedureLoader { source, .. } => source.status_code(),
1283 Error::SubmitDdlTask { source, .. }
1284 | Error::SubmitReconcileProcedure { source, .. } => source.status_code(),
1285 Error::ConvertProtoData { source, .. }
1286 | Error::TableMetadataManager { source, .. }
1287 | Error::RuntimeSwitchManager { source, .. }
1288 | Error::KvBackend { source, .. }
1289 | Error::UnexpectedLogicalRouteTable { source, .. }
1290 | Error::UpdateTopicNameValue { source, .. } => source.status_code(),
1291 Error::ListActiveFrontends { source, .. }
1292 | Error::ListActiveDatanodes { source, .. }
1293 | Error::ListActiveFlownodes { source, .. } => source.status_code(),
1294 Error::NoAvailableFrontend { .. } | Error::RepartitionGcRequired { .. } => {
1295 StatusCode::IllegalState
1296 }
1297
1298 Error::InitMetadata { source, .. }
1299 | Error::InitDdlManager { source, .. }
1300 | Error::InitReconciliationManager { source, .. } => source.status_code(),
1301
1302 Error::BuildTlsOptions { source, .. } => source.status_code(),
1303 Error::Other { source, .. } => source.status_code(),
1304 Error::RepartitionCreateSubtasks { source, .. } => source.status_code(),
1305 Error::RepartitionGcRequirement { source, .. } => source.status_code(),
1306 Error::InspectRepartitionProcedures { source, .. } => source.status_code(),
1307 Error::RepartitionSubprocedureStateReceiver { source, .. } => source.status_code(),
1308 Error::AllocateRegions { source, .. } => source.status_code(),
1309 Error::DeallocateRegions { source, .. } => source.status_code(),
1310 Error::AllocateRegionRoutes { source, .. } => source.status_code(),
1311 Error::AllocateWalOptions { source, .. } => source.status_code(),
1312 Error::BuildCreateRequest { source, .. } => source.status_code(),
1313 Error::NoEnoughAvailableNode { .. } => StatusCode::RuntimeResourcesExhausted,
1314
1315 #[cfg(feature = "pg_kvbackend")]
1316 Error::CreatePostgresPool { .. }
1317 | Error::GetPostgresClient { .. }
1318 | Error::GetPostgresConnection { .. }
1319 | Error::PostgresExecution { .. } => StatusCode::Internal,
1320 #[cfg(feature = "mysql_kvbackend")]
1321 Error::MySqlExecution { .. }
1322 | Error::CreateMySqlPool { .. }
1323 | Error::ParseMySqlUrl { .. }
1324 | Error::DecodeSqlValue { .. }
1325 | Error::AcquireMySqlClient { .. } => StatusCode::Internal,
1326 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1327 Error::SqlExecutionTimeout { .. } => StatusCode::Internal,
1328 }
1329 }
1330
1331 fn as_any(&self) -> &dyn std::any::Any {
1332 self
1333 }
1334
1335 fn retry_hint(&self) -> RetryHint {
1336 match self {
1337 Error::RetryLater { .. }
1338 | Error::RetryLaterWithSource { .. }
1339 | Error::MailboxTimeout { .. }
1340 | Error::NoEnoughAvailableNode { .. }
1341 | Error::NoLeader { .. }
1342 | Error::LeaderLeaseExpired { .. }
1343 | Error::LeaderLeaseChanged { .. }
1344 | Error::PeerUnavailable { .. } => RetryHint::Retryable,
1345
1346 Error::ConnectEtcd { error, .. } | Error::EtcdFailed { error, .. } => {
1347 common_meta::error::retry_hint_from_etcd_error(error)
1348 }
1349
1350 #[cfg(feature = "pg_kvbackend")]
1351 Error::PostgresExecution { error, .. } => {
1352 common_meta::error::retry_hint_from_postgres_error(error)
1353 }
1354 #[cfg(feature = "pg_kvbackend")]
1355 Error::GetPostgresClient { error, .. } => {
1356 common_meta::error::retry_hint_from_postgres_pool_error(error)
1357 }
1358 #[cfg(feature = "mysql_kvbackend")]
1359 Error::MySqlExecution { error, .. }
1360 | Error::CreateMySqlPool { error, .. }
1361 | Error::AcquireMySqlClient { error, .. } => {
1362 common_meta::error::retry_hint_from_sqlx_error(error)
1363 }
1364 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1365 Error::SqlExecutionTimeout { .. } => RetryHint::Retryable,
1366
1367 Error::ListActiveFrontends { source, .. }
1368 | Error::ListActiveDatanodes { source, .. }
1369 | Error::ListActiveFlownodes { source, .. }
1370 | Error::InitDdlManager { source, .. }
1371 | Error::InitReconciliationManager { source, .. }
1372 | Error::InitMetadata { source, .. }
1373 | Error::NextSequence { source, .. }
1374 | Error::SetNextSequence { source, .. }
1375 | Error::PeekSequence { source, .. }
1376 | Error::SubmitDdlTask { source, .. }
1377 | Error::SubmitReconcileProcedure { source, .. }
1378 | Error::InvalidateTableCache { source, .. }
1379 | Error::ConvertProtoData { source, .. }
1380 | Error::TableMetadataManager { source, .. }
1381 | Error::RuntimeSwitchManager { source, .. }
1382 | Error::KvBackend { source, .. }
1383 | Error::UnexpectedLogicalRouteTable { source, .. }
1384 | Error::SaveClusterInfo { source, .. }
1385 | Error::InvalidClusterInfoFormat { source, .. }
1386 | Error::InvalidDatanodeStatFormat { source, .. }
1387 | Error::InvalidNodeInfoFormat { source, .. }
1388 | Error::FlowStateHandler { source, .. }
1389 | Error::BuildWalProvider { source, .. }
1390 | Error::BuildKafkaClient { error: source, .. }
1391 | Error::UpdateTopicNameValue { source, .. }
1392 | Error::BuildTlsOptions { source, .. }
1393 | Error::AllocateRegions { source, .. }
1394 | Error::DeallocateRegions { source, .. }
1395 | Error::BuildCreateRequest { source, .. }
1396 | Error::AllocateRegionRoutes { source, .. }
1397 | Error::AllocateWalOptions { source, .. }
1398 | Error::RepartitionGcRequirement { source, .. } => source.retry_hint(),
1399
1400 Error::Other { source, .. }
1401 | Error::ListCatalogs { source, .. }
1402 | Error::ListSchemas { source, .. }
1403 | Error::ListTables { source, .. }
1404 | Error::DowngradeLeader { source, .. } => source.retry_hint(),
1405
1406 Error::SubmitProcedure { source, .. }
1407 | Error::WaitProcedure { source, .. }
1408 | Error::QueryProcedure { source, .. }
1409 | Error::StartProcedureManager { source, .. }
1410 | Error::StopProcedureManager { source, .. }
1411 | Error::RegisterProcedureLoader { source, .. }
1412 | Error::InspectRepartitionProcedures { source, .. }
1413 | Error::RepartitionSubprocedureStateReceiver { source, .. } => source.retry_hint(),
1414
1415 Error::ShutdownServer { source, .. } | Error::StartHttp { source, .. } => {
1416 source.retry_hint()
1417 }
1418 Error::StartTelemetryTask { source, .. } => source.retry_hint(),
1419 Error::CreateChannel { source, .. } => source.retry_hint(),
1420 Error::RepartitionCreateSubtasks { source, .. } => source.retry_hint(),
1421 Error::SerializePartitionExpr { source, .. }
1422 | Error::DeserializePartitionExpr { source, .. } => source.retry_hint(),
1423
1424 Error::DeleteRecords { error, .. }
1425 | Error::BuildPartitionClient { error, .. }
1426 | Error::GetOffset { error, .. } => rskafka_client_error_to_retry_hint(error),
1427
1428 Error::PusherNotFound { .. }
1429 | Error::PushMessage { .. }
1430 | Error::ExceededDeadline { .. } => RetryHint::NonRetryable,
1431
1432 _ => RetryHint::NonRetryable,
1433 }
1434 }
1435}
1436
1437pub(crate) fn match_for_io_error(err_status: &tonic::Status) -> Option<&std::io::Error> {
1439 let mut err: &(dyn std::error::Error + 'static) = err_status;
1440
1441 loop {
1442 if let Some(io_err) = err.downcast_ref::<std::io::Error>() {
1443 return Some(io_err);
1444 }
1445
1446 if let Some(h2_err) = err.downcast_ref::<h2::Error>()
1449 && let Some(io_err) = h2_err.get_io()
1450 {
1451 return Some(io_err);
1452 }
1453
1454 err = err.source()?;
1455 }
1456}
1457
1458#[cfg(test)]
1459mod tests {
1460 use std::time::Duration;
1461
1462 use common_error::ext::ErrorExt;
1463 use common_error::mock::MockError;
1464 use common_error::status_code::StatusCode;
1465 use rskafka::BackoffError;
1466 use rskafka::client::error::Error as KafkaClientError;
1467 use snafu::ResultExt;
1468
1469 use super::{
1470 BuildPartitionClientSnafu, DeallocateRegionsSnafu, DeleteRecordsSnafu, GetOffsetSnafu,
1471 };
1472
1473 fn retry_failed_kafka_error() -> KafkaClientError {
1474 KafkaClientError::RetryFailed(BackoffError::DeadlineExceded {
1475 deadline: Duration::from_secs(1),
1476 source: Box::new(std::io::Error::other("retry failed")),
1477 })
1478 }
1479
1480 #[test]
1481 fn test_deallocate_regions_is_retryable_when_source_is_retry_later() {
1482 let source = common_meta::error::Error::retry_later(MockError::new(StatusCode::Internal));
1483 let err = Err::<(), _>(source)
1484 .context(DeallocateRegionsSnafu { table_id: 1024_u32 })
1485 .unwrap_err();
1486
1487 assert!(err.is_retryable());
1488 assert!(err.retry_hint().is_retryable());
1489 }
1490
1491 #[test]
1492 fn test_deallocate_regions_is_not_retryable_when_source_is_not_retry_later() {
1493 let source = common_meta::error::UnexpectedSnafu {
1494 err_msg: "mock error",
1495 }
1496 .build();
1497 let err = Err::<(), _>(source)
1498 .context(DeallocateRegionsSnafu { table_id: 1024_u32 })
1499 .unwrap_err();
1500
1501 assert!(!err.is_retryable());
1502 assert!(!err.retry_hint().is_retryable());
1503 }
1504
1505 #[test]
1506 fn test_kafka_retry_failed_errors_are_retryable() {
1507 let delete_records_err = Err::<(), _>(retry_failed_kafka_error())
1508 .context(DeleteRecordsSnafu {
1509 topic: "test_topic",
1510 partition: 0,
1511 offset: 1024u64,
1512 })
1513 .unwrap_err();
1514 let build_partition_client_err = Err::<(), _>(retry_failed_kafka_error())
1515 .context(BuildPartitionClientSnafu {
1516 topic: "test_topic",
1517 partition: 0,
1518 })
1519 .unwrap_err();
1520 let get_offset_err = Err::<(), _>(retry_failed_kafka_error())
1521 .context(GetOffsetSnafu {
1522 topic: "test_topic",
1523 })
1524 .unwrap_err();
1525
1526 assert!(delete_records_err.is_retryable());
1527 assert!(build_partition_client_err.is_retryable());
1528 assert!(get_offset_err.is_retryable());
1529 assert!(delete_records_err.retry_hint().is_retryable());
1530 assert!(build_partition_client_err.retry_hint().is_retryable());
1531 assert!(get_offset_err.retry_hint().is_retryable());
1532 }
1533
1534 #[test]
1535 fn test_kafka_non_retry_failed_errors_are_not_retryable() {
1536 let delete_records_err = Err::<(), _>(KafkaClientError::InvalidResponse("invalid".into()))
1537 .context(DeleteRecordsSnafu {
1538 topic: "test_topic",
1539 partition: 0,
1540 offset: 1024u64,
1541 })
1542 .unwrap_err();
1543 let build_partition_client_err =
1544 Err::<(), _>(KafkaClientError::InvalidResponse("invalid".into()))
1545 .context(BuildPartitionClientSnafu {
1546 topic: "test_topic",
1547 partition: 0,
1548 })
1549 .unwrap_err();
1550 let get_offset_err = Err::<(), _>(KafkaClientError::InvalidResponse("invalid".into()))
1551 .context(GetOffsetSnafu {
1552 topic: "test_topic",
1553 })
1554 .unwrap_err();
1555
1556 assert!(!delete_records_err.is_retryable());
1557 assert!(!build_partition_client_err.is_retryable());
1558 assert!(!get_offset_err.is_retryable());
1559 assert!(!delete_records_err.retry_hint().is_retryable());
1560 assert!(!build_partition_client_err.retry_hint().is_retryable());
1561 assert!(!get_offset_err.retry_hint().is_retryable());
1562 }
1563}