Пример #1
0
        private async Task <TAutoNrData> UpdateAutoNrWithRetries <TSequenceData, TAutoNrData>(string sequence, string aggregateId, AutoNrUpdater <TSequenceData, TAutoNrData> updater, int retries)
            where TSequenceData : class
            where TAutoNrData : class
        {
            var sequenceRow = await GetSequenceRow(sequence);             // or null

            if (sequenceRow == null)
            {
                throw new Exception($"Sequence not found: {sequence}");
            }

            var idRow = await GetIdRow(sequence, aggregateId);

            if (idRow == null)
            {
                throw new Exception($"Agreggate with id {aggregateId} not found in sequence {sequence}");
            }

            var nrRow = await GetNrRow(sequence, idRow.Nr);

            if (nrRow == null)
            {
                throw new Exception($"Agreggate with id {aggregateId} not found in sequence {sequence}");
            }

            var prevNrRow = await GetNrRow(sequence, idRow.Nr - 1);

            var nextNrRow = await GetNrRow(sequence, idRow.Nr + 1);

            var result = updater(
                nrRow.GetData <TAutoNrData>(),
                sequenceRow.GetData <TSequenceData>(),
                prevNrRow != null ? prevNrRow.GetData <TAutoNrData>() : null,
                nextNrRow != null ? nextNrRow.GetData <TAutoNrData>() : null);

            sequenceRow.SetData(result.SequenceData);
            nrRow.SetData(result.NrData);

            var batch = new TableBatchOperation();

            batch.Add(TableOperation.Replace(sequenceRow));       // OperationIndex 0
            batch.Add(TableOperation.Replace(nrRow));             // OperationIndex 1
            if (prevNrRow != null)
            {
                batch.Add(TableOperation.Merge(prevNrRow));                 // OperationIndex 2
            }
            if (nextNrRow != null)
            {
                batch.Add(TableOperation.Merge(nextNrRow));                 // OperationIndex 2 or 3
            }
            try
            {
                await table.ExecuteBatchAsync(batch);
            }
            catch (StorageException storageException)
            {
                int    operationIndex;
                string errorCode;
                if (!TryParseStorageException(storageException, out operationIndex, out errorCode))
                {
                    throw;
                }

                if (errorCode == "UpdateConditionNotSatisfied")
                {
                    if (retries >= 0)
                    {
                        return(await UpdateAutoNrWithRetries(sequence, aggregateId, updater, retries - 1));
                    }
                    var rowName = new string[] { "sequence", "auto-nr", "prev-auto-nr", "next-auto-nr" }[operationIndex];
                    throw new AutoNrOptimisticException($"Optimistic lock failed because {rowName} has changed. Sequence: {sequence}, nr:{idRow.Nr}.");
                }

                throw;
            }

            return(result.NrData);
        }
Пример #2
0
 public async Task <TAutoNrData> UpdateAutoNr <TSequenceData, TAutoNrData>(string sequence, string aggregateId, AutoNrUpdater <TSequenceData, TAutoNrData> updater)
     where TSequenceData : class
     where TAutoNrData : class
 {
     return(await UpdateAutoNrWithRetries(sequence, aggregateId, updater, MaxRetries));
 }
Пример #3
0
        public Task <TNrData> UpdateAutoNr <TSequenceData, TNrData>(string sequence, string aggregateId, AutoNrUpdater <TSequenceData, TNrData> updater)
            where TSequenceData : class
            where TNrData : class
        {
            Sequence contextLock = sequences[sequence];

            if (contextLock == null)
            {
                throw new Exception($"Sequence not found: {sequence}");
            }

            lock (contextLock)             // only one thread per context
            {
                var context = sequences[sequence];
                if (context == null)
                {
                    throw new Exception($"Sequence not found: {sequence}");
                }
                long seqNr;
                if (!context.TryGet(aggregateId, out seqNr))
                {
                    throw new Exception($"Agreggate with id {aggregateId} not found in sequence {sequence}");
                }

                var data   = context.GetAutoNrDataByNr <TNrData>(seqNr);
                var prev   = context.GetAutoNrDataByNr <TNrData>(seqNr - 1);
                var next   = context.GetAutoNrDataByNr <TNrData>(seqNr + 1);
                var result = updater(data, context.GetConfig <TSequenceData>(), prev, next);
                context.SetData(aggregateId, seqNr, result.NrData);
                context.SetConfig(result.SequenceData);
                return(Task.FromResult(result.NrData));
            }
        }