We're back to the channel pump for another round. In the previous channel pump article we had introduced an asynchronous coroutine between the main channel pump loop and a callback on acquiring a channel throttle. This use of coroutines let us suspend the channel pump until a throttle was available without having to tie up a thread during that wait. That left us with the following channel pump code.
ChannelPumpBEGIN LOOP AcceptChannel IF AcquireThrottle THEN DoWork (runs in the background) ELSE STOP (GotThrottle will run when a throttle is free)END LOOP
GotThrottleDoWork (runs in the background)ChannelPump
DoWorkMessagePumpCloseChannelReleaseThrottle
Now, let's look at the problem of accepting a channel. In many cases, we could fail to actually get a channel when we call AcceptChannel. For example, the channel listener may have been closed, the timeout for listening may have expired, or the network may have gone down. Some of these conditions are transient and some indicate that no more channels will ever be created. What we really want to know after failing to get a channel is whether the channel pump should keep trying.
In a message pump, we can build the desired behavior by calling TryReceive on the channel. Unfortunately, there's no equivalent TryAcceptChannel. We'll have to build our own TryAcceptChannel to replace the call to AcceptChannel in ChannelPump. Under the covers, we'll call AcceptChannel inside of a try-catch block. The trick is to handle the exceptions properly and then return whether TryAcceptChannel succeeded in accepting a channel. Here's how TryAcceptChannel should handle each case.
We can finish up by rewriting ChannelPump to take advantage of our new TryAcceptChannel method.
ChannelPumpBEGIN LOOP IF TryAcceptChannel THEN IF channel IS NULL THEN STOP END IF IF AcquireThrottle THEN DoWork (runs in the background) ELSE STOP (GotThrottle will run when a throttle is free) END IF END IFEND LOOP
Next time: Checking for ServiceSecurityContext