mirror of
https://github.com/kataras/iris.git
synced 2026-01-03 18:27:07 +00:00
Add notes for the new lead maintainer of the open-source iris project and align with @get-ion/ion by @hiveminded
Former-commit-id: da4f38eb9034daa49446df3ee529423b98f9b331
This commit is contained in:
@@ -1,7 +1,3 @@
|
||||
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
@@ -9,14 +5,11 @@ import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
"github.com/kataras/iris/core/errors"
|
||||
"github.com/kataras/iris/core/nettools"
|
||||
"github.com/kataras/iris/core/netutil"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
@@ -25,16 +18,17 @@ import (
|
||||
//
|
||||
// Interfaces are separated to return relative functionality to them.
|
||||
type Supervisor struct {
|
||||
Scheduler
|
||||
server *http.Server
|
||||
Server *http.Server
|
||||
closedManually int32 // future use, accessed atomically (non-zero means we've called the Shutdown)
|
||||
|
||||
shouldWait int32 // non-zero means that the host should wait for unblocking
|
||||
unblockChan chan struct{}
|
||||
shutdownChan chan struct{}
|
||||
errChan chan error
|
||||
manuallyTLS bool // we need that in order to determinate what to output on the console before the server begin.
|
||||
shouldWait int32 // non-zero means that the host should wait for unblocking
|
||||
unblockChan chan struct{}
|
||||
|
||||
mu sync.Mutex
|
||||
|
||||
onServe []func(TaskHost)
|
||||
onErr []func(error)
|
||||
onShutdown []func()
|
||||
}
|
||||
|
||||
// New returns a new host supervisor
|
||||
@@ -46,10 +40,8 @@ type Supervisor struct {
|
||||
// to return and exit and restore the flow too.
|
||||
func New(srv *http.Server) *Supervisor {
|
||||
return &Supervisor{
|
||||
server: srv,
|
||||
unblockChan: make(chan struct{}, 1),
|
||||
shutdownChan: make(chan struct{}),
|
||||
errChan: make(chan error),
|
||||
Server: srv,
|
||||
unblockChan: make(chan struct{}, 1),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,78 +75,73 @@ func (su *Supervisor) isWaiting() bool {
|
||||
return atomic.LoadInt32(&su.shouldWait) != 0
|
||||
}
|
||||
|
||||
// Done is being received when in server Shutdown.
|
||||
// This can be used to gracefully shutdown connections that have
|
||||
// undergone NPN/ALPN protocol upgrade or that have been hijacked.
|
||||
// This function should start protocol-specific graceful shutdown,
|
||||
// but should not wait for shutdown to complete.
|
||||
func (su *Supervisor) Done() <-chan struct{} {
|
||||
return su.shutdownChan
|
||||
func (su *Supervisor) newListener() (net.Listener, error) {
|
||||
// this will not work on "unix" as network
|
||||
// because UNIX doesn't supports the kind of
|
||||
// restarts we may want for the server.
|
||||
//
|
||||
// User still be able to call .Serve instead.
|
||||
l, err := netutil.TCPKeepAlive(su.Server.Addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// here we can check for sure, without the need of the supervisor's `manuallyTLS` field.
|
||||
if netutil.IsTLS(su.Server) {
|
||||
// means tls
|
||||
tlsl := tls.NewListener(l, su.Server.TLSConfig)
|
||||
return tlsl, nil
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// Err refences to the return value of Server's .Serve, not the server's specific error logger.
|
||||
func (su *Supervisor) Err() <-chan error {
|
||||
return su.errChan
|
||||
}
|
||||
|
||||
func (su *Supervisor) notifyShutdown() {
|
||||
go func() {
|
||||
su.shutdownChan <- struct{}{}
|
||||
}()
|
||||
|
||||
su.Scheduler.notifyShutdown()
|
||||
// RegisterOnError registers a function to call when errors occured by the underline http server.
|
||||
func (su *Supervisor) RegisterOnError(cb func(error)) {
|
||||
su.mu.Lock()
|
||||
su.onErr = append(su.onErr, cb)
|
||||
su.mu.Unlock()
|
||||
}
|
||||
|
||||
func (su *Supervisor) notifyErr(err error) {
|
||||
// if err == http.ErrServerClosed {
|
||||
// su.notifyShutdown()
|
||||
// return
|
||||
// }
|
||||
|
||||
go func() {
|
||||
su.errChan <- err
|
||||
}()
|
||||
|
||||
su.Scheduler.notifyErr(err)
|
||||
su.mu.Lock()
|
||||
for _, f := range su.onErr {
|
||||
go f(err)
|
||||
}
|
||||
su.mu.Unlock()
|
||||
}
|
||||
|
||||
// RegisterOnServe registers a function to call on
|
||||
// Serve/ListenAndServe/ListenAndServeTLS/ListenAndServeAutoTLS.
|
||||
func (su *Supervisor) RegisterOnServe(cb func(TaskHost)) {
|
||||
su.mu.Lock()
|
||||
su.onServe = append(su.onServe, cb)
|
||||
su.mu.Unlock()
|
||||
}
|
||||
|
||||
func (su *Supervisor) notifyServe(host TaskHost) {
|
||||
su.mu.Lock()
|
||||
for _, f := range su.onServe {
|
||||
go f(host)
|
||||
}
|
||||
su.mu.Unlock()
|
||||
}
|
||||
|
||||
/// TODO:
|
||||
// Remove all channels, do it with events
|
||||
// or with channels but with a different channel on each task proc
|
||||
// I don't know channels are not so safe, when go func and race risk..
|
||||
// so better with callbacks....
|
||||
func (su *Supervisor) supervise(blockFunc func() error) error {
|
||||
// println("Running Serve from Supervisor")
|
||||
|
||||
// su.server: in order to Serve and Shutdown the underline server and no re-run the supervisors when .Shutdown -> .Serve.
|
||||
// su.GetBlocker: set the Block() and Unblock(), which are checked after a shutdown or error.
|
||||
// su.GetNotifier: only one supervisor is allowed to be notified about Close/Shutdown and Err.
|
||||
// su.log: set this builder's logger in order to supervisor to be able to share a common logger.
|
||||
host := createTaskHost(su)
|
||||
// run the list of supervisors in different go-tasks by-design.
|
||||
su.Scheduler.runOnServe(host)
|
||||
|
||||
if len(su.Scheduler.onInterruptTasks) > 0 {
|
||||
// this can't be moved to the task interrupt's `Run` function
|
||||
// because it will not catch more than one ctrl/cmd+c, so
|
||||
// we do it here. These tasks are canceled already too.
|
||||
go func() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch,
|
||||
// kill -SIGINT XXXX or Ctrl+c
|
||||
os.Interrupt,
|
||||
syscall.SIGINT, // register that too, it should be ok
|
||||
// os.Kill is equivalent with the syscall.SIGKILL
|
||||
os.Kill,
|
||||
syscall.SIGKILL, // register that too, it should be ok
|
||||
// kill -SIGTERM XXXX
|
||||
syscall.SIGTERM,
|
||||
)
|
||||
select {
|
||||
case <-ch:
|
||||
su.Scheduler.runOnInterrupt(host)
|
||||
}
|
||||
}()
|
||||
}
|
||||
su.notifyServe(host)
|
||||
|
||||
tryStartInterruptNotifier()
|
||||
|
||||
err := blockFunc()
|
||||
su.notifyErr(err)
|
||||
@@ -172,26 +159,6 @@ func (su *Supervisor) supervise(blockFunc func() error) error {
|
||||
return err // start the server
|
||||
}
|
||||
|
||||
func (su *Supervisor) newListener() (net.Listener, error) {
|
||||
// this will not work on "unix" as network
|
||||
// because UNIX doesn't supports the kind of
|
||||
// restarts we may want for the server.
|
||||
//
|
||||
// User still be able to call .Serve instead.
|
||||
l, err := nettools.TCPKeepAlive(su.server.Addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if nettools.IsTLS(su.server) {
|
||||
// means tls
|
||||
tlsl := tls.NewListener(l, su.server.TLSConfig)
|
||||
return tlsl, nil
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// Serve accepts incoming connections on the Listener l, creating a
|
||||
// new service goroutine for each. The service goroutines read requests and
|
||||
// then call su.server.Handler to reply to them.
|
||||
@@ -204,7 +171,8 @@ func (su *Supervisor) newListener() (net.Listener, error) {
|
||||
// Serve always returns a non-nil error. After Shutdown or Close, the
|
||||
// returned error is http.ErrServerClosed.
|
||||
func (su *Supervisor) Serve(l net.Listener) error {
|
||||
return su.supervise(func() error { return su.server.Serve(l) })
|
||||
|
||||
return su.supervise(func() error { return su.Server.Serve(l) })
|
||||
}
|
||||
|
||||
// ListenAndServe listens on the TCP network address addr
|
||||
@@ -240,8 +208,8 @@ func (su *Supervisor) ListenAndServeTLS(certFile string, keyFile string) error {
|
||||
}
|
||||
|
||||
setupHTTP2(cfg)
|
||||
su.server.TLSConfig = cfg
|
||||
|
||||
su.Server.TLSConfig = cfg
|
||||
su.manuallyTLS = true
|
||||
return su.ListenAndServe()
|
||||
}
|
||||
|
||||
@@ -256,10 +224,33 @@ func (su *Supervisor) ListenAndServeAutoTLS() error {
|
||||
cfg := new(tls.Config)
|
||||
cfg.GetCertificate = autoTLSManager.GetCertificate
|
||||
setupHTTP2(cfg)
|
||||
su.server.TLSConfig = cfg
|
||||
su.Server.TLSConfig = cfg
|
||||
su.manuallyTLS = true
|
||||
return su.ListenAndServe()
|
||||
}
|
||||
|
||||
// RegisterOnShutdown registers a function to call on Shutdown.
|
||||
// This can be used to gracefully shutdown connections that have
|
||||
// undergone NPN/ALPN protocol upgrade or that have been hijacked.
|
||||
// This function should start protocol-specific graceful shutdown,
|
||||
// but should not wait for shutdown to complete.
|
||||
func (su *Supervisor) RegisterOnShutdown(cb func()) {
|
||||
// when go1.9: replace the following lines with su.Server.RegisterOnShutdown(f)
|
||||
su.mu.Lock()
|
||||
su.onShutdown = append(su.onShutdown, cb)
|
||||
su.mu.Unlock()
|
||||
}
|
||||
|
||||
func (su *Supervisor) notifyShutdown() {
|
||||
// when go1.9: remove the lines below
|
||||
su.mu.Lock()
|
||||
for _, f := range su.onShutdown {
|
||||
go f()
|
||||
}
|
||||
su.mu.Unlock()
|
||||
// end
|
||||
}
|
||||
|
||||
// Shutdown gracefully shuts down the server without interrupting any
|
||||
// active connections. Shutdown works by first closing all open
|
||||
// listeners, then closing all idle connections, and then waiting
|
||||
@@ -272,9 +263,7 @@ func (su *Supervisor) ListenAndServeAutoTLS() error {
|
||||
// separately notify such long-lived connections of shutdown and wait
|
||||
// for them to close, if desired.
|
||||
func (su *Supervisor) Shutdown(ctx context.Context) error {
|
||||
// println("Running Shutdown from Supervisor")
|
||||
|
||||
atomic.AddInt32(&su.closedManually, 1) // future-use
|
||||
su.notifyShutdown()
|
||||
return su.server.Shutdown(ctx)
|
||||
return su.Server.Shutdown(ctx)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user