Skip to content

panic: send on closed channel in mirror() #19

@mikluko

Description

@mikluko

Description

The mirror() function in nats.go can panic with "send on closed channel" when the consumer closes mch while messages are still being received on nch.

Stack trace

panic: send on closed channel

goroutine 5677 [running]:
github.com/mikluko/peanats.(*connectionImpl).mirror.func1()
    github.com/mikluko/peanats@v0.20.2/nats.go:199 +0x4c
created by github.com/mikluko/peanats.(*connectionImpl).mirror in goroutine 5831
    github.com/mikluko/peanats@v0.20.2/nats.go:197 +0x80

Root cause

https://github.com/mikluko/peanats/blob/main/nats.go#L196-L203

func (c *connectionImpl) mirror(mch chan Msg) chan *nats.Msg {
    nch := make(chan *nats.Msg, cap(mch))
    go func() {
        for msg := range nch {
            mch <- NewMsg(msg)  // panics if mch is closed
        }
    }()
    return nch
}

The goroutine doesn't handle the case where mch is closed by the consumer.

Suggested fix

Use a done channel or recover:

func (c *connectionImpl) mirror(mch chan Msg) chan *nats.Msg {
    nch := make(chan *nats.Msg, cap(mch))
    go func() {
        defer func() {
            recover() // ignore send on closed channel
        }()
        for msg := range nch {
            mch <- NewMsg(msg)
        }
    }()
    return nch
}

Or better, use select with a done channel to allow graceful shutdown.

Version

v0.20.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions