Middle · Trace · Channels own completion and terminal failure

Trace buffered values, the terminal exception type, and a later write attempt.

Think through your answer before opening the explanation.

Runtime & concurrency

using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Reflection;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

var channel = System.Threading.Channels.Channel.CreateBounded<int>(2);
if (!channel.Writer.TryWrite(2) || !channel.Writer.TryWrite(4)) throw new InvalidOperationException();
channel.Writer.TryComplete(new InvalidOperationException("controlled"));
var items = new List<int>();
while (channel.Reader.TryRead(out int item)) items.Add(item);
Console.WriteLine("items:" + string.Join(",", items));
try { await channel.Reader.Completion; } catch (InvalidOperationException error) { Console.WriteLine($"failure:{error.GetType().Name}"); }
Console.WriteLine($"write-after:{channel.Writer.TryWrite(6)}");
Reveal answer and reasoning

The output is items:2,4, failure:InvalidOperationException, and write-after:False. Two and four are accepted before completion. Completing the writer with the controlled error stops later admission but leaves those values readable, so TryRead drains them in their queued order. Awaiting Reader.Completion then observes the supplied fault rather than treating the drained channel as successful.

The final TryWrite fails because writer admission has ended. A common wrong trace drops the buffered items or suppresses the failure after reading them. Another assumes the failure must be a particular ReadAsync closed-channel wrapper even though this code directly awaits the Completion task instead. The snippet uses real Channel APIs with bounded capacity and no OS workers. Its lifecycle result does not demonstrate durable storage, consumer processing success, or a distributed shutdown protocol beyond the operations actually executed.

What a strong answer covers

  • Accepted values drain in order before terminal observation.
  • Completion faults with the chosen InvalidOperationException.
  • Later TryWrite returns false.

Common pitfall

Ignoring the actual API being awaited or treating drained data as proof of successful terminal completion.

Follow-up questions

  1. What changes with successful completion?
  2. What if the channel is empty when completed?

Self-review

Choose what to revisit. These marks are your own assessment and are separate from lesson completion.

Primary references

Open lesson and code ↗

← All interview questions