javascriptxstate

XState: guard for finite number of retries


I have an XState state machine in JavaScript that is pretty simple; it initiates a connection to a server and on FAILURE, tries reconnecting. My objective is to do a finite number of retries (say, 3 times) after which it goes into final state.

I can't figure out how to achieve this. Any help is appreciated.

From my understanding, if the guard evaluates to TRUE, TARGET is transitioned to. What if the guard evaluates to FALSE? How do I transition to TRIED_ENOUGH_TIMES_DONE?

WAITFORRECONNECT: {
            //activities: ["showingLoadingPanel"],
            entry: (context, event) => {
                console.log("logging re-connect entry call");
                console.log('Retry Count: ' + context.iNumberOfRetries);
            },
            on: {
                DISCONNECTED: { target: 'showingAlert', actions: assign({ errorMessage: (context, event) => event.data }) },                    
                LOGIN_SUCCESS: 'IDLE',

                LOGIN_FAILURE: {
                    
                    actions: assign({ iNumberOfRetries: (context, event) => context.iNumberOfRetries + 1 }),                        
                    target:  'WAITFORRECONNECT',
                    cond: 'isMaxRetriesReached',
                    internal: false

                },
                LOGOUT: {
                    target: 'showingFinalAlert',
                    actions: assign({ errorMessage: (context, event) => event.data })
                },
                CLOSEWINDOW: {
                    target: 'showingFinalAlert',
                    actions: assign({ errorMessage: (context, event) => event.data })
                }
            },
            invoke: {
                src: (context, event) =>
                    connectToServer(
                        context.waitTimeInMilliSeconds,
                        context.sServerAddress,
                        context.sUsername,
                        context.sPassword,
                        context.sPort,
                    ),

                onError: {
                    target: "showingAlert",
                    actions: assign({ errorMessage: (context, event) => event.data })
                }
            },



        },       

    {
        activities: { showingLoadingPanel: createLoadingActivity },
        guards: { 
                isMaxRetriesReached: ({context}) =>
                    {                           
                        return context.iNumberOfRetries <=2;
                    }
            }

   }

Solution

  • I modified my LOGIN_FAILURE state to accomodate an IDLE transition if maxRetriesFails. This seems to be working.

    LOGIN_FAILURE:              
                            
    [
                            
    {
        target:  'WAITFORRECONNECT',
        cond: 'isMaxRetriesReached',            
    
    },
                            
    { target: 'IDLE'},
    ],