= Solution
A cyclic <Communicating Scala Objects> component has a communication loop followed by a close-down phase. `repeat { ... }` catches the library's normal `Stopped` family of exceptions, including closure, and leaves the loop; ordinary `while` code instead needs the explicit handler used above. In either case, cleanup closes every owned input port with `closeIn` and every owned output port with `closeOut`, preferably in `finally`. Reclosing a one-to-one port is harmless. A parallel composition completes only when every component has completed; one component returning does not automatically cancel all the others.
The producer closes `left` on return. The <strict buffer> observes this, drains its <FIFO queue> into a cooperating consumer, and closes `right`; the consumer's next read detects closure and enters its own cleanup. Conversely, the consumer closes `right` on return; the <strict buffer> then closes `left`, releasing a blocked producer write or causing its next write to stop. Thus,
$$
\boxed{\text{upstream closure drains forward; downstream closure cancels backward}.}
$$
Eventual termination assumes that surviving components reach their next communication or closure check, and that the consumer keeps accepting a finite outstanding backlog after producer termination. A component stuck forever in unrelated computation cannot be stopped by closing a port alone.
Back to article page