Transactional batch cosmos - write IF certain value read in partition

Sep 16 2020

Using transactional batch in cosmos, is it possible to query a partition within a collection (Select * from partition where openOrder=1) and then IF the query returns that there are no open orders, add an item to the collection.

Or you could have the write first, and then have the conditional read (Select * from partition where openOrder=1 and id={unique GUID just written}) and then if the 2nd read fails, the write would be reversed (?).

Would want this to be done in one atomic operation because I don't want to think there are no open orders and then another process writes an open order before this process can.

If not, is it possible to do this a different way?

**Edit 3:30 PM PT 9/16 with attempted solution that wrote a document when I tested it **

function checkOpenOrder(inputDocString, query){
    console.log("Stored Procedure Starting")
    var context = getContext(); 
    var container = context.getCollection();
    var containerLink = container.getSelfLink();
    var response = context.getResponse(); 

    var isAccepted = container.queryDocuments(
        container.getSelfLink(), 
        query,
        function (err, items, options) {
            if (err) throw err;
            // Query would be fed in such that if there is no open order, no items would return in the collection 

            if (items.length == 0){ 
                var docCreated = container.createDocument(containerLink, inputDocString, 
                    function (err2, itemWritten) {
                        if (err2) throw err2;
                        // else was successfully able to write document?
                        response.setBody("Wrote document");
                    });

            }
            else { 
               
                response.setBody("Order currently open");
            }
            

        });
    if (!isAccepted) throw new Error('The query was not accepted by the server.')

    
}

Editar: pregunta final 9/17 ¿Me gustaría establecer el grado máximo de paralelismo en 1 para asegurarme de que el procedimiento almacenado no se pueda ejecutar 2x en la misma partición al mismo tiempo? (que podría crear una condición de carrera si ve que no hay una orden abierta -> crea un documento y luego tenemos 2 órdenes abiertas). Creo que quiero deshabilitar la consulta entre particiones (además no la necesitaré).

Respuestas

1 MoB. Sep 16 2020 at 04:20

Me temo que la respuesta es no. TransactionalBatch solo admite operaciones de escritura. Si desea una transacción de lectura y escritura de documentos cruzados como en su caso, solo tiene dos opciones:

  1. Realice la transacción en un procedimiento almacenado. Esto solo funciona si está trabajando dentro de una sola partición y no necesita realizar ninguna operación no relacionada con Cosmos dentro de su transacción. De su descripción, esto debería estar bien.

  2. Implemente la transacción en el lado del cliente con algún tipo de bloqueo.

1 AnkitVijay Sep 16 2020 at 06:01

Como se menciona en una de las respuestas, TransactionBatchsolo admite operaciones de escritura. Nos habíamos enfrentado a un desafío similar con Cosmos DB. Así es como podría abordar el problema:

  • Puede introducir un concepto de "Sesión" donde la operación Commit / Save ocurre al final de la solicitud / sesión.
  • Cree un mapa / caché de identidad local para todas las Getoperaciones. Es decir, primero verifique si el documento de Cosmos está presente en la caché local, si es así, luego devuélvalo desde la caché local. De lo contrario, tráelo a Cosmos.
  • La operación Create, Upserto Deletesolo se guarda en la memoria caché local y actualiza el mapa de identidad.
  • La Commitoperación se llama al final de la solicitud. Utiliza los elementos del caché local para crear un lote de transacciones y guardarlo en Cosmos.

La ventaja de este enfoque es que puede hacer todo esto en C # sin ningún código de bloqueo complejo.

Algunas limitaciones de este enfoque son:

  • Solo puede funcionar dentro de una sola partición (que creo que está bien para ti)
  • Dado que está trabajando con identificadores de Cosmos Document, puede ser complicado pasar un archivo personalizado QueryDefinitionque no funciona ids.