dgrr / http2

HTTP/2 implementation for fasthttp
Apache License 2.0
208 stars 35 forks source link

fasthttp http2 Whether connection-level health probes are supported #66

Open zxpdmw opened 9 months ago

zxpdmw commented 9 months ago

image What this does is simulate a network/http2 connection-level health probe

dgrr commented 9 months ago

Hello, as far as I remember the client does ping the server using the PingInterval, but it doesn't close the connection if a number of pings failed. I'd accept a PR for that. https://github.com/dgrr/http2/blob/master/conn.go#L459

zxpdmw commented 9 months ago

Why only fasthttp.hostclient support http2

zxpdmw commented 9 months ago

If the client fails to ping the server for many times, it hopes to close the connection in time, so that the request fails quickly and enters the retry logic

zxpdmw commented 9 months ago
func (c *Conn) writeLoop() {
    var lastErr error

    defer func() { _ = c.Close() }()

    defer func() {
        if err := recover(); err != nil {
            if lastErr == nil {
                switch errn := err.(type) {
                case error:
                    lastErr = errn
                case string:
                    lastErr = errors.New(errn)
                }
            }
        }

        if lastErr == nil {
            lastErr = io.ErrUnexpectedEOF
        }

        c.reqQueued.Range(func(_, v interface{}) bool {
            r := v.(*Ctx)
            r.resolve(lastErr)

            return true
        })
    }()

    if c.pingInterval <= 0 {
        c.pingInterval = DefaultPingInterval
    }

    ticker := time.NewTicker(c.pingInterval)
    defer ticker.Stop()

loop:
    for {
        select {
        case ctx, ok := <-c.in: // sending requests
            if !ok {
                break loop
            }

            err := c.writeRequest(ctx)
            if err != nil {
                ctx.resolve(err)

                if errors.Is(err, ErrNotAvailableStreams) {
                    continue
                }

                lastErr = WriteError{err}

                break loop
            }
        case fr, ok := <-c.out: // generic output
            if !ok {
                break loop
            }

            err := c.writeFrame(fr)
            if err != nil {
                lastErr = WriteError{err}
                break loop
            }

            ReleaseFrameHeader(fr)
        case <-ticker.C: // ping
            if err := c.writePing(); err != nil {
                lastErr = WriteError{err}
                break loop
            }
        }

        if !c.disableAcks && c.unacks >= 3 {
            lastErr = ErrTimeout
            break loop
        }
    }
}

defer c.Close Won't the connection be closed

        if !c.disableAcks && c.unacks >= 3 {
            lastErr = ErrTimeout
            break loop
        }

If ack is enabled and the number of acks is greater than three times, it will jump out of the loop, and eventually it will execute until the defer closes the connection

zxpdmw commented 9 months ago

writeLoop AND readLoop The method is all the same logic

zxpdmw commented 9 months ago

Fasthttp HTTP2 Client looks like the code implementation has implemented connection-level health detection

dgrr commented 9 months ago

Yes, it seems like it. Is your question resolved?

zxpdmw commented 9 months ago

I use this library, it seems that I am still using http1, and the example in the code log does not run

dgrr commented 9 months ago

Does the server support HTTP/2? Are you connecting through TLS?

zxpdmw commented 8 months ago

Without using TLS, the example in my repository won't work in http2

dgrr commented 8 months ago

Yes, the library only supports TLS.

zxpdmw commented 8 months ago

Do the client and server support TLS at the same time?