0

I have a service which wants to open 28 connections to different S3 objects to save them there for later reuse.

At this time, I'm testing my code against localstack to make sure it will work and avoid potential confusion in our real S3 environment.

When I open up to about 8 connections in a raw, things work as expected. Nearly every time I go over that number, it starts creating "server keep idle connection" errors. The following is an example of the error in its entirety:

Put http://192.168.26.95:4572/bucket-name/test-12.mp3?partNumber=1&uploadId=ofutQ7QNwlpy0q4jYAofwhZQ130mMqk5hKkKsI2b50bBNHB1CfQI2IuUg: http: server closed idle connection

Just in case, I tried with one connection, left it open for some time without sending anything to it and it worked just fine. No "idle connection" errors. So I'm pretty sure the error label is wrong. It is more likely an error due to an overwhelmed listener (i.e. too many connections in a row, the connection pipe is full).

I have two main questions:

  1. Is there a way to fix the problem on the client side? I tried to pace the connections, but even with a sleep of 1 second between each connection (which is way too long) I still get the error.

  2. Would there be a way to setup localstack to allow for more connections to happen in a row? I'm using the Docker version.

For (1), I looked a bit in MinIO, the PutObject() does not seem to have any way to increase the timeout for a connection to succeed, or a number of repeat attempts, which would make my life easier.

For (2), it would need to match what a real S3 environment allows. So if the existing settings of localstack already match a real S3, I'm afraid we need to make (1) work.


The following is a sample which doesn't fail as bad as the main code, but with a count of 28, it still fails most of the time. The length of data or waiting before writing to the pipes or not doesn't seem to affect the PutObject() which will generate that "idle connection" error. The number of connections (calls to PutObject()) does have a strong effect.

package main

import (
    "fmt"
    "io"
    "os"
    "time"

    "github.com/minio/minio-go"
)

func main() {
    var mc *minio.Client
    var err error
    var size int64
    var count int = 28
    var outputRC []io.ReadCloser
    var inputPipe []*os.File

    mc, err = minio.New("192.168.2.95:4572", "localstack", "localstack", false)
    if err != nil {
        fmt.Printf("error: minio.New(): %v\n", err)
        os.Exit(1)
    }

    outputRC = make([]io.ReadCloser, count)
    inputPipe = make([]*os.File, count)

    // create pipes which are used to send data to the S3 objects
    for i := 0; i < count; i++ {
        // reader, writer, err = os.Pipe()
        outputRC[i], inputPipe[i], err = os.Pipe()
        if err != nil {
            fmt.Printf("error: os.Pipe() #%d: %v\n", i, err)
            os.Exit(1)
        }
    }

    // now setup the readers (read pipe output and save in S3 objects)
    for i := 0; i < count; i++ {
        time.Sleep(100 * time.Millisecond)
        idx := i
        go func() {
            filename := fmt.Sprintf("whatever-%d.mp3", idx)
            size, err = mc.PutObject("bucket-name", filename, outputRC[idx], -1, minio.PutObjectOptions{ContentType:"audio/mpeg"})
            if err != nil {
                fmt.Printf("error: mc.PutObject() #%d: %v\n", idx, err)
                //os.Exit(1)
            }
        }()
    }

    //time.Sleep(5 * time.Second)

    for i := 0; i < count; i++ {
        fmt.Fprintf(inputPipe[i], "FILE #%d\n", i)
    }

    //time.Sleep(10 * time.Second)

    for i := 0; i < count; i++ {
        inputPipe[i].Close()
    }

    time.Sleep(60 * time.Second)
}
Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • 2
    What are "server keep idle connection" errors? Can you please show the exact error you are receiving, and from which call? A [mre] would be even better. – JimB Jan 23 '20 at 22:49
  • @JimB Okay, I added the complete error message and a minimal example. As for the call, that's the one with the link `PutObject()`. Internally, I would imagine that it uses HTTP objects. From what I've found about that error message, that very message would be in the Go implementation of `net/http`. – Alexis Wilke Jan 23 '20 at 23:48
  • 1
    The error is much easier to locate when you provide the correct error text. If you look at the comment on that error, it explains the situation in which it can be returned, with more details here: https://github.com/golang/go/issues/19943#issuecomment-355607646. It's likely a problem with the test server you're using, maybe with minio itself, but if you're properly sending and closing the files there's probably not much you can do. – JimB Jan 24 '20 at 15:26

0 Answers0