HabitRPG / habitica

A habit tracker app which treats your goals like a Role Playing Game.
https://habitica.com
Other
11.82k stars 4.05k forks source link

ParallelSaveError errors when deleting an account #10867

Open Alys opened 5 years ago

Alys commented 5 years ago

Loggly reports errors for a user deleting their account:

"method":"DELETE","originalUrl":"/api/v4/user" ... ParallelSaveError: Can't save() the same doc multiple times in parallel.

followed by:

"method":"GET","originalUrl":"/api/v4/user" ... "message":"NotAuthorized: There is no account that uses those credentials.

"method":"GET","originalUrl":"/api/v4/tasks/user" ... "message":"NotAuthorized: There is no account that uses those credentials.

The account and tasks are deleted now but I don't know if that's from the user trying the delete a second time. The reason I'm mentioned this is that we want to be certain that an account deletion is performed fully when a user requests it. The ParallelSaveError implies that it might not be.

This was not reported by the user, it's just something I noticed when investigating something else, so we can't contact the user to ask for more information.

paglias commented 5 years ago

Thanks for the link to the loggly page! The erros is coming from a group method which leads me to think it's the same issue as https://github.com/HabitRPG/habitica/issues/10814 which was deployed yesterday or the day before. I'll check if any change is necessary or if it's covered by the fix #10852

paglias commented 5 years ago

This is still happening, multiple saves to the user doc when deleting an account at /website/transpiled-babel/models/group.js:1183. Unlinking tasks from challenges and groups was fixed in #10852, so my guess is that it could be due to this code promises.push(payments.cancelGroupSubscriptionForUser(user, this)); trying to save the user another time

paglias commented 5 years ago

Actually it's likely to happen from this code in the delete user route that removes the user from all groups concurrently

    let groupLeavePromises = groupsUserIsMemberOf.map((group) => {
      return group.leave(user, 'remove-all');
    });