Circuit Self-managed infrastructure, programmatic monitoring and orchestration

Using channels

Channel elements are FIFO queues for binary messages. A channel physically lives on a particular host. It supports a ‘send’ operation which pushes a new binary message to the queue, and a ‘receive’ operation which removes the next binary message from the queue.

On creation, channels can be configured to buffer a fixed non-negative number of messages. When the buffer is full, send operations block until a message is received. Receive operations, on the other hand, block if there are no pending messages in the buffer, until the next send operation is performed.

Channels are created using the anchor's MakeChan method:

	MakeChan(n int) (Chan, error)

For instance,

	ch, err := anchor.MakeChan(0)
	if err != nil {
		… // this anchor is already busy
	}

An application error will be returned only if the anchor already has an element attached to it. The integer parameter specifies the number of messages the channel will buffer. This must be a non-negative integer.

Interacting with the channel is done using the channel element's interface:

	type Chan interface {
		Send() (io.WriteCloser, error)
		Recv() (io.ReadCloser, error)
		Close() error
		Stat() ChanStat
		Scrub()
	}

The Scrub method will forcefully abort and discard the channel element, even if messages are pending in the channel's buffer.

Sending and receiving messages

The send/receive mechanism transports io.ReadWriteCloser pipes between the sender and the receiver. The sender gets the write end and the receiver gets the read end of the pipe.

To send a message, the user invokes Send. If the channel has been closed or aborted, a non-nil application error is returned. Otherwise, a new pipe is created. Send attempts to send the pipe itself through the channel. It will block until there is space in the channel buffer or there is a matching call to Receive.

When Send unblocks it returns an io.WriteCloser wherein the user writes the content of the message and closes the stream to indicate end of message.

	w, err := ch.Send()
	if err != nil {
		… // channel has been closed
	}
	w.Write(msg)
	w.Close()

To receive a message, the user invokes Recv. The operation blocks until there is a pipe in the channel buffer or a matching call to Send. Receive will return an application error if the channel has been closed. Otherwise it returns the reader end of the pipe received.

Channel closure

Channels can be closed synchronously with the Close method. The closure event will be communicated to the receiver after all pending messages have been received. Close returns an application error only if the channel has already been clsoed.

An alternative method of closing the channel is to invoke Scrub. This will abort the channel and discard any pending messages.

Retrieving channel state

The Stat method can be called asynchronously to retrieve the current state of the channel. The returned structure includes the channel capacity, whether the channel has been closed or aborted, the number of messages sent and received. (The difference of sent and received messages is the count of messages pending reception in the channel buffer.)

	type ChanStat struct {
		Cap int
		Closed bool
		Aborted bool
		NumSend int
		NumRecv int
	}