Example #1
0
 public ValueTask EnqueueAsync(
     KuduOperation operation,
     CancellationToken cancellationToken = default)
 {
     return(_writer.WriteAsync(operation, cancellationToken));
 }
Example #2
0
    private async Task <bool> DequeueAsync(List <KuduOperation> batch)
    {
        ChannelReader <KuduOperation> reader     = _reader;
        CancellationToken             flushToken = _flushCts.Token;
        bool flushRequested = flushToken.IsCancellationRequested;
        int  capacity       = _options.BatchSize;

        // Drain the queue before asynchronously waiting until the batch
        // is full or the flush interval is met.
        while (reader.TryRead(out var operation))
        {
            batch.Add(operation);

            if (batch.Count >= capacity)
            {
                // The batch is full, but we can't complete a pending flush
                // here as there could still be more items in the queue.
                return(false);
            }
        }

        if (flushRequested)
        {
            // Short-circuit if a flush was requested and the queue is empty.
            return(true);
        }

        try
        {
            if (batch.Count == 0)
            {
                // Wait indefinitely for the first operation.
                KuduOperation operation = await reader.ReadAsync(flushToken)
                                          .ConfigureAwait(false);

                batch.Add(operation);
            }

            using var timeout   = new CancellationTokenSource(_options.FlushInterval);
            using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(
                      timeout.Token, flushToken);
            var token = linkedCts.Token;

            while (batch.Count < capacity)
            {
                KuduOperation operation = await reader.ReadAsync(token)
                                          .ConfigureAwait(false);

                batch.Add(operation);
            }
        }
        catch (OperationCanceledException)
        {
            // We've hit the flush interval, or someone called FlushAsync().
            while (batch.Count < capacity &&
                   reader.TryRead(out var operation))
            {
                batch.Add(operation);
            }
        }
        catch (ChannelClosedException)
        {
            // This session was disposed.
            // The queue is empty and is not accepting new items.
        }

        return(flushRequested && batch.Count < capacity);
    }