public ValueTask EnqueueAsync( KuduOperation operation, CancellationToken cancellationToken = default) { return(_writer.WriteAsync(operation, cancellationToken)); }
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); }