File tree Expand file tree Collapse file tree 3 files changed +47
-0
lines changed Expand file tree Collapse file tree 3 files changed +47
-0
lines changed Original file line number Diff line number Diff line change @@ -2,6 +2,7 @@ use crate::{
2
2
builders:: CrateBuilder ,
3
3
util:: { MockAnonymousUser , RequestHelper , TestApp } ,
4
4
} ;
5
+ use http:: StatusCode ;
5
6
use std:: time:: Duration ;
6
7
7
8
#[ test]
@@ -64,3 +65,25 @@ fn assert_unconditional_redirects(anon: &MockAnonymousUser) {
64
65
anon. get :: < ( ) > ( "/api/v1/crates/awesome-project/1.0.0/download" )
65
66
. assert_redirect_ends_with ( "/awesome-project/awesome-project-1.0.0.crate" ) ;
66
67
}
68
+
69
+ #[ test]
70
+ fn http_error_with_unhealthy_database ( ) {
71
+ let ( app, anon) = TestApp :: init ( ) . with_slow_real_db_pool ( ) . empty ( ) ;
72
+
73
+ let response = anon. get :: < ( ) > ( "/api/v1/summary" ) ;
74
+ assert_eq ! ( response. status( ) , StatusCode :: OK ) ;
75
+
76
+ app. db_chaosproxy ( ) . break_networking ( ) ;
77
+
78
+ let response = anon. get :: < ( ) > ( "/api/v1/summary" ) ;
79
+ assert_eq ! ( response. status( ) , StatusCode :: SERVICE_UNAVAILABLE ) ;
80
+
81
+ app. db_chaosproxy ( ) . restore_networking ( ) ;
82
+ app. as_inner ( )
83
+ . primary_database
84
+ . wait_until_healthy ( Duration :: from_millis ( 500 ) )
85
+ . expect ( "the database did not return healthy" ) ;
86
+
87
+ let response = anon. get :: < ( ) > ( "/api/v1/summary" ) ;
88
+ assert_eq ! ( response. status( ) , StatusCode :: OK ) ;
89
+ }
Original file line number Diff line number Diff line change @@ -20,6 +20,7 @@ use std::fmt;
20
20
use chrono:: NaiveDateTime ;
21
21
use diesel:: result:: Error as DieselError ;
22
22
23
+ use crate :: db:: PoolError ;
23
24
use crate :: util:: AppResponse ;
24
25
25
26
mod json;
@@ -69,6 +70,11 @@ pub fn server_error<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
69
70
Box :: new ( json:: ServerError ( error. to_string ( ) ) )
70
71
}
71
72
73
+ /// Returns an error with status 503 and the provided description as JSON
74
+ pub fn service_unavailable < S : ToString + ?Sized > ( error : & S ) -> Box < dyn AppError > {
75
+ Box :: new ( json:: ServiceUnavailable ( error. to_string ( ) ) )
76
+ }
77
+
72
78
// =============================================================================
73
79
// AppError trait
74
80
@@ -111,6 +117,10 @@ impl dyn AppError {
111
117
}
112
118
113
119
fn try_convert ( err : & ( dyn Error + Send + ' static ) ) -> Option < Box < Self > > {
120
+ if matches ! ( err. downcast_ref( ) , Some ( PoolError :: UnhealthyPool ) ) {
121
+ return Some ( service_unavailable ( "Service unavailable" ) ) ;
122
+ }
123
+
114
124
match err. downcast_ref ( ) {
115
125
Some ( DieselError :: NotFound ) => Some ( not_found ( ) ) ,
116
126
Some ( DieselError :: DatabaseError ( _, info) )
Original file line number Diff line number Diff line change @@ -80,6 +80,8 @@ pub(super) struct BadRequest(pub(super) String);
80
80
#[ derive( Debug ) ]
81
81
pub ( super ) struct ServerError ( pub ( super ) String ) ;
82
82
#[ derive( Debug ) ]
83
+ pub ( crate ) struct ServiceUnavailable ( pub ( super ) String ) ;
84
+ #[ derive( Debug ) ]
83
85
pub ( crate ) struct TooManyRequests {
84
86
pub retry_after : NaiveDateTime ,
85
87
}
@@ -120,6 +122,18 @@ impl fmt::Display for ServerError {
120
122
}
121
123
}
122
124
125
+ impl AppError for ServiceUnavailable {
126
+ fn response ( & self ) -> Option < AppResponse > {
127
+ Some ( json_error ( & self . 0 , StatusCode :: SERVICE_UNAVAILABLE ) )
128
+ }
129
+ }
130
+
131
+ impl fmt:: Display for ServiceUnavailable {
132
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
133
+ self . 0 . fmt ( f)
134
+ }
135
+ }
136
+
123
137
impl AppError for TooManyRequests {
124
138
fn response ( & self ) -> Option < AppResponse > {
125
139
use std:: convert:: TryInto ;
You can’t perform that action at this time.
0 commit comments