I am doing an integration with payment service. And I have to onboard a merchant. For onboarding a merchant I need to follow bellow steps
If any step fails, I need to retry from that step only. I can not start from starting.
My Solution:
I am maintaining a state object for onboarding of the user. state object has 4 fields
with each step I am setting respective state attribute as true and saving it.
Algotithm:
Initialise state object all
state.userCreated = false;
state.businessProfileCreated = false;
state.paymentProfileCreated = false;
state.webhookRegistered = false;`
if(state.userCreated != true)
create user
if create profile **not** success
save state
return
state.userCreated = true
if(state.businessProfileCreated != true)
create business profile
if businessProfile creation **not** success
save state
return
state.businessProfileCreated = true
if(state.paymentProfileCreated != true create payment profile if payment Profile creation not success save state return state.paymentProfileCreated
if(state.webhookRegistered != true) :create webhook profile save state return
state.paymentProfileCreated save state ``
I need a clean way of doing this that also handle api failure. Is there any pattern exists for this task
Maybe others have better ideas, but what comes to my mind is a modified version of the Strategy Pattern. (See https://en.wikipedia.org/wiki/Strategy_pattern)
To implement this, you would need a list of functions to execute, (the strategy,) and you would write some code which walks through the list, invokes the function, checks the result, and keeps track of where the error occurred, by storing the index of the function that failed instead of jockeying a bunch of boolean flags.
Your problem, if you decide to use this pattern, is that different functions may need different parameters, and to complicate things even more, some function may depend on some result returned by a previously invoked function. To solve this, you will have to store all of the information that these functions might need into a separate object and pass that object to each one of the functions, so that they can read fields from that object and write fields to it as they need.
It is probably not worth the hassle, and it will probably not make it any more clear to the reader what is happening.
Consider keeping the structure of your existing code but just improving it, for example:
Use a single enum telling you how far you went instead of a whole bunch of booleans;
Move all the steps in a new function, and modify each error check so that it returns a failure indication instead of saving state and then returning. Then, from the place where you call this function, check whether it indicates error, and if so, save the state only in one place.