fasthttp icon indicating copy to clipboard operation
fasthttp copied to clipboard

Any protection against fault tolerance for fasthttp?

Open gitmko0 opened this issue 3 years ago • 3 comments

Something along the lines of this: https://cloud.ibm.com/docs/go?topic=go-fault-tolerance

Is there any possibility to incorporate fasthttp into the code above or we can do one for our own use with a newer version of fasthttp? What kind of fault tolerance features can be done with fasthttp other than timeout settings and max connection etc? anyone tested under extreme loads (overcapacity type)?

gitmko0 avatar Nov 08 '20 01:11 gitmko0

hey @gitmko0

here's the first snippet, translated for fasthttp, and a variant without middlewares

func HystrixHandler(h func(*fasthttp.RequestCtx), command string) func(*fasthttp.RequestCtx) {
  return func(ctx *fasthttp.RequestCtx) {
    hystrix.Do(command, func() error {
      h(ctx)
      return nil
    }, func(err error) error {
      // Handle failures
      return err
    })
  }
}

func HystrixHandlerNoMiddlewares(command string) func(*fasthttp.RequestCtx) {
  return func(ctx *fasthttp.RequestCtx) {
    hystrix.Do(command, func() error {
      ctx.SetBodyString("hey there")
      return nil
    }, func(err error) error {
      // Handle failures
      return err
    })
  }
}

other stuff you can do as you normally would, hystrix is just a standalone package that shouldn't really care what http engine you use. note, that first examples with middlewares allows for custom handler types, e.g. you can use it to handle errors that you can return from handlers, if you'd use func(*fasthttp.RequestCtx) error or something like that

kirillDanshin avatar Nov 08 '20 11:11 kirillDanshin

thx. this is a game changer... now we need some hot reloading "golang modules" and we have our own "erlang". what do you guys think? hot reloading golang modules the way forward or something better? definitely not interpreted code... I'm talking about clustering possibilities for this.

I'm thinking using pub/sub and inject modules into golang code and let fasthttp run the updated code. Should this be the way forward?

gitmko0 avatar Nov 08 '20 21:11 gitmko0

@kirillDanshin i've tried running it but not sure why the code, when failed is unresponsive, even after timeout.

  1. do you have a full working example of how to use this?
  2. possible to do a hystrix.Go() version example?

trying to explore how to implement it the "proper way" for reverse proxy, in scenario where by "if too many incoming connections, fail gracefully.", but recover in 1s. with reference here : https://github.com/valyala/fasthttp/issues/64

sample code, any comments?


package main


import (
        "log"
        //      "os"
        "github.com/afex/hystrix-go/hystrix"
        "github.com/valyala/fasthttp"
//      "github.com/fasthttp/router"

)
func init(){
        hystrix.ConfigureCommand("mycommand", hystrix.CommandConfig{
                Timeout:               1000,
                MaxConcurrentRequests: 100,
                ErrorPercentThreshold: 25,
        })

}


var proxyClient = &fasthttp.HostClient{
        Addr: "127.0.0.1:8080",
        // set other options here if required - most notably timeouts.
}


func HystrixHandler(h func(*fasthttp.RequestCtx), command string) func(*fasthttp.RequestCtx) {
        return func(ctx *fasthttp.RequestCtx) {
                hystrix.Do(command, func() error {
                        h(ctx)
                        return nil
                }, func(err error) error {
                        // Handle failures
                        return err
                })
        }
}

func ReverseProxyHandler(ctx *fasthttp.RequestCtx) {
        req := &ctx.Request
        resp := &ctx.Response
        prepareRequest(req)
        if err := proxyClient.Do(req, resp); err != nil {
                ctx.Logger().Printf("error when proxying the request: %s", err)
        }
        postprocessResponse(resp)
}

func prepareRequest(req *fasthttp.Request) {
        // do not proxy "Connection" header.
        req.Header.Del("Connection")
        // strip other unneeded headers.

        // alter other request params before sending them to upstream host
}

func postprocessResponse(resp *fasthttp.Response) {
        // do not proxy "Connection" header
        resp.Header.Del("Connection")

        // strip other unneeded headers

        // alter other response data if needed
}

func main() {


//      r := router.New()

//      r.Use(HystrixHandler("mycommand"))
        //if err := fasthttp.ListenAndServe(":80", r.Handler); err != nil {
        if err := fasthttp.ListenAndServe(":80", HystrixHandler(ReverseProxyHandler,"mycommand")); err != nil {
//      if err := fasthttp.ListenAndServe(":80", HystrixHandler(); err != nil {
                log.Fatalf("error in fasthttp server: %s", err)
        }
}

gitmko0 avatar Nov 09 '20 04:11 gitmko0