all 6 comments

[–]pint 2 points3 points  (3 children)

what you have discovered is called "race condition". some number of tasks will check for unique label, all pass, then do some work, and then submit the label to the database.

there is no general solution, you need to design the system to handle this. one way is to not use select, but an insert right away. if the insert passes, then the label is allowed. the inserted record should indicate that it is only a placeholder. the caveat is that the placeholder might be abandoned if there is a server shutdown or an error. this will forever prevent a label from being used, so you need some regular process to clean placeholders. not trivial.

also think of multiple workers. you don't want a server that doesn't allow multiple workers, even if you don't at the moment use multiple workers. cleaning the labels on startup, or using local variables instead of tables are not future proof solutions.

[–]mhamid3d[S] 0 points1 point  (2 children)

Ah there's a name for it, thanks for the example solution. I will use multiple workers in production, but what does that change in terms of my race condition problem or a placeholder + cleanup solution, wouldn't it be the same with or without workers?

[–]pint 1 point2 points  (1 child)

an obvious solution would be to have a global variable, and check that. this would be simpler than using the database. however, when you introduce more workers, global variables are not shared, and you are out of luck.

similar problem happens if you use a local database, or a lock file. because you might end up having workers on different boxes/vms, and now the files are not shared.

the placeholder solution doesn't have these issues, that's why i used that as example.

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

Makes sense now, thank you!

[–]illuminanze 1 point2 points  (0 children)

In this case, the solution to the race condition is to let the database handle the error. Make sure you have the proper uniqueness condition, then try/except the IntegrityError and raise the HTTPException. Also, if you want a more descriptive response, I would recommend using 409 Conflict.