How to prevent race condition when creating a document on parse server?












0















A mobile app uses parse server as a backend with mongoDB as database.



For every user in the User collection there is a user profile in the UserProfile collection. A user profile has a pointer field as a reference to the User to which the user profile belongs.



The problem is that multiple user profiles are created for the same user during sign up.



That is because the sign-up process looks like this:





  1. Client: user signs up


  2. Server: creates user profile in afterSave of User


  3. Client: after sign-up calls cloud code function updateProfile to update information in the user profile


  4. Server: updateProfile looks for existing user profile or creates a new one if none exists


This causes a race condition: The server creates a user profile in step #2 and at the same time updateProfile creates a new user profile in step #4. The time difference in createdAt of these user profiles is milliseconds.



Now:




  • If I leave out step #2, then even if step #4 gets calls multiple times immediately after each other, it can cause a race condition because updateProfile won't find a user profile until it's created. On the other hand every user needs to have a user profile associated with it, so creating it server side is the only way to ensure that.


  • If I change step #4, to not create a new profile, then the information in the profile is not updated when the client calls the cloud code function updateProfile because the user profile from step #1 is not yet created.



What is the correct approach?



Update:




  • Unfortunately the user profile cannot be created on beforeSave of the User because it doesn't seem to have an ID yet. If that was possible then it would be ensured that a user profile is created before the client calls updateProfile.










share|improve this question




















  • 1





    Does the UserProfile have a pointer to User? If so, you can make a unique index on that field.

    – Arthur Cinader
    Nov 16 '18 at 2:27











  • I thought of that, it prevents multiple user profiles. However, step #4 will still fail because it won't find the user profile that hasn't been created by step #2 yet. I need something that ensures that the write operation in step #2 is done before the find/modify operation in step #4.

    – Manuel
    Nov 16 '18 at 2:32













  • so why even bother doing #2? why not count on #4 to do the work. but you should make the unique index anyway.

    – Arthur Cinader
    Nov 16 '18 at 2:37






  • 1





    Please show your code. What you're trying to do is easily done without race conditions. In a nutshell, (a) you can have your afterSave hook create and update the profile and skip step #4, or (b) skip step #2, and after user creation is complete call updateProfile (which will do a create first if there is none). If one or both of those approaches is failing, then the code requires review.

    – danh
    Nov 17 '18 at 23:43











  • @danh (a) afterSave hook for User class cannot update the user profile because the information to update is provided by the client in step #4, so step #4 cannot be skipped. (b) if step #2 is skipped, then the creation of a user profile is determined by the client. If a client is terminated after the user creation request and before the response (e.g. on slow network), then no user profile will be created. No code to review here, this is a conceptual question.

    – Manuel
    Nov 18 '18 at 16:51


















0















A mobile app uses parse server as a backend with mongoDB as database.



For every user in the User collection there is a user profile in the UserProfile collection. A user profile has a pointer field as a reference to the User to which the user profile belongs.



The problem is that multiple user profiles are created for the same user during sign up.



That is because the sign-up process looks like this:





  1. Client: user signs up


  2. Server: creates user profile in afterSave of User


  3. Client: after sign-up calls cloud code function updateProfile to update information in the user profile


  4. Server: updateProfile looks for existing user profile or creates a new one if none exists


This causes a race condition: The server creates a user profile in step #2 and at the same time updateProfile creates a new user profile in step #4. The time difference in createdAt of these user profiles is milliseconds.



Now:




  • If I leave out step #2, then even if step #4 gets calls multiple times immediately after each other, it can cause a race condition because updateProfile won't find a user profile until it's created. On the other hand every user needs to have a user profile associated with it, so creating it server side is the only way to ensure that.


  • If I change step #4, to not create a new profile, then the information in the profile is not updated when the client calls the cloud code function updateProfile because the user profile from step #1 is not yet created.



What is the correct approach?



Update:




  • Unfortunately the user profile cannot be created on beforeSave of the User because it doesn't seem to have an ID yet. If that was possible then it would be ensured that a user profile is created before the client calls updateProfile.










share|improve this question




















  • 1





    Does the UserProfile have a pointer to User? If so, you can make a unique index on that field.

    – Arthur Cinader
    Nov 16 '18 at 2:27











  • I thought of that, it prevents multiple user profiles. However, step #4 will still fail because it won't find the user profile that hasn't been created by step #2 yet. I need something that ensures that the write operation in step #2 is done before the find/modify operation in step #4.

    – Manuel
    Nov 16 '18 at 2:32













  • so why even bother doing #2? why not count on #4 to do the work. but you should make the unique index anyway.

    – Arthur Cinader
    Nov 16 '18 at 2:37






  • 1





    Please show your code. What you're trying to do is easily done without race conditions. In a nutshell, (a) you can have your afterSave hook create and update the profile and skip step #4, or (b) skip step #2, and after user creation is complete call updateProfile (which will do a create first if there is none). If one or both of those approaches is failing, then the code requires review.

    – danh
    Nov 17 '18 at 23:43











  • @danh (a) afterSave hook for User class cannot update the user profile because the information to update is provided by the client in step #4, so step #4 cannot be skipped. (b) if step #2 is skipped, then the creation of a user profile is determined by the client. If a client is terminated after the user creation request and before the response (e.g. on slow network), then no user profile will be created. No code to review here, this is a conceptual question.

    – Manuel
    Nov 18 '18 at 16:51
















0












0








0








A mobile app uses parse server as a backend with mongoDB as database.



For every user in the User collection there is a user profile in the UserProfile collection. A user profile has a pointer field as a reference to the User to which the user profile belongs.



The problem is that multiple user profiles are created for the same user during sign up.



That is because the sign-up process looks like this:





  1. Client: user signs up


  2. Server: creates user profile in afterSave of User


  3. Client: after sign-up calls cloud code function updateProfile to update information in the user profile


  4. Server: updateProfile looks for existing user profile or creates a new one if none exists


This causes a race condition: The server creates a user profile in step #2 and at the same time updateProfile creates a new user profile in step #4. The time difference in createdAt of these user profiles is milliseconds.



Now:




  • If I leave out step #2, then even if step #4 gets calls multiple times immediately after each other, it can cause a race condition because updateProfile won't find a user profile until it's created. On the other hand every user needs to have a user profile associated with it, so creating it server side is the only way to ensure that.


  • If I change step #4, to not create a new profile, then the information in the profile is not updated when the client calls the cloud code function updateProfile because the user profile from step #1 is not yet created.



What is the correct approach?



Update:




  • Unfortunately the user profile cannot be created on beforeSave of the User because it doesn't seem to have an ID yet. If that was possible then it would be ensured that a user profile is created before the client calls updateProfile.










share|improve this question
















A mobile app uses parse server as a backend with mongoDB as database.



For every user in the User collection there is a user profile in the UserProfile collection. A user profile has a pointer field as a reference to the User to which the user profile belongs.



The problem is that multiple user profiles are created for the same user during sign up.



That is because the sign-up process looks like this:





  1. Client: user signs up


  2. Server: creates user profile in afterSave of User


  3. Client: after sign-up calls cloud code function updateProfile to update information in the user profile


  4. Server: updateProfile looks for existing user profile or creates a new one if none exists


This causes a race condition: The server creates a user profile in step #2 and at the same time updateProfile creates a new user profile in step #4. The time difference in createdAt of these user profiles is milliseconds.



Now:




  • If I leave out step #2, then even if step #4 gets calls multiple times immediately after each other, it can cause a race condition because updateProfile won't find a user profile until it's created. On the other hand every user needs to have a user profile associated with it, so creating it server side is the only way to ensure that.


  • If I change step #4, to not create a new profile, then the information in the profile is not updated when the client calls the cloud code function updateProfile because the user profile from step #1 is not yet created.



What is the correct approach?



Update:




  • Unfortunately the user profile cannot be created on beforeSave of the User because it doesn't seem to have an ID yet. If that was possible then it would be ensured that a user profile is created before the client calls updateProfile.







mongodb parse.com parse-server






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 15 '18 at 14:18







Manuel

















asked Nov 15 '18 at 14:06









ManuelManuel

5,79712050




5,79712050








  • 1





    Does the UserProfile have a pointer to User? If so, you can make a unique index on that field.

    – Arthur Cinader
    Nov 16 '18 at 2:27











  • I thought of that, it prevents multiple user profiles. However, step #4 will still fail because it won't find the user profile that hasn't been created by step #2 yet. I need something that ensures that the write operation in step #2 is done before the find/modify operation in step #4.

    – Manuel
    Nov 16 '18 at 2:32













  • so why even bother doing #2? why not count on #4 to do the work. but you should make the unique index anyway.

    – Arthur Cinader
    Nov 16 '18 at 2:37






  • 1





    Please show your code. What you're trying to do is easily done without race conditions. In a nutshell, (a) you can have your afterSave hook create and update the profile and skip step #4, or (b) skip step #2, and after user creation is complete call updateProfile (which will do a create first if there is none). If one or both of those approaches is failing, then the code requires review.

    – danh
    Nov 17 '18 at 23:43











  • @danh (a) afterSave hook for User class cannot update the user profile because the information to update is provided by the client in step #4, so step #4 cannot be skipped. (b) if step #2 is skipped, then the creation of a user profile is determined by the client. If a client is terminated after the user creation request and before the response (e.g. on slow network), then no user profile will be created. No code to review here, this is a conceptual question.

    – Manuel
    Nov 18 '18 at 16:51
















  • 1





    Does the UserProfile have a pointer to User? If so, you can make a unique index on that field.

    – Arthur Cinader
    Nov 16 '18 at 2:27











  • I thought of that, it prevents multiple user profiles. However, step #4 will still fail because it won't find the user profile that hasn't been created by step #2 yet. I need something that ensures that the write operation in step #2 is done before the find/modify operation in step #4.

    – Manuel
    Nov 16 '18 at 2:32













  • so why even bother doing #2? why not count on #4 to do the work. but you should make the unique index anyway.

    – Arthur Cinader
    Nov 16 '18 at 2:37






  • 1





    Please show your code. What you're trying to do is easily done without race conditions. In a nutshell, (a) you can have your afterSave hook create and update the profile and skip step #4, or (b) skip step #2, and after user creation is complete call updateProfile (which will do a create first if there is none). If one or both of those approaches is failing, then the code requires review.

    – danh
    Nov 17 '18 at 23:43











  • @danh (a) afterSave hook for User class cannot update the user profile because the information to update is provided by the client in step #4, so step #4 cannot be skipped. (b) if step #2 is skipped, then the creation of a user profile is determined by the client. If a client is terminated after the user creation request and before the response (e.g. on slow network), then no user profile will be created. No code to review here, this is a conceptual question.

    – Manuel
    Nov 18 '18 at 16:51










1




1





Does the UserProfile have a pointer to User? If so, you can make a unique index on that field.

– Arthur Cinader
Nov 16 '18 at 2:27





Does the UserProfile have a pointer to User? If so, you can make a unique index on that field.

– Arthur Cinader
Nov 16 '18 at 2:27













I thought of that, it prevents multiple user profiles. However, step #4 will still fail because it won't find the user profile that hasn't been created by step #2 yet. I need something that ensures that the write operation in step #2 is done before the find/modify operation in step #4.

– Manuel
Nov 16 '18 at 2:32







I thought of that, it prevents multiple user profiles. However, step #4 will still fail because it won't find the user profile that hasn't been created by step #2 yet. I need something that ensures that the write operation in step #2 is done before the find/modify operation in step #4.

– Manuel
Nov 16 '18 at 2:32















so why even bother doing #2? why not count on #4 to do the work. but you should make the unique index anyway.

– Arthur Cinader
Nov 16 '18 at 2:37





so why even bother doing #2? why not count on #4 to do the work. but you should make the unique index anyway.

– Arthur Cinader
Nov 16 '18 at 2:37




1




1





Please show your code. What you're trying to do is easily done without race conditions. In a nutshell, (a) you can have your afterSave hook create and update the profile and skip step #4, or (b) skip step #2, and after user creation is complete call updateProfile (which will do a create first if there is none). If one or both of those approaches is failing, then the code requires review.

– danh
Nov 17 '18 at 23:43





Please show your code. What you're trying to do is easily done without race conditions. In a nutshell, (a) you can have your afterSave hook create and update the profile and skip step #4, or (b) skip step #2, and after user creation is complete call updateProfile (which will do a create first if there is none). If one or both of those approaches is failing, then the code requires review.

– danh
Nov 17 '18 at 23:43













@danh (a) afterSave hook for User class cannot update the user profile because the information to update is provided by the client in step #4, so step #4 cannot be skipped. (b) if step #2 is skipped, then the creation of a user profile is determined by the client. If a client is terminated after the user creation request and before the response (e.g. on slow network), then no user profile will be created. No code to review here, this is a conceptual question.

– Manuel
Nov 18 '18 at 16:51







@danh (a) afterSave hook for User class cannot update the user profile because the information to update is provided by the client in step #4, so step #4 cannot be skipped. (b) if step #2 is skipped, then the creation of a user profile is determined by the client. If a client is terminated after the user creation request and before the response (e.g. on slow network), then no user profile will be created. No code to review here, this is a conceptual question.

– Manuel
Nov 18 '18 at 16:51














0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53321248%2fhow-to-prevent-race-condition-when-creating-a-document-on-parse-server%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53321248%2fhow-to-prevent-race-condition-when-creating-a-document-on-parse-server%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Xamarin.iOS Cant Deploy on Iphone

Glorious Revolution

Dulmage-Mendelsohn matrix decomposition in Python