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:
parent
cacbfad765
commit
9c2a36be17
166
app.go
166
app.go
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user