comment update for package ghttp

This commit is contained in:
John 2020-05-01 03:31:04 +08:00
parent c8d253eb56
commit 5f8e6ad9ed
11 changed files with 68 additions and 58 deletions

View File

@ -16,6 +16,9 @@ import (
"github.com/gogf/gf/os/gview" "github.com/gogf/gf/os/gview"
) )
// utilAdmin is the controller for administration.
type utilAdmin struct{}
// Index shows the administration page. // Index shows the administration page.
func (p *utilAdmin) Index(r *Request) { func (p *utilAdmin) Index(r *Request) {
data := map[string]interface{}{ data := map[string]interface{}{

View File

@ -3,7 +3,6 @@
// This Source Code Form is subject to the terms of the MIT License. // This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, // If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf. // You can obtain one at https://github.com/gogf/gf.
// pprof封装.
package ghttp package ghttp
@ -27,7 +26,8 @@ import (
) )
const ( const (
gADMIN_ACTION_INTERVAL_LIMIT = 2000 // (毫秒)服务开启后允许执行管理操作的间隔限制 // Allow executing management command after server starts after this interval in milliseconds.
gADMIN_ACTION_INTERVAL_LIMIT = 2000
gADMIN_ACTION_NONE = 0 gADMIN_ACTION_NONE = 0
gADMIN_ACTION_RESTARTING = 1 gADMIN_ACTION_RESTARTING = 1
gADMIN_ACTION_SHUTINGDOWN = 2 gADMIN_ACTION_SHUTINGDOWN = 2
@ -36,48 +36,44 @@ const (
gADMIN_GPROC_COMM_GROUP = "GF_GPROC_HTTP_SERVER" gADMIN_GPROC_COMM_GROUP = "GF_GPROC_HTTP_SERVER"
) )
// 用于服务管理的对象 // serverActionLocker is the locker for server administration operations.
type utilAdmin struct{}
// (进程级别)用于Web Server管理操作的互斥锁保证管理操作的原子性
var serverActionLocker sync.Mutex var serverActionLocker sync.Mutex
// (进程级别)用于记录上一次操作的时间(毫秒) // serverActionLastTime is timestamp in milliseconds of last administration operation.
var serverActionLastTime = gtype.NewInt64(gtime.TimestampMilli()) var serverActionLastTime = gtype.NewInt64(gtime.TimestampMilli())
// 当前服务进程所处的互斥管理操作状态 // serverProcessStatus is the server status for operation of current process.
var serverProcessStatus = gtype.NewInt() var serverProcessStatus = gtype.NewInt()
// 重启Web Server参数支持自定义重启的可执行文件路径不传递时默认和原有可执行文件路径一致。 // RestartAllServer restarts all the servers of the process.
// 针对*niux系统: 平滑重启 // The optional parameter <newExeFilePath> specifies the new binary file for creating process.
// 针对windows : 完整重启
func RestartAllServer(newExeFilePath ...string) error { func RestartAllServer(newExeFilePath ...string) error {
serverActionLocker.Lock() serverActionLocker.Lock()
defer serverActionLocker.Unlock() defer serverActionLocker.Unlock()
if err := checkProcessStatus(); err != nil { if err := checkProcessStatus(); err != nil {
return err return err
} }
if err := checkActionFrequence(); err != nil { if err := checkActionFrequency(); err != nil {
return err return err
} }
return restartWebServers("", newExeFilePath...) return restartWebServers("", newExeFilePath...)
} }
// 关闭所有的WebServer // ShutdownAllServer shuts down all servers of current process.
func ShutdownAllServer() error { func ShutdownAllServer() error {
serverActionLocker.Lock() serverActionLocker.Lock()
defer serverActionLocker.Unlock() defer serverActionLocker.Unlock()
if err := checkProcessStatus(); err != nil { if err := checkProcessStatus(); err != nil {
return err return err
} }
if err := checkActionFrequence(); err != nil { if err := checkActionFrequency(); err != nil {
return err return err
} }
shutdownWebServers() shutdownWebServers()
return nil return nil
} }
// 检查当前服务进程的状态 // checkProcessStatus checks the server status of current process.
func checkProcessStatus() error { func checkProcessStatus() error {
status := serverProcessStatus.Val() status := serverProcessStatus.Val()
if status > 0 { if status > 0 {
@ -91,8 +87,9 @@ func checkProcessStatus() error {
return nil return nil
} }
// 检测当前操作的频繁度 // checkActionFrequency checks the operation frequency.
func checkActionFrequence() error { // It returns error if it is too frequency.
func checkActionFrequency() error {
interval := gtime.TimestampMilli() - serverActionLastTime.Val() interval := gtime.TimestampMilli() - serverActionLastTime.Val()
if interval < gADMIN_ACTION_INTERVAL_LIMIT { if interval < gADMIN_ACTION_INTERVAL_LIMIT {
return errors.New(fmt.Sprintf("too frequent action, please retry in %d ms", gADMIN_ACTION_INTERVAL_LIMIT-interval)) return errors.New(fmt.Sprintf("too frequent action, please retry in %d ms", gADMIN_ACTION_INTERVAL_LIMIT-interval))
@ -101,16 +98,16 @@ func checkActionFrequence() error {
return nil return nil
} }
// 平滑重启:创建一个子进程,通过环境变量传参 // forkReloadProcess creates a new child process and copies the fd to child process.
func forkReloadProcess(newExeFilePath ...string) error { func forkReloadProcess(newExeFilePath ...string) error {
path := os.Args[0] path := os.Args[0]
if len(newExeFilePath) > 0 { if len(newExeFilePath) > 0 {
path = newExeFilePath[0] path = newExeFilePath[0]
} }
p := gproc.NewProcess(path, os.Args, os.Environ()) var (
// 创建新的服务进程,子进程自动从父进程复制文件描述来监听同样的端口 p = gproc.NewProcess(path, os.Args, os.Environ())
sfm := getServerFdMap() sfm = getServerFdMap()
// 将sfm中的fd按照子进程创建时的文件描述符顺序进行整理以便子进程获取到正确的fd )
for name, m := range sfm { for name, m := range sfm {
for fdk, fdv := range m { for fdk, fdv := range m {
if len(fdv) > 0 { if len(fdv) > 0 {
@ -138,13 +135,12 @@ func forkReloadProcess(newExeFilePath ...string) error {
return nil return nil
} }
// 完整重启:创建一个新的子进程 // forkRestartProcess creates a new server process.
func forkRestartProcess(newExeFilePath ...string) error { func forkRestartProcess(newExeFilePath ...string) error {
path := os.Args[0] path := os.Args[0]
if len(newExeFilePath) > 0 { if len(newExeFilePath) > 0 {
path = newExeFilePath[0] path = newExeFilePath[0]
} }
// 去掉平滑重启的环境变量参数
os.Unsetenv(gADMIN_ACTION_RELOAD_ENVKEY) os.Unsetenv(gADMIN_ACTION_RELOAD_ENVKEY)
env := os.Environ() env := os.Environ()
env = append(env, gADMIN_ACTION_RESTART_ENVKEY+"=1") env = append(env, gADMIN_ACTION_RESTART_ENVKEY+"=1")
@ -156,7 +152,7 @@ func forkRestartProcess(newExeFilePath ...string) error {
return nil return nil
} }
// 获取所有Web Server的文件描述符map // getServerFdMap returns all the servers name to file descriptor mapping as map.
func getServerFdMap() map[string]listenerFdMap { func getServerFdMap() map[string]listenerFdMap {
sfm := make(map[string]listenerFdMap) sfm := make(map[string]listenerFdMap)
serverMapping.RLockFunc(func(m map[string]interface{}) { serverMapping.RLockFunc(func(m map[string]interface{}) {
@ -167,7 +163,7 @@ func getServerFdMap() map[string]listenerFdMap {
return sfm return sfm
} }
// 二进制转换为FdMap // bufferToServerFdMap converts binary content to fd map.
func bufferToServerFdMap(buffer []byte) map[string]listenerFdMap { func bufferToServerFdMap(buffer []byte) map[string]listenerFdMap {
sfm := make(map[string]listenerFdMap) sfm := make(map[string]listenerFdMap)
if len(buffer) > 0 { if len(buffer) > 0 {
@ -183,16 +179,17 @@ func bufferToServerFdMap(buffer []byte) map[string]listenerFdMap {
return sfm return sfm
} }
// Web Server重启 // restartWebServers restarts all servers.
func restartWebServers(signal string, newExeFilePath ...string) error { func restartWebServers(signal string, newExeFilePath ...string) error {
serverProcessStatus.Set(gADMIN_ACTION_RESTARTING) serverProcessStatus.Set(gADMIN_ACTION_RESTARTING)
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
if len(signal) > 0 { if len(signal) > 0 {
// 在终端信号下,立即执行重启操作 // Controlled by signal.
forceCloseWebServers() forceCloseWebServers()
forkRestartProcess(newExeFilePath...) forkRestartProcess(newExeFilePath...)
} else { } else {
// 非终端信号下异步1秒后再执行重启目的是让接口能够正确返回结果否则接口会报错(因为web server关闭了) // Controlled by web page.
// It should ensure the response wrote to client and then close all servers gracefully.
gtimer.SetTimeout(time.Second, func() { gtimer.SetTimeout(time.Second, func() {
forceCloseWebServers() forceCloseWebServers()
forkRestartProcess(newExeFilePath...) forkRestartProcess(newExeFilePath...)
@ -215,18 +212,15 @@ func restartWebServers(signal string, newExeFilePath ...string) error {
return nil return nil
} }
// 关闭所有Web Server // shutdownWebServers shuts down all servers.
func shutdownWebServers(signal ...string) { func shutdownWebServers(signal ...string) {
serverProcessStatus.Set(gADMIN_ACTION_SHUTINGDOWN) serverProcessStatus.Set(gADMIN_ACTION_SHUTINGDOWN)
if len(signal) > 0 { if len(signal) > 0 {
glog.Printf("%d: server shutting down by signal: %s", gproc.Pid(), signal[0]) glog.Printf("%d: server shutting down by signal: %s", gproc.Pid(), signal[0])
// 在终端信号下,立即执行关闭操作
forceCloseWebServers() forceCloseWebServers()
allDoneChan <- struct{}{} allDoneChan <- struct{}{}
} else { } else {
glog.Printf("%d: server shutting down by api", gproc.Pid()) glog.Printf("%d: server shutting down by api", gproc.Pid())
// 非终端信号下异步1秒后再执行关闭
// 目的是让接口能够正确返回结果,否则接口会报错(因为web server关闭了)
gtimer.SetTimeout(time.Second, func() { gtimer.SetTimeout(time.Second, func() {
forceCloseWebServers() forceCloseWebServers()
allDoneChan <- struct{}{} allDoneChan <- struct{}{}
@ -234,8 +228,7 @@ func shutdownWebServers(signal ...string) {
} }
} }
// 关优雅闭进程所有端口的Web Server服务 // gracefulShutdownWebServers gracefully shuts down all servers.
// 注意只是关闭Web Server服务并不是退出进程
func gracefulShutdownWebServers() { func gracefulShutdownWebServers() {
serverMapping.RLockFunc(func(m map[string]interface{}) { serverMapping.RLockFunc(func(m map[string]interface{}) {
for _, v := range m { for _, v := range m {
@ -246,8 +239,7 @@ func gracefulShutdownWebServers() {
}) })
} }
// 强制关闭进程所有端口的Web Server服务 // forceCloseWebServers forced shuts down all servers.
// 注意只是关闭Web Server服务并不是退出进程
func forceCloseWebServers() { func forceCloseWebServers() {
serverMapping.RLockFunc(func(m map[string]interface{}) { serverMapping.RLockFunc(func(m map[string]interface{}) {
for _, v := range m { for _, v := range m {
@ -258,7 +250,7 @@ func forceCloseWebServers() {
}) })
} }
// 异步监听进程间消息 // handleProcessMessage listens the signal from system.
func handleProcessMessage() { func handleProcessMessage() {
for { for {
if msg := gproc.Receive(gADMIN_GPROC_COMM_GROUP); msg != nil { if msg := gproc.Receive(gADMIN_GPROC_COMM_GROUP); msg != nil {

View File

@ -15,10 +15,10 @@ import (
"syscall" "syscall"
) )
// 进程信号量监听消息队列 // procSignalChan is the channel for listening the signal.
var procSignalChan = make(chan os.Signal) var procSignalChan = make(chan os.Signal)
// 信号量处理 // handleProcessSignal handles all signal from system.
func handleProcessSignal() { func handleProcessSignal() {
var sig os.Signal var sig os.Signal
signal.Notify( signal.Notify(
@ -35,12 +35,12 @@ func handleProcessSignal() {
sig = <-procSignalChan sig = <-procSignalChan
intlog.Printf(`signal received: %s`, sig.String()) intlog.Printf(`signal received: %s`, sig.String())
switch sig { switch sig {
// 进程终止,停止所有子进程运行 // Stop the servers.
case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGABRT: case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGABRT:
shutdownWebServers(sig.String()) shutdownWebServers(sig.String())
return return
// 用户信号,重启服务 // Restart the servers.
case syscall.SIGUSR1: case syscall.SIGUSR1:
restartWebServers(sig.String()) restartWebServers(sig.String())
return return

View File

@ -8,7 +8,7 @@
package ghttp package ghttp
// windows不处理信号量 // handleProcessSignal does nothing on windows platform.
func handleProcessSignal() { func handleProcessSignal() {
} }

View File

@ -10,26 +10,32 @@ import (
"time" "time"
) )
// SetCookieMaxAge sets the CookieMaxAge for server.
func (s *Server) SetCookieMaxAge(ttl time.Duration) { func (s *Server) SetCookieMaxAge(ttl time.Duration) {
s.config.CookieMaxAge = ttl s.config.CookieMaxAge = ttl
} }
// SetCookiePath sets the CookiePath for server.
func (s *Server) SetCookiePath(path string) { func (s *Server) SetCookiePath(path string) {
s.config.CookiePath = path s.config.CookiePath = path
} }
// SetCookieDomain sets the CookieDomain for server.
func (s *Server) SetCookieDomain(domain string) { func (s *Server) SetCookieDomain(domain string) {
s.config.CookieDomain = domain s.config.CookieDomain = domain
} }
// GetCookieMaxAge returns the CookieMaxAge of server.
func (s *Server) GetCookieMaxAge() time.Duration { func (s *Server) GetCookieMaxAge() time.Duration {
return s.config.CookieMaxAge return s.config.CookieMaxAge
} }
// GetCookiePath returns the CookiePath of server.
func (s *Server) GetCookiePath() string { func (s *Server) GetCookiePath() string {
return s.config.CookiePath return s.config.CookiePath
} }
// GetCookieDomain returns CookieDomain of server.
func (s *Server) GetCookieDomain() string { func (s *Server) GetCookieDomain() string {
return s.config.CookieDomain return s.config.CookieDomain
} }

View File

@ -8,7 +8,8 @@ package ghttp
import "github.com/gogf/gf/internal/intlog" import "github.com/gogf/gf/internal/intlog"
// 设置日志目录,只有在设置了日志目录的情况下才会输出日志到日志文件中。 // SetLogPath sets the log path for server.
// It logs content to file only if the log path is set.
func (s *Server) SetLogPath(path string) { func (s *Server) SetLogPath(path string) {
if len(path) == 0 { if len(path) == 0 {
return return
@ -19,38 +20,37 @@ func (s *Server) SetLogPath(path string) {
s.config.AccessLogEnabled = true s.config.AccessLogEnabled = true
} }
// 设置日志内容是否输出到终端,默认情况下只有错误日志才会自动输出到终端。 // SetLogStdout sets whether output the logging content to stdout.
// 如果需要输出请求日志到终端默认情况下使用SetAccessLogEnabled方法开启请求日志特性即可。
func (s *Server) SetLogStdout(enabled bool) { func (s *Server) SetLogStdout(enabled bool) {
s.config.LogStdout = enabled s.config.LogStdout = enabled
} }
// 设置是否开启access log日志功能 // SetAccessLogEnabled enables/disables the access log.
func (s *Server) SetAccessLogEnabled(enabled bool) { func (s *Server) SetAccessLogEnabled(enabled bool) {
s.config.AccessLogEnabled = enabled s.config.AccessLogEnabled = enabled
} }
// 设置是否开启error log日志功能 // SetErrorLogEnabled enables/disables the error log.
func (s *Server) SetErrorLogEnabled(enabled bool) { func (s *Server) SetErrorLogEnabled(enabled bool) {
s.config.ErrorLogEnabled = enabled s.config.ErrorLogEnabled = enabled
} }
// 设置是否开启error stack打印功能 // SetErrorStack enables/disables the error stack feature.
func (s *Server) SetErrorStack(enabled bool) { func (s *Server) SetErrorStack(enabled bool) {
s.config.ErrorStack = enabled s.config.ErrorStack = enabled
} }
// 获取日志目录 // GetLogPath returns the log path.
func (s *Server) GetLogPath() string { func (s *Server) GetLogPath() string {
return s.config.LogPath return s.config.LogPath
} }
// access log日志功能是否开启 // IsAccessLogEnabled checks whether the access log enabled.
func (s *Server) IsAccessLogEnabled() bool { func (s *Server) IsAccessLogEnabled() bool {
return s.config.AccessLogEnabled return s.config.AccessLogEnabled
} }
// error log日志功能是否开启 // IsErrorLogEnabled checks whether the error log enabled.
func (s *Server) IsErrorLogEnabled() bool { func (s *Server) IsErrorLogEnabled() bool {
return s.config.ErrorLogEnabled return s.config.ErrorLogEnabled
} }

View File

@ -6,18 +6,23 @@
package ghttp package ghttp
// SetNameToUriType sets the NameToUriType for server.
func (s *Server) SetNameToUriType(t int) { func (s *Server) SetNameToUriType(t int) {
s.config.NameToUriType = t s.config.NameToUriType = t
} }
// SetDumpRouterMap sets the DumpRouterMap for server.
// If DumpRouterMap is enabled, it automatically dumps the route map when server starts.
func (s *Server) SetDumpRouterMap(enabled bool) { func (s *Server) SetDumpRouterMap(enabled bool) {
s.config.DumpRouterMap = enabled s.config.DumpRouterMap = enabled
} }
// SetClientMaxBodySize sets the ClientMaxBodySize for server.
func (s *Server) SetClientMaxBodySize(maxSize int64) { func (s *Server) SetClientMaxBodySize(maxSize int64) {
s.config.ClientMaxBodySize = maxSize s.config.ClientMaxBodySize = maxSize
} }
// SetFormParsingMemory sets the FormParsingMemory for server.
func (s *Server) SetFormParsingMemory(maxMemory int64) { func (s *Server) SetFormParsingMemory(maxMemory int64) {
s.config.FormParsingMemory = maxMemory s.config.FormParsingMemory = maxMemory
} }

View File

@ -6,16 +6,19 @@
package ghttp package ghttp
// SetRewrite sets rewrites for static URI for server.
func (s *Server) SetRewrite(uri string, rewrite string) { func (s *Server) SetRewrite(uri string, rewrite string) {
s.config.Rewrites[uri] = rewrite s.config.Rewrites[uri] = rewrite
} }
// SetRewriteMap sets the rewrite map for server.
func (s *Server) SetRewriteMap(rewrites map[string]string) { func (s *Server) SetRewriteMap(rewrites map[string]string) {
for k, v := range rewrites { for k, v := range rewrites {
s.config.Rewrites[k] = v s.config.Rewrites[k] = v
} }
} }
// SetRouteOverWrite sets the RouteOverWrite for server.
func (s *Server) SetRouteOverWrite(enabled bool) { func (s *Server) SetRouteOverWrite(enabled bool) {
s.config.RouteOverWrite = enabled s.config.RouteOverWrite = enabled
} }

View File

@ -12,22 +12,27 @@ import (
"github.com/gogf/gf/os/gsession" "github.com/gogf/gf/os/gsession"
) )
// SetSessionMaxAge sets the SessionMaxAge for server.
func (s *Server) SetSessionMaxAge(ttl time.Duration) { func (s *Server) SetSessionMaxAge(ttl time.Duration) {
s.config.SessionMaxAge = ttl s.config.SessionMaxAge = ttl
} }
// SetSessionIdName sets the SessionIdName for server.
func (s *Server) SetSessionIdName(name string) { func (s *Server) SetSessionIdName(name string) {
s.config.SessionIdName = name s.config.SessionIdName = name
} }
// SetSessionStorage sets the SessionStorage for server.
func (s *Server) SetSessionStorage(storage gsession.Storage) { func (s *Server) SetSessionStorage(storage gsession.Storage) {
s.config.SessionStorage = storage s.config.SessionStorage = storage
} }
// GetSessionMaxAge returns the SessionMaxAge of server.
func (s *Server) GetSessionMaxAge() time.Duration { func (s *Server) GetSessionMaxAge() time.Duration {
return s.config.SessionMaxAge return s.config.SessionMaxAge
} }
// GetSessionIdName returns the SessionIdName of server.
func (s *Server) GetSessionIdName() string { func (s *Server) GetSessionIdName() string {
return s.config.SessionIdName return s.config.SessionIdName
} }

View File

@ -92,9 +92,8 @@ func (s *Server) AddStaticPath(prefix string, path string) {
path: realPath, path: realPath,
} }
if len(s.config.StaticPaths) > 0 { if len(s.config.StaticPaths) > 0 {
// 先添加item
s.config.StaticPaths = append(s.config.StaticPaths, addItem) s.config.StaticPaths = append(s.config.StaticPaths, addItem)
// 按照prefix从长到短进行排序 // Sort the array by length of prefix from short to long.
array := garray.NewSortedArray(func(v1, v2 interface{}) int { array := garray.NewSortedArray(func(v1, v2 interface{}) int {
s1 := gconv.String(v1) s1 := gconv.String(v1)
s2 := gconv.String(v2) s2 := gconv.String(v2)
@ -107,7 +106,7 @@ func (s *Server) AddStaticPath(prefix string, path string) {
for _, v := range s.config.StaticPaths { for _, v := range s.config.StaticPaths {
array.Add(v.prefix) array.Add(v.prefix)
} }
// 按照重新排序的顺序重新添加item // Add the items to paths by previous sorted slice.
paths := make([]staticPathItem, 0) paths := make([]staticPathItem, 0)
for _, v := range array.Slice() { for _, v := range array.Slice() {
for _, item := range s.config.StaticPaths { for _, item := range s.config.StaticPaths {

View File

@ -3,9 +3,6 @@
// This Source Code Form is subject to the terms of the MIT License. // This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, // If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf. // You can obtain one at https://github.com/gogf/gf.
//
// HTTP Cookie管理对象
// 由于Cookie是和HTTP请求挂钩的因此被包含到 ghttp 包中进行管理。
package ghttp package ghttp