Open teonat opened 1 year ago
My first impression was that this can be fixed easily by adding another try/except to the get_or_create
-function, but I'm not really sure if we can just import the asyncpg-package here? Thoughts @collerek ?
from asyncpg import UniqueViolationError
...
try:
return await self.get(*args, **kwargs), False
except NoMatch:
_defaults = _defaults or {}
try:
return await self.create(**{**kwargs, **_defaults}), True
except UniqueViolationError:
return await self.get(*args, **kwargs), False
Sorry for the necro, but in a similar vein; ormar
doesn't provide anything in terms of connection management for those tasks. The async with database:
line creates a connection to your database, but then that same connection is implicitly used in both asyncio tasks (via Application.Meta.database
), without any guarantee of which operation will run first. Ideally you'd pass a new database.connection()
to each task, but ormar
doesn't seem to provide any API to use a given connection. Your idea doesn't provide any guarantees, since another process (or task) could create a new Application
after you've caught NoMatch
but before you call .create()
. I think you just need a transaction, but like I said about connections, transactions also can't easily be shared between tasks with ormar
Describe the bug When asynchronously attempting to get an item that does not exist in the db with
get_or_create
twice (or more times) concurrently, on a model with anormar.UniqueColumns
-constraint,asyncpg.UniqueViolationError
is thrown for the losing attempt at creating it.To Reproduce
Define a model with an unique constrant:
Attempt to
get_or_create
something that doesnt exists twice or more times concurrently with asyncio tasks (or taskgroups):The above test results in the following error:
Expected behavior Ideally, I'd expect to get the existing/newly created object from all attempts at using
get_or_create
.Versions (please complete the following information):
ormar
version: 0.12.1pydantic
version: 0.10.2fastapi
version: N/A (0.85.0)