Azure-cosmos-dotnet-v2: Handling Unique Constraint Conflicts

Created on 13 Jun 2018  ·  13Comments  ·  Source: Azure/azure-cosmos-dotnet-v2

Hi,

This defect - https://github.com/Azure/azure-docs-sdk-dotnet/issues/612 - has pretty much the only example online that i can locate on how to handle unique constraint collision.. however, it seems to behave differently depending on if you use UpsertDocumentAsync, or CreateDocumentAsync

{
    await client.UpsertDocumentAsync(uri, entity);  // 449 Retry With   -> 'Unique index constraint violation.'
    await client.CreateDocumentAsync(uri, entity);  // 409 Conflict     -> 'Unique index constraint violation.'
}

i am using v1.22.0 of the Microsoft.Azure.DocumentDB pkg.. is this a defect? or is there a pattern to handle this that i am missing?

Most helpful comment

@semplea

Sorry for confusion. Let me explain my answer.

_Preconditions:_
We want to insert the following document:

{
     "id": "1",
     "name": "Alex"
}

And cosmos collection is configured to have to unique constraint for Name

_Steps:_

  1. Call Upsert first time -> OK, as we didn't have any documents before;
  2. Call Upsert second time with the same name ("Alex"), but with different id (eq 2, for instance) -> 449 error, as we tried to insert another document (with different id) with name, which is already presented in the collection.

So, we end up with exception when we break unique constraint AND entity that needs to be inserted has other id than entity which is already in the collection.

Sounds pretty logical to me, doesn't?

All 13 comments

This documentation seems suggest that the UpsertDocumentAsync should return 409 ...

https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.client.documentclient.upsertdocumentasync

Returning 449 with unique constraint error is incorrect, and will be fixed soon.

Without unique index the behavior is correct: if one transaction stats to upsert a doc which doesn’t exist (upsert->create), and another one created the doc concurrently, the upsert results in 449 (retry with/concurrency violation), so that the client would retry and on retry upsert would result in replace. With unique index the retry may not always be the solution, because another doc may be created with same unique value. For unique index, status code should be 409.

To work around until the fix is there, you may special-case 449 with error message that contains “Unique index constraint violation”.

not sure that comment constitutes closed though..

Issue still exists. Are there any plan to fix it?

@markjbrown , @christopheranderson

This issue is still relevant

Sorry for delay. The should be fixed in December, the change is in the pipeline.

Maybe I'm missing something, but why would this throw an error at all? isn't the point of an upsert query to either insert a document, or if it already exists (based on the unique id) update the document.
This seems relevant: https://github.com/Azure/azure-docs-sdk-dotnet/issues/729#issuecomment-409355908

Maybe I'm missing something, but why would this throw an error at all? isn't the point of an upsert query to either insert a document, or if it already exists (based on the unique id) update the document.
This seems relevant: Azure/azure-docs-sdk-dotnet#729 (comment)

i raised this so long ago i can't even remember chap... 🍺

@semplea Upsert works as you expect in case object contains same id. The issue is more about when collection has unique constraint which is differ than id.

Thanks for the explanation @spzSource, I hadn't found this explicitly anywhere in the documentation, so it's quite helpful!

However, the logic still seems a bit flawed to me. I don't see the fundamental difference between a unique key constraint, and the default id field, which is also unique. Say a collection has a constraint on multiple keys (e.g. 'uniqueKeys': [{'paths': ['/a_id', '/b_id']}]). Any updates on documents in such a collection would then be impossible.

@semplea

Sorry for confusion. Let me explain my answer.

_Preconditions:_
We want to insert the following document:

{
     "id": "1",
     "name": "Alex"
}

And cosmos collection is configured to have to unique constraint for Name

_Steps:_

  1. Call Upsert first time -> OK, as we didn't have any documents before;
  2. Call Upsert second time with the same name ("Alex"), but with different id (eq 2, for instance) -> 449 error, as we tried to insert another document (with different id) with name, which is already presented in the collection.

So, we end up with exception when we break unique constraint AND entity that needs to be inserted has other id than entity which is already in the collection.

Sounds pretty logical to me, doesn't?

Thanks for the additional explanation @spzSource! This makes more sense to me now!

@mkolt so it seems like this has maybe finally been released to the production systems? Some of our error handling has suddenly snapped, and i received no update / confirmation of an impending change to the service.

Is/was this being tracked somewhere else??

I have also emailed the askcosmosdb group...

Was this page helpful?
0 / 5 - 0 ratings