11use std:: {
22 collections:: HashMap ,
3- fmt:: Debug ,
3+ fmt:: { Debug , Display } ,
44 sync:: Arc ,
55 time:: { Duration , Instant } ,
66} ;
@@ -168,11 +168,30 @@ pub enum ValueForRender<Loader: CacheLoader> {
168168 /// Error while loading the value
169169 Error {
170170 message : Arc < str > ,
171+ status : StatusCode ,
171172 /// If there's a cached value available that's considered stale, provide it here.
172173 stale_cache : Option < Latest < Loader > > ,
173174 } ,
174175}
175176
177+ /// An error type that wraps up a [axum::Response].
178+ ///
179+ /// If you return this as an error value from [CacheLoader::load],
180+ /// it will be used as the error response.
181+ #[ derive( Clone , Debug ) ]
182+ pub struct ErrorResponse {
183+ pub status : StatusCode ,
184+ pub message : String ,
185+ }
186+
187+ impl std:: error:: Error for ErrorResponse { }
188+
189+ impl Display for ErrorResponse {
190+ fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
191+ f. write_str ( & self . message )
192+ }
193+ }
194+
176195impl < Loader : CacheLoader > Clone for ValueForRender < Loader > {
177196 fn clone ( & self ) -> Self {
178197 match self {
@@ -182,9 +201,11 @@ impl<Loader: CacheLoader> Clone for ValueForRender<Loader> {
182201 } ,
183202 ValueForRender :: Error {
184203 message,
204+ status,
185205 stale_cache,
186206 } => ValueForRender :: Error {
187207 message : message. clone ( ) ,
208+ status : * status,
188209 stale_cache : stale_cache. clone ( ) ,
189210 } ,
190211 }
@@ -210,12 +231,9 @@ impl<Loader: CacheLoader> ValueForRender<Loader> {
210231 }
211232 ValueForRender :: Error {
212233 message,
234+ status,
213235 stale_cache : _,
214- } => {
215- let mut res = message. as_ref ( ) . to_owned ( ) . into_response ( ) ;
216- * res. status_mut ( ) = StatusCode :: INTERNAL_SERVER_ERROR ;
217- res
218- }
236+ } => ( status, message. as_ref ( ) . to_owned ( ) ) . into_response ( ) ,
219237 }
220238 }
221239}
@@ -336,6 +354,7 @@ impl<Loader: CacheLoader> AsyncLoader<Loader> {
336354 tracing:: error!( "AsyncLoader::get_response: impossible Err received: {err:?}" ) ;
337355 ValueForRender :: Error {
338356 message : "Internal error detected: broadcast channel is gone" . into ( ) ,
357+ status : StatusCode :: INTERNAL_SERVER_ERROR ,
339358 stale_cache,
340359 }
341360 }
@@ -369,6 +388,7 @@ impl<Loader: CacheLoader> AsyncLoader<Loader> {
369388 tracing:: error!( "AsyncLoader::get_response: impossible Err received: {err:?}" ) ;
370389 ValueForRender :: Error {
371390 message : "Internal error detected: broadcast channel is gone" . into ( ) ,
391+ status : StatusCode :: INTERNAL_SERVER_ERROR ,
372392 stale_cache,
373393 }
374394 }
@@ -410,6 +430,7 @@ impl<Loader: CacheLoader> AsyncLoader<Loader> {
410430 ValueForRender :: Success { value, loaded : _ } => Ok ( value) ,
411431 ValueForRender :: Error {
412432 message,
433+ status : _,
413434 stale_cache,
414435 } => match stale_cache {
415436 Some ( latest) => Ok ( latest. value ) ,
@@ -490,6 +511,7 @@ impl<Loader: CacheLoader> AsyncLoader<Loader> {
490511 } ) ,
491512 ValueForRender :: Error {
492513 message : _,
514+ status : _,
493515 stale_cache,
494516 } => stale_cache. clone ( ) ,
495517 } ;
@@ -571,8 +593,13 @@ impl<Loader: CacheLoader> AsyncLoader<Loader> {
571593 } ,
572594 Err ( err) => {
573595 tracing:: error!( "AsyncLoader::do_update: {err:?}" ) ;
596+ let ( message, status) = match err. downcast ( ) {
597+ Ok ( ErrorResponse { status, message } ) => ( message, status) ,
598+ Err ( err) => ( err. to_string ( ) , StatusCode :: INTERNAL_SERVER_ERROR ) ,
599+ } ;
574600 ValueForRender :: Error {
575- message : err. to_string ( ) . into ( ) ,
601+ message : message. into ( ) ,
602+ status,
576603 stale_cache,
577604 }
578605 }
0 commit comments