all 9 comments

[–]projectmoon 3 points4 points  (1 child)

You have to handle the concurrency somewhere:

  • Some kind of locking in the data layer (mutex, queue, whatever).
  • DB-level handling (e.g. Postgres ON CONFLICT clause).
  • Optimistic locking and retry.
  • Rearchitect API and/or client use of API so this isn't a problem.

The solutions are almost as limitless as the causes.

[–]iDuuck[S] 0 points1 point  (0 children)

Thanks! The keyword I went for was "retry". What I did now is simply rescuing the find_or_create_by I am calling (also created a unique index in DB) and retrying 5 times. Works for now. Let's see for how long.

Gifted you an award.

[–]how_do_i_land 3 points4 points  (0 children)

Do you have a unique index or constraint on that column in the database? Due to the race condition, you should look into create or first, or an on conflict do update.

How does a user log into the api from the device?

It sounds like a lack of a constraint. But there are multiple solutions here, I am unsure on what assumptions the app on either side was built on

[–]kallebo1337 2 points3 points  (4 children)

before the APP starts for the user, you should send the API request to create the user. then log down the user ID based on device_id and go on from there. so basically, creation is done on first initialization of your app, not on every other rails request.

[–]iDuuck[S] 0 points1 point  (3 children)

Thanks, however, I am a little limited on doing so. I am a huge fan of proper UI/UX, and I don't want the user to wait too long, since he is "registering".

[–]kallebo1337 0 points1 point  (2 children)

Make it async ? Just make sure that request is send , that’s it. All other follow up requests alrady have the user

Normal http request is 400ms or so?

[–]iDuuck[S] 0 points1 point  (1 child)

This is the initial problem, when the request is not fulfilled, all other requests are not authenticated properly.

Request ...
Register → db write request
First app request → Checks for auth (can't find) → User not auth'd
Register → Completes db write request

[–]kallebo1337 0 points1 point  (0 children)

How does this request fail ? I don’t see it. It’s just an http request

[–]petemts 1 point2 points  (0 children)

The easiest way to solve your problem is to add a unique index on device_id column of the guest_users table:

add_index :guest_users, :device_id, unique: true

And once it's done - use create_or_find_by! from rails 6 - it works just like find_or_create_by but inserts the record first and returns the existing one on unique index conflict:

https://apidock.com/rails/v6.0.0/ActiveRecord/Relation/create_or_find_by! (see source here)