go-whatsapp: QR Code benchmark generate memory problem!

Hello, I have this function served via swagger

func ScanQr(params profile.ScanQrParams) middleware.Responder {
        qr := make(chan string)
        errCh := make(chan error)

        go func() {
                sessionID := params.SessionID.String()
                handler, err := wa.Login(qr, params.ProxyURL, sessionID)
                if err != nil {
                        errCh <- err
                }
                wa.Connections[sessionID] = handler
        }()

        select {
        case err := <-errCh:
                errText := err.Error()
                return profile.NewScanQrDefault(500).WithPayload(&models.Error{
                        Code:    500,
                        Message: &errText,
                })
        case qrText := <-qr:
                return profile.NewScanQrOK().WithPayload(&models.QRCode{
                        Base64: qrText,
                })

        }

}

I tried to flood the function with 50 requests to understand what will be going on if we have 50 users online asking for the QR… Well, i got a server panic a VERY LONG error but I will add the deader of the error.

runtime: out of memory: cannot allocate 26214400-byte block (3927212032 in use)
fatal error: out of memory

runtime stack:
runtime.throw(0x87ae49f, 0xd)
        /usr/local/go/src/runtime/panic.go:774 +0x6a
runtime.largeAlloc(0x1900000, 0x8090101, 0xe740ed20)
        /usr/local/go/src/runtime/malloc.go:1140 +0x108
runtime.mallocgc.func1()
        /usr/local/go/src/runtime/malloc.go:1033 +0x39
runtime.systemstack(0x9588700)
        /usr/local/go/src/runtime/asm_386.s:399 +0x53
runtime.mstart()
        /usr/local/go/src/runtime/proc.go:1146

goroutine 2083 [running]:
runtime.systemstack_switch()
        /usr/local/go/src/runtime/asm_386.s:360 fp=0x9c1397c sp=0x9c13978 pc=0x8098d00
runtime.mallocgc(0x1900000, 0x86dc340, 0x87ef801, 0x84cc9a40)
        /usr/local/go/src/runtime/malloc.go:1032 +0x6a8 fp=0x9c139d0 sp=0x9c1397c pc=0x8052508
runtime.makeslice(0x86dc340, 0x1900000, 0x1900000, 0xe74b9cb8)
        /usr/local/go/src/runtime/slice.go:49 +0x4f fp=0x9c139e4 sp=0x9c139d0 pc=0x8085acf
bufio.NewReaderSize(...)
        /usr/local/go/src/bufio/bufio.go:56
github.com/gorilla/websocket.newConn(0x88e4140, 0x1232000, 0x0, 0x1900000, 0xa00000, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        /root/go/pkg/mod/github.com/gorilla/websocket@v1.4.2/conn.go:293 +0x2e1 fp=0x9c13a4c sp=0x9c139e4 pc=0x85a56d1
github.com/gorilla/websocket.(*Dialer).DialContext(0x950c340, 0x88df800, 0x950cfc0, 0x87b9975, 0x19, 0x8d96fc68, 0x0, 0x0, 0x0, 0x0)
        /root/go/pkg/mod/github.com/gorilla/websocket@v1.4.2/client.go:327 +0xc6f fp=0x9c13be4 sp=0x9c13a4c pc=0x85a2def
github.com/gorilla/websocket.(*Dialer).Dial(0x950c340, 0x87b9975, 0x19, 0x8d96fc68, 0x8d96fccc, 0x84dc65e, 0x0, 0x0)
        /root/go/pkg/mod/github.com/gorilla/websocket@v1.4.2/client.go:106 +0x4d fp=0x9c13c10 sp=0x9c13be4 pc=0x85a1fad
github.com/Rhymen/go-whatsapp.(*Conn).connect(0x9a253b0, 0x0, 0x0)
        /root/go/pkg/mod/github.com/!rhymen/go-whatsapp@v0.1.1-0.20200408093540-2f227c53b44f/conn.go:163 +0x1a1 fp=0x9c13d34 sp=0x9c13c10 pc=0x85b8601
github.com/Rhymen/go-whatsapp.NewConn(0xf8475800, 0xd, 0x87bc8dd, 0x1d, 0x121cdb8)
        /root/go/pkg/mod/github.com/!rhymen/go-whatsapp@v0.1.1-0.20200408093540-2f227c53b44f/conn.go:125 +0x119 fp=0x9c13d5c sp=0x9c13d34 pc=0x85b8229
bitbucket.org/rockyOO7/wa-api/whatsapp.NewConn(0x0, 0x98ff6f8, 0x0, 0x0)
        /home/beshoo/go-wapi/wa/whatsapp/main.go:164 +0x1b8 fp=0x9c13dcc sp=0x9c13d5c pc=0x8606438
bitbucket.org/rockyOO7/wa-api/whatsapp.Login(0x19223580, 0x0, 0x97f0f90, 0x24, 0x807903e, 0x87ef7e8, 0x1)
        /home/beshoo/go-wapi/wa/whatsapp/main.go:182 +0x7d fp=0x9c13fac sp=0x9c13dcc pc=0x86064cd
bitbucket.org/rockyOO7/wa-api/api.ScanQr.func1(0xd177aa00, 0x0, 0x97f0f90, 0x24, 0x19223580, 0x192235c0)
        /home/beshoo/go-wapi/wa/api/profile.go:24 +0x4d fp=0x9c13fd8 sp=0x9c13fac pc=0x861cdad

Now let us see what is going on, on the main.go:164*

func NewConn(proxyURLString *string) (*wa.Conn, error) {
        var err error
        var wac *wa.Conn
        var timeout = time.Duration(*timeoutInt) * time.Second
        log.Infof("TimeOutFlag: %v , TimeOut: %v", *timeoutInt,timeout)

        if proxyURLString != nil {
                proxyURL, err := url.Parse(*proxyURLString)
                if err != nil {
                        return nil, err
                }
                proxy := http.ProxyURL(proxyURL)
                wac, err = wa.NewConnWithProxy(timeout, proxy)
        } else {
                wac, err = wa.NewConn(timeout) //<========== main.go:164 
        }
        if err != nil {
                wac.Disconnect()
                return nil, err
        }
        return wac, nil
}

and profile.go:24

func ScanQr(params profile.ScanQrParams) middleware.Responder {
        qr := make(chan string)
        errCh := make(chan error)

        go func() {
                sessionID := params.SessionID.String()
                handler, err := wa.Login(qr, params.ProxyURL, sessionID) // <<========= profile.go:24
                if err != nil {
                        errCh <- err
                }
                wa.Connections[sessionID] = handler
        }()

        select {
        case err := <-errCh:
                errText := err.Error()
                return profile.NewScanQrDefault(500).WithPayload(&models.Error{
                        Code:    500,
                        Message: &errText,
                })
        case qrText := <-qr:
                return profile.NewScanQrOK().WithPayload(&models.QRCode{
                        Base64: qrText,
                })

        }

}

and the Login function which triggered by the QR scaner profile.go:24


func Login(qr chan string, proxyURL *strfmt.URI, sessionID string) (*WaHandler, error) {

        var proxyURLString *string
        if proxyURL != nil {
                temp := proxyURL.String()
                proxyURLString = &temp
        }

        var wac, err = NewConn(proxyURLString) // <=========== main.go:182 
        if err != nil {
                return nil, err
        }
        .....................
}

Well, how can we handle suchtype of memory problem?

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 17 (7 by maintainers)

Most upvoted comments

No, i am saying the WA Version with wac.SetClientVersion(2, 2017, 6)

Ok, we should test it a little bit more before opening a PR, like Send messages, receiving too. But glad too know it might fix the memory issue!