@@ -91,11 +91,14 @@ impl<Event, NextState, CurrentState, Err>
9191}
9292
9393/// A transition that can be either fatal, transient, or a state transition.
94- pub struct MaybeFatalTransition < Event , NextState , Err > (
95- pub ( crate ) Result < AcceptNextState < Event , NextState > , Rejection < Event , Err > > ,
94+ pub struct MaybeFatalTransition < Event , NextState , Err , ErrorState = ( ) > (
95+ pub ( crate ) Result < AcceptNextState < Event , NextState > , Rejection < Event , Err , ErrorState > > ,
9696) ;
9797
98- impl < Event , NextState , Err > MaybeFatalTransition < Event , NextState , Err > {
98+ impl < Event , NextState , Err , ErrorState > MaybeFatalTransition < Event , NextState , Err , ErrorState >
99+ where
100+ ErrorState : fmt:: Debug ,
101+ {
99102 #[ inline]
100103 pub ( crate ) fn fatal ( event : Event , error : Err ) -> Self {
101104 MaybeFatalTransition ( Err ( Rejection :: fatal ( event, error) ) )
@@ -111,10 +114,15 @@ impl<Event, NextState, Err> MaybeFatalTransition<Event, NextState, Err> {
111114 MaybeFatalTransition ( Ok ( AcceptNextState ( event, next_state) ) )
112115 }
113116
117+ #[ inline]
118+ pub ( crate ) fn replyable_error ( event : Event , error_state : ErrorState , error : Err ) -> Self {
119+ MaybeFatalTransition ( Err ( Rejection :: replyable_error ( event, error_state, error) ) )
120+ }
121+
114122 pub fn save < P > (
115123 self ,
116124 persister : & P ,
117- ) -> Result < NextState , PersistedError < Err , P :: InternalStorageError > >
125+ ) -> Result < NextState , PersistedError < Err , P :: InternalStorageError , ErrorState > >
118126 where
119127 P : SessionPersister < SessionEvent = Event > ,
120128 Err : std:: error:: Error ,
@@ -217,16 +225,21 @@ pub enum AcceptOptionalTransition<Event, NextState, CurrentState> {
217225}
218226
219227/// Wrapper representing a fatal or transient rejection of a state transition.
220- pub enum Rejection < Event , Err > {
228+ pub enum Rejection < Event , Err , ErrorState = ( ) > {
221229 Fatal ( RejectFatal < Event , Err > ) ,
222230 Transient ( RejectTransient < Err > ) ,
231+ ReplyableError ( RejectReplyableError < Event , ErrorState , Err > ) ,
223232}
224233
225- impl < Event , Err > Rejection < Event , Err > {
234+ impl < Event , Err , ErrorState > Rejection < Event , Err , ErrorState > {
226235 #[ inline]
227236 pub fn fatal ( event : Event , error : Err ) -> Self { Rejection :: Fatal ( RejectFatal ( event, error) ) }
228237 #[ inline]
229238 pub fn transient ( error : Err ) -> Self { Rejection :: Transient ( RejectTransient ( error) ) }
239+ #[ inline]
240+ pub fn replyable_error ( event : Event , error_state : ErrorState , error : Err ) -> Self {
241+ Rejection :: ReplyableError ( RejectReplyableError ( event, error_state, error) )
242+ }
230243}
231244
232245/// Represents a fatal rejection of a state transition.
@@ -235,6 +248,13 @@ pub struct RejectFatal<Event, Err>(pub(crate) Event, pub(crate) Err);
235248/// Represents a transient rejection of a state transition.
236249/// When this error occurs, the session should resume from its current state.
237250pub struct RejectTransient < Err > ( pub ( crate ) Err ) ;
251+ /// Represents a replyable error that transitions to an error state but keeps the session open.
252+ /// When this error occurs, the session transitions to the ErrorState.
253+ pub struct RejectReplyableError < Event , ErrorState , Err > (
254+ pub ( crate ) Event ,
255+ pub ( crate ) ErrorState ,
256+ pub ( crate ) Err ,
257+ ) ;
238258/// Represents a bad initial inputs to the state machine.
239259/// When this error occurs, the session cannot be created.
240260/// The wrapper contains the error and should be returned to the caller.
@@ -248,15 +268,18 @@ impl<Err: std::error::Error> fmt::Display for RejectTransient<Err> {
248268}
249269
250270/// Error type that represents all possible errors that can be returned when processing a state transition
251- #[ derive( Debug , Clone , PartialEq , Eq ) ]
252- pub struct PersistedError < ApiError : std:: error:: Error , StorageError : std:: error:: Error > (
253- InternalPersistedError < ApiError , StorageError > ,
254- ) ;
255-
256- impl < ApiErr , StorageErr > PersistedError < ApiErr , StorageErr >
271+ #[ derive( Debug ) ]
272+ pub struct PersistedError <
273+ ApiError : std:: error:: Error ,
274+ StorageError : std:: error:: Error ,
275+ ErrorState : fmt:: Debug = ( ) ,
276+ > ( InternalPersistedError < ApiError , StorageError , ErrorState > ) ;
277+
278+ impl < ApiErr , StorageErr , ErrorState > PersistedError < ApiErr , StorageErr , ErrorState >
257279where
258280 StorageErr : std:: error:: Error ,
259281 ApiErr : std:: error:: Error ,
282+ ErrorState : fmt:: Debug ,
260283{
261284 #[ allow( dead_code) ]
262285 pub fn storage_error ( self ) -> Option < StorageErr > {
@@ -268,7 +291,9 @@ where
268291
269292 pub fn api_error ( self ) -> Option < ApiErr > {
270293 match self . 0 {
271- InternalPersistedError :: Fatal ( e) | InternalPersistedError :: Transient ( e) => Some ( e) ,
294+ InternalPersistedError :: Fatal ( e)
295+ | InternalPersistedError :: Transient ( e)
296+ | InternalPersistedError :: FatalWithState ( e, _) => Some ( e) ,
272297 _ => None ,
273298 }
274299 }
@@ -282,46 +307,61 @@ where
282307
283308 pub fn api_error_ref ( & self ) -> Option < & ApiErr > {
284309 match & self . 0 {
285- InternalPersistedError :: Fatal ( e) | InternalPersistedError :: Transient ( e) => Some ( e) ,
310+ InternalPersistedError :: Fatal ( e)
311+ | InternalPersistedError :: Transient ( e)
312+ | InternalPersistedError :: FatalWithState ( e, _) => Some ( e) ,
313+ _ => None ,
314+ }
315+ }
316+
317+ pub fn error_state ( self ) -> Option < ErrorState > {
318+ match self . 0 {
319+ InternalPersistedError :: FatalWithState ( _, state) => Some ( state) ,
286320 _ => None ,
287321 }
288322 }
289323}
290324
291- impl < ApiError : std:: error:: Error , StorageError : std:: error:: Error >
292- From < InternalPersistedError < ApiError , StorageError > >
293- for PersistedError < ApiError , StorageError >
325+ impl < ApiError : std:: error:: Error , StorageError : std:: error:: Error , ErrorState : fmt :: Debug >
326+ From < InternalPersistedError < ApiError , StorageError , ErrorState > >
327+ for PersistedError < ApiError , StorageError , ErrorState >
294328{
295- fn from ( value : InternalPersistedError < ApiError , StorageError > ) -> Self { PersistedError ( value) }
329+ fn from ( value : InternalPersistedError < ApiError , StorageError , ErrorState > ) -> Self {
330+ PersistedError ( value)
331+ }
296332}
297333
298- impl < ApiError : std:: error:: Error , StorageError : std:: error:: Error > std :: error :: Error
299- for PersistedError < ApiError , StorageError >
334+ impl < ApiError : std:: error:: Error , StorageError : std:: error:: Error , ErrorState : fmt :: Debug >
335+ std :: error :: Error for PersistedError < ApiError , StorageError , ErrorState >
300336{
301337}
302338
303- impl < ApiError : std:: error:: Error , StorageError : std:: error:: Error > fmt:: Display
304- for PersistedError < ApiError , StorageError >
339+ impl < ApiError : std:: error:: Error , StorageError : std:: error:: Error , ErrorState : fmt:: Debug >
340+ fmt :: Display for PersistedError < ApiError , StorageError , ErrorState >
305341{
306342 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
307343 match & self . 0 {
308344 InternalPersistedError :: Transient ( err) => write ! ( f, "Transient error: {err}" ) ,
309- InternalPersistedError :: Fatal ( err) => write ! ( f, "Fatal error: {err}" ) ,
345+ InternalPersistedError :: Fatal ( err) | InternalPersistedError :: FatalWithState ( err, _) =>
346+ write ! ( f, "Fatal error: {err}" ) ,
310347 InternalPersistedError :: Storage ( err) => write ! ( f, "Storage error: {err}" ) ,
311348 }
312349 }
313350}
314351
315- #[ derive( Debug , Clone , PartialEq , Eq ) ]
316- pub ( crate ) enum InternalPersistedError < InternalApiError , StorageErr >
352+ #[ derive( Debug ) ]
353+ pub ( crate ) enum InternalPersistedError < InternalApiError , StorageErr , ErrorState = ( ) >
317354where
318355 InternalApiError : std:: error:: Error ,
319356 StorageErr : std:: error:: Error ,
357+ ErrorState : fmt:: Debug ,
320358{
321359 /// Error indicating that the session should be retried from the same state
322360 Transient ( InternalApiError ) ,
323361 /// Error indicating that the session is terminally closed
324362 Fatal ( InternalApiError ) ,
363+ /// Fatal error that results in a state transition to ErrorState
364+ FatalWithState ( InternalApiError , ErrorState ) ,
325365 /// Error indicating that application failed to save the session event. This should be treated as a transient error
326366 /// but is represented as a separate error because this error is propagated from the application's storage layer
327367 Storage ( StorageErr ) ,
@@ -390,6 +430,8 @@ trait InternalSessionPersister: SessionPersister {
390430 Err ( InternalPersistedError :: Transient ( err) . into ( ) ) ,
391431 Err ( Rejection :: Fatal ( RejectFatal ( event, err) ) ) =>
392432 Err ( self . handle_fatal_reject ( RejectFatal ( event, err) ) . into ( ) ) ,
433+ Err ( Rejection :: ReplyableError ( reject_replyable_error) ) =>
434+ Err ( self . handle_replyable_error_reject ( reject_replyable_error) . into ( ) ) ,
393435 }
394436 }
395437
@@ -425,6 +467,8 @@ trait InternalSessionPersister: SessionPersister {
425467 Err ( self . handle_fatal_reject ( reject_fatal) . into ( ) ) ,
426468 Err ( Rejection :: Transient ( RejectTransient ( err) ) ) =>
427469 Err ( InternalPersistedError :: Transient ( err) . into ( ) ) ,
470+ Err ( Rejection :: ReplyableError ( reject_replyable_error) ) =>
471+ Err ( self . handle_replyable_error_reject ( reject_replyable_error) . into ( ) ) ,
428472 }
429473 }
430474 /// Save a transition that can result in:
@@ -458,6 +502,8 @@ trait InternalSessionPersister: SessionPersister {
458502 Err ( self . handle_fatal_reject ( reject_fatal) . into ( ) ) ,
459503 Err ( Rejection :: Transient ( RejectTransient ( err) ) ) =>
460504 Err ( InternalPersistedError :: Transient ( err) . into ( ) ) ,
505+ Err ( Rejection :: ReplyableError ( reject_replyable_error) ) =>
506+ Err ( self . handle_replyable_error_reject ( reject_replyable_error) . into ( ) ) ,
461507 }
462508 }
463509
@@ -479,12 +525,13 @@ trait InternalSessionPersister: SessionPersister {
479525 }
480526
481527 /// Save a transition that can be a fatal error, transient error or a state transition
482- fn save_maybe_fatal_error_transition < NextState , Err > (
528+ fn save_maybe_fatal_error_transition < NextState , Err , ErrorState > (
483529 & self ,
484- state_transition : MaybeFatalTransition < Self :: SessionEvent , NextState , Err > ,
485- ) -> Result < NextState , PersistedError < Err , Self :: InternalStorageError > >
530+ state_transition : MaybeFatalTransition < Self :: SessionEvent , NextState , Err , ErrorState > ,
531+ ) -> Result < NextState , PersistedError < Err , Self :: InternalStorageError , ErrorState > >
486532 where
487533 Err : std:: error:: Error ,
534+ ErrorState : fmt:: Debug ,
488535 {
489536 match state_transition. 0 {
490537 Ok ( AcceptNextState ( event, next_state) ) => {
@@ -499,17 +546,20 @@ trait InternalSessionPersister: SessionPersister {
499546 // No event to store for transient errors
500547 Err ( InternalPersistedError :: Transient ( err) . into ( ) )
501548 }
549+ Rejection :: ReplyableError ( reject_replyable_error) =>
550+ Err ( self . handle_replyable_error_reject ( reject_replyable_error) . into ( ) ) ,
502551 }
503552 }
504553 }
505554 }
506555
507- fn handle_fatal_reject < Err > (
556+ fn handle_fatal_reject < Err , ErrorState > (
508557 & self ,
509558 reject_fatal : RejectFatal < Self :: SessionEvent , Err > ,
510- ) -> InternalPersistedError < Err , Self :: InternalStorageError >
559+ ) -> InternalPersistedError < Err , Self :: InternalStorageError , ErrorState >
511560 where
512561 Err : std:: error:: Error ,
562+ ErrorState : fmt:: Debug ,
513563 {
514564 let RejectFatal ( event, error) = reject_fatal;
515565 if let Err ( e) = self . save_event ( event) {
@@ -522,6 +572,22 @@ trait InternalSessionPersister: SessionPersister {
522572
523573 InternalPersistedError :: Fatal ( error)
524574 }
575+
576+ fn handle_replyable_error_reject < Err , ErrorState > (
577+ & self ,
578+ reject_replyable_error : RejectReplyableError < Self :: SessionEvent , ErrorState , Err > ,
579+ ) -> InternalPersistedError < Err , Self :: InternalStorageError , ErrorState >
580+ where
581+ Err : std:: error:: Error ,
582+ ErrorState : fmt:: Debug ,
583+ {
584+ let RejectReplyableError ( event, error_state, error) = reject_replyable_error;
585+ if let Err ( e) = self . save_event ( event) {
586+ return InternalPersistedError :: Storage ( e) ;
587+ }
588+ // For replyable errors, don't close the session - keep it open for error response
589+ InternalPersistedError :: FatalWithState ( error, error_state)
590+ }
525591}
526592
527593impl < T : SessionPersister > InternalSessionPersister for T { }
0 commit comments