1
0
mirror of https://github.com/gofiber/fiber.git synced 2025-02-14 13:46:23 +00:00

Add Prefork support for Windows

This commit is contained in:
Fenny 2020-06-22 15:12:50 +02:00
parent cacbfad765
commit 9c2a36be17

166
app.go
View File

@ -13,8 +13,6 @@ import (
"net"
"net/http"
"net/http/httputil"
"os"
"os/exec"
"reflect"
"runtime"
"sort"
@ -25,6 +23,7 @@ import (
utils "github.com/gofiber/utils"
fasthttp "github.com/valyala/fasthttp"
fprefork "github.com/valyala/fasthttp/prefork"
)
// Version of current package
@ -371,9 +370,46 @@ func (app *App) Group(prefix string, handlers ...Handler) *Group {
return &Group{prefix: prefix, app: app}
}
// Error makes it compatible with `error` interface.
func (e *Error) Error() string {
return e.Message
}
// NewError creates a new HTTPError instance.
func NewError(code int, message ...string) *Error {
e := &Error{code, utils.StatusMessage(code)}
if len(message) > 0 {
e.Message = message[0]
}
return e
}
// Routes returns all registered routes
//
// for _, r := range app.Routes() {
// fmt.Printf("%s\t%s\n", r.Method, r.Path)
// }
func (app *App) Routes() []*Route {
routes := make([]*Route, 0)
for m := range app.stack {
for r := range app.stack[m] {
// Ignore HEAD routes handling GET routes
if m == 1 && app.stack[m][r].Method == MethodGet {
continue
}
routes = append(routes, app.stack[m][r])
}
}
// Sort routes by stack position
sort.Slice(routes, func(i, k int) bool {
return routes[i].pos < routes[k].pos
})
return routes
}
// Serve can be used to pass a custom listener
// This method does not support the Prefork feature
// Preforkin is not available using app.Serve(ln net.Listener)
// Prefork is not supported using app.Serve(ln net.Listener)
// You can pass an optional *tls.Config to enable TLS.
func (app *App) Serve(ln net.Listener, tlsconfig ...*tls.Config) error {
// Update fiber server settings
@ -384,7 +420,7 @@ func (app *App) Serve(ln net.Listener, tlsconfig ...*tls.Config) error {
}
// Print startup message
if !app.Settings.DisableStartupMessage {
startupMessage(ln)
startupMessage(ln.Addr().String())
}
return app.server.Serve(ln)
@ -393,6 +429,7 @@ func (app *App) Serve(ln net.Listener, tlsconfig ...*tls.Config) error {
// Listen serves HTTP requests from the given addr or port.
// You can pass an optional *tls.Config to enable TLS.
func (app *App) Listen(address interface{}, tlsconfig ...*tls.Config) error {
// Convert address to string
addr, ok := address.(string)
if !ok {
port, ok := address.(int)
@ -406,28 +443,37 @@ func (app *App) Listen(address interface{}, tlsconfig ...*tls.Config) error {
}
// Update fiber server settings
app.init()
// Setup listener
var ln net.Listener
var err error
// Prefork enabled, not available on windows
if app.Settings.Prefork && runtime.NumCPU() > 1 && runtime.GOOS != "windows" {
if ln, err = app.prefork(addr); err != nil {
return err
}
} else {
if ln, err = net.Listen("tcp4", addr); err != nil {
return err
// Start prefork
if app.Settings.Prefork && runtime.NumCPU() > 1 {
pf := fprefork.New(app.server) // fasthttp/prefork
pf.Reuseport = true
pf.Network = "tcp4"
pf.ServeFunc = func(lnn net.Listener) error {
if len(tlsconfig) > 0 {
lnn = tls.NewListener(lnn, tlsconfig[0])
}
// Print startup message
if !app.Settings.DisableStartupMessage && !utils.GetArgument(childFlag) {
startupMessage(lnn.Addr().String())
}
return app.server.Serve(lnn)
}
return pf.ListenAndServe(addr)
}
// TLS config
// Setup listener
ln, err := net.Listen("tcp4", addr)
if err != nil {
return err
}
// Add TLS config if provided
if len(tlsconfig) > 0 {
ln = tls.NewListener(ln, tlsconfig[0])
}
// Print startup message
if !app.Settings.DisableStartupMessage && !utils.GetArgument(childFlag) {
startupMessage(ln)
startupMessage(ln.Addr().String())
}
// Start listening
return app.server.Serve(ln)
}
@ -503,86 +549,6 @@ func (app *App) Test(request *http.Request, msTimeout ...int) (*http.Response, e
return resp, nil
}
// Error makes it compatible with `error` interface.
func (e *Error) Error() string {
return e.Message
}
// NewError creates a new HTTPError instance.
func NewError(code int, message ...string) *Error {
e := &Error{code, utils.StatusMessage(code)}
if len(message) > 0 {
e.Message = message[0]
}
return e
}
// Routes returns all registered routes
//
// for _, r := range app.Routes() {
// fmt.Printf("%s\t%s\n", r.Method, r.Path)
// }
func (app *App) Routes() []*Route {
routes := make([]*Route, 0)
for m := range app.stack {
for r := range app.stack[m] {
// Ignore HEAD routes handling GET routes
if m == 1 && app.stack[m][r].Method == MethodGet {
continue
}
routes = append(routes, app.stack[m][r])
}
}
// Sort routes by stack position
sort.Slice(routes, func(i, k int) bool {
return routes[i].pos < routes[k].pos
})
return routes
}
// Sharding: https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/
func (app *App) prefork(address string) (ln net.Listener, err error) {
// Master proc
if !utils.GetArgument(childFlag) {
addr, err := net.ResolveTCPAddr("tcp", address)
if err != nil {
return ln, err
}
tcplistener, err := net.ListenTCP("tcp", addr)
if err != nil {
return ln, err
}
fl, err := tcplistener.File()
if err != nil {
return ln, err
}
files := []*os.File{fl}
childs := make([]*exec.Cmd, runtime.NumCPU()/2)
// #nosec G204
for i := range childs {
childs[i] = exec.Command(os.Args[0], append(os.Args[1:], preforkFlag, childFlag)...)
childs[i].Stdout = os.Stdout
childs[i].Stderr = os.Stderr
childs[i].ExtraFiles = files
if err := childs[i].Start(); err != nil {
return ln, err
}
}
for k := range childs {
if err := childs[k].Wait(); err != nil {
return ln, err
}
}
os.Exit(0)
} else {
// 1 core per child
runtime.GOMAXPROCS(1)
ln, err = net.FileListener(os.NewFile(3, ""))
}
return ln, err
}
type disableLogger struct{}
func (dl *disableLogger) Printf(format string, args ...interface{}) {
@ -644,7 +610,7 @@ func (app *App) init() *App {
return app
}
func startupMessage(ln net.Listener) {
func startupMessage(addr string) {
fmt.Printf(" _______ __\n ____ / ____(_) /_ ___ _____\n_____ / /_ / / __ \\/ _ \\/ ___/\n __ / __/ / / /_/ / __/ /\n /_/ /_/_.___/\\___/_/ v%s\n", Version)
fmt.Printf("Started listening on %s\n", ln.Addr().String())
fmt.Printf("Started listening on %s\n", addr)
}