Today I've received bug reports that some of our application's POST requests are being duplicated.
These requests results in the creation of objects on the remote database such like Tasks, Meetings, etc, so the duplication of them implies in Tasks being created with the same name, same due date, user, etc.
I've tried to replicate this but it seems to be a random behavior, and the only concurrent symptom reported is that the request takes more time than normal to complete.
I'm currently using the stack React + Redux + Axios + Asp.Net WebApi, and I have reached to the following considerations in order to understand and solve the issue.
Any tips on any of these topics are really appreciated.
React + Redux:
The action creator that dispatches the request is called just once, on a onClick event. Apparently there's no state change or page refresh that could cause a multiple call of this fuction.
handleClick(event) {
var postData = {
title: this.state.text,
dueDate: this.state.date,
assignedUser: this.state.user.id
};
this.props.contentPost(postData);
}
Axios:
One of my suspicions is that, for some unknown reason, the users' requests fails, or take to long to complete and then axios supposedly sends the request it again. I've checked it's documentation and issues databases, and didn't found nothing like Automatic Retries or request duplication.
export const contentPost = (props) => {
return function (dispatch) {
dispatch({ type: CONTENT_POST_ERROR, payload: null })
dispatch({ type: CONTENT_POST_LOADING, payload: true });
dispatch({ type: CONTENT_POST_SUCCESS, payload: null })
const request = axios({
method: 'post',
url: `/api/content`,
headers: auth.getHttpHeader(),
validateStatus: function (status) {
return status >= 200 && status < 300; // default
},
data: props
}).then((res) => {
dispatch({ type: CONTENT_POST_LOADING, payload: false });
dispatch({ type: CONTENT_POST_SUCCESS, payload: true, data: res })
}).catch(err => {
dispatch({ type: CONTENT_POST_ERROR, payload: err.code })
dispatch({ type: CONTENT_POST_LOADING, payload: false });
dispatch({ type: CONTENT_POST_SUCCESS, payload: false, data: null })
});
}
};
WebApi
The Controller's method don't have any sort of throttling or "uniqueness token" to identify and prevent duplicated requests. Since this is a random behavior, I would not bet that the Routing or any part of my server side application has any responsibility on this.
Axios:
WebApi
Even with the described above, these solutions looks like an overkill, while the root causes also seems a little too subjective.
I've found out that a late loading state feedback for the users was causing this behavior.
Some people stills double-click stuff on websites. It was naive not to have prevented this by code.
There are a lot of ways to accomplish a better user experience in this scenario. I chose to completely change the button while user are sending our POST request, and we are also implementing the throttling at our backend.
{this.props.content_post_loading &&
<a className="btn btn-primary disabled">Creating...</a>
||
<a className="btn btn-primary" onClick={this.handleCreateClick}>Create</a>
}