/// <summary>
        /// Try to abort the transaction.
        /// </summary>
        ///
        /// <param name="transaction">
        /// The transaction to abort.
        /// </param>
        /// <param name="cancellationToken">
        /// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
        /// </param>
        ///
        /// <returns>Whether the abort call has succeeded.</returns>
        private async Task <bool> TryAbort(AsyncTransaction transaction, CancellationToken cancellationToken)
        {
            try
            {
                if (transaction != null)
                {
                    await transaction.Abort();
                }
                else
                {
                    await this.session.AbortTransactionAsync(cancellationToken);
                }
            }
            catch (Exception e)
            {
                this.logger.LogWarning("This session is invalid on ABORT: {}", e);
                return(false);
            }

            return(true);
        }
Exemple #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="AsyncTransactionExecutor"/> class.
 /// </summary>
 ///
 /// <param name="transaction">
 /// The <see cref="AsyncTransaction"/> object the <see cref="AsyncTransactionExecutor"/> wraps.
 /// </param>
 /// <param name="serializer">The serializer to serialize and deserialize Ion data.</param>
 internal AsyncTransactionExecutor(AsyncTransaction transaction, ISerializer serializer = null)
 {
     this.transaction = transaction;
     this.serializer  = serializer;
 }
Exemple #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="AsyncTransactionExecutor"/> class.
 /// </summary>
 ///
 /// <param name="transaction">
 /// The <see cref="AsyncTransaction"/> object the <see cref="AsyncTransactionExecutor"/> wraps.
 /// </param>
 internal AsyncTransactionExecutor(AsyncTransaction transaction)
 {
     this.transaction = transaction;
 }
        /// <summary>
        /// Execute the Executor lambda asynchronously against QLDB and retrieve the result within a transaction.
        /// </summary>
        ///
        /// <param name="func">The Executor lambda representing the block of code to be executed within the transaction.
        /// This cannot have any side effects as it may be invoked multiple times, and the result cannot be trusted
        /// until the transaction is committed.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive
        /// notice of cancellation.</param>
        /// <typeparam name="T">The return type.</typeparam>
        ///
        /// <returns>The return value of executing the executor. Note that if you directly return a
        /// <see cref="IAsyncResult"/>, this will be automatically buffered in memory before the implicit commit to
        /// allow reading, as the commit will close any open results. Any other <see cref="IAsyncResult"/> instances
        /// created within the executor block will be invalidated, including if the return value is an object which
        /// nests said <see cref="IAsyncResult"/> instances within it.
        /// </returns>
        ///
        /// <exception cref="TransactionAbortedException">
        /// Thrown if the Executor lambda calls <see cref="AsyncTransactionExecutor.Abort"/>.
        /// </exception>
        /// <exception cref="AmazonServiceException">
        /// Thrown when there is an error executing against QLDB.
        /// </exception>
        internal async Task <T> Execute <T>(
            Func <AsyncTransactionExecutor, Task <T> > func,
            CancellationToken cancellationToken)
        {
            ValidationUtils.AssertNotNull(func, "func");

            AsyncTransaction transaction   = null;
            string           transactionId = QldbTransactionException.DefaultTransactionId;

            try
            {
                transaction = await this.StartTransaction(cancellationToken);

                transactionId = transaction.Id;
                T returnedValue = await func(new AsyncTransactionExecutor(transaction));

                if (returnedValue is IAsyncResult result)
                {
                    returnedValue = (T)(object)(await AsyncBufferedResult.BufferResultAsync(result));
                }

                await transaction.Commit();

                return(returnedValue);
            }
            catch (TransactionAbortedException)
            {
                throw;
            }
            catch (InvalidSessionException ise)
            {
                if (IsTransactionExpiredException(ise))
                {
                    throw new QldbTransactionException(
                              transactionId,
                              await this.TryAbort(transaction, cancellationToken),
                              ise);
                }
                else
                {
                    throw new RetriableException(transactionId, false, ise);
                }
            }
            catch (OccConflictException occ)
            {
                throw new RetriableException(transactionId, true, occ);
            }
            catch (AmazonServiceException ase)
            {
                if (ase.StatusCode == HttpStatusCode.InternalServerError ||
                    ase.StatusCode == HttpStatusCode.ServiceUnavailable)
                {
                    throw new RetriableException(
                              transactionId,
                              await this.TryAbort(transaction, cancellationToken),
                              ase);
                }

                throw new QldbTransactionException(
                          transactionId,
                          await this.TryAbort(transaction, cancellationToken),
                          ase);
            }
            catch (Exception e)
            {
                throw new QldbTransactionException(
                          transactionId,
                          await this.TryAbort(transaction, cancellationToken),
                          e);
            }
            finally
            {
                transaction?.Dispose();
            }
        }