How to prevent sync.Pool creating two instances

Issue

I am implementing a TCP Connection pool for logging to fluent-bit, here’s the code

import (
    "fmt"
    "log"
    "net"
    "sync"
)

type FluentConnectionPool struct {
    sync.Mutex
    pool          *sync.Pool
}

func (fl *FluentConnectionPool) Log(message string) {
    fl.Lock()
    defer fl.Unlock()

    conn := fl.pool.Get().(*net.TCPConn)
    defer fl.pool.Put(conn)

    fmt.Printf("using: %v\n", conn.LocalAddr())

    if _, err := conn.Write([]byte(message)) ; err != nil {
        log.Fatal(err)
    }
}

func (fl *FluentConnectionPool) Close() {
    conn := fl.pool.Get().(*net.TCPConn)
    defer conn.Close()

    fmt.Printf("Closing: %v\n", conn.LocalAddr())
}

func New(address string) (*FluentConnectionPool, error) {
    fluentAddress, err := net.ResolveTCPAddr("tcp", address)

    if err != nil {
        return nil, err
    }

    pool := &sync.Pool{New: func() interface{} {
        connection, _ := net.DialTCP("tcp", nil, fluentAddress)
        return connection
    }}

    return &FluentConnectionPool{
        pool:          pool,
    }, nil
}

when I test the code like this

import "time"

func main() {
    pool, _ := New("localhost:5170")
    defer pool.Close()

    for i := 0 ; i < 10 ; i++ {
        go func() {
               pool.Log(`{"data": {"name": "name here"}}`)
        }()
    }

    time.Sleep(1 * time.Second)
}

the output is like this

using: 127.0.0.1:43990
using: 127.0.0.1:43990
using: 127.0.0.1:43990
using: 127.0.0.1:43990
using: 127.0.0.1:43990
using: 127.0.0.1:43990
using: 127.0.0.1:43990
using: 127.0.0.1:43990
using: 127.0.0.1:43990
using: 127.0.0.1:43994
Closing: 127.0.0.1:43994

I don’t understand why the connection create twice (43990 & 43994) even though I have locked the function, so the connection on 43990 remains open, could you please explain why did this happened?

Thank You!

Solution

This from the Pool docs might explain the behaviour:

Any item stored in the Pool may be removed automatically at any time without notification. If the Pool holds the only reference when this happens, the item might be deallocated.

It is likely that the pool removed the connection you used.

Answered By – Burak Serdar

Answer Checked By – Pedro (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.