other: 新版 server 完善通知、事件
This commit is contained in:
parent
ffc3421b29
commit
49b8efd9b2
|
@ -1,12 +1,14 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/utils/collection/listings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/kercylan98/minotaur/utils/collection/listings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
LaunchedEventHandler func(srv Server, ip string, t time.Time)
|
LaunchedEventHandler func(srv Server, ip string, t time.Time)
|
||||||
|
ShutdownEventHandler func(srv Server)
|
||||||
ConnectionOpenedEventHandler func(srv Server, conn Conn)
|
ConnectionOpenedEventHandler func(srv Server, conn Conn)
|
||||||
ConnectionClosedEventHandler func(srv Server, conn Conn, err error)
|
ConnectionClosedEventHandler func(srv Server, conn Conn, err error)
|
||||||
ConnectionReceivePacketEventHandler func(srv Server, conn Conn, packet Packet)
|
ConnectionReceivePacketEventHandler func(srv Server, conn Conn, packet Packet)
|
||||||
|
@ -16,12 +18,20 @@ type Events interface {
|
||||||
// RegisterLaunchedEvent 注册服务器启动事件,当服务器启动后将会触发该事件
|
// RegisterLaunchedEvent 注册服务器启动事件,当服务器启动后将会触发该事件
|
||||||
// - 该事件将在系统级 Actor 中运行,该事件中阻塞会导致服务器启动延迟
|
// - 该事件将在系统级 Actor 中运行,该事件中阻塞会导致服务器启动延迟
|
||||||
RegisterLaunchedEvent(handler LaunchedEventHandler, priority ...int)
|
RegisterLaunchedEvent(handler LaunchedEventHandler, priority ...int)
|
||||||
|
|
||||||
|
// RegisterShutdownEvent 注册服务器关闭事件,当服务器关闭时将会触发该事件,当该事件处理完毕后服务器将关闭
|
||||||
|
// - 该事件将在系统级 Actor 中运行,该事件中阻塞会导致服务器关闭延迟
|
||||||
|
// - 该事件未执行完毕前,服务器的一切均正常运行
|
||||||
|
RegisterShutdownEvent(handler ShutdownEventHandler, priority ...int)
|
||||||
|
|
||||||
// RegisterConnectionOpenedEvent 注册连接打开事件,当新连接创建完毕时将会触发该事件
|
// RegisterConnectionOpenedEvent 注册连接打开事件,当新连接创建完毕时将会触发该事件
|
||||||
// - 该事件将在系统级 Actor 中运行,不应执行阻塞操作
|
// - 该事件将在系统级 Actor 中运行,不应执行阻塞操作
|
||||||
RegisterConnectionOpenedEvent(handler ConnectionOpenedEventHandler, priority ...int)
|
RegisterConnectionOpenedEvent(handler ConnectionOpenedEventHandler, priority ...int)
|
||||||
|
|
||||||
// RegisterConnectionClosedEvent 注册连接关闭事件,当连接关闭后将会触发该事件
|
// RegisterConnectionClosedEvent 注册连接关闭事件,当连接关闭后将会触发该事件
|
||||||
// - 该事件将在系统级 Actor 中运行,不应执行阻塞操作
|
// - 该事件将在系统级 Actor 中运行,不应执行阻塞操作
|
||||||
RegisterConnectionClosedEvent(handler ConnectionClosedEventHandler, priority ...int)
|
RegisterConnectionClosedEvent(handler ConnectionClosedEventHandler, priority ...int)
|
||||||
|
|
||||||
// RegisterConnectionReceivePacketEvent 注册连接接收数据包事件,当连接接收到数据包后将会触发该事件
|
// RegisterConnectionReceivePacketEvent 注册连接接收数据包事件,当连接接收到数据包后将会触发该事件
|
||||||
// - 该事件将在连接的 Actor 中运行,不应执行阻塞操作
|
// - 该事件将在连接的 Actor 中运行,不应执行阻塞操作
|
||||||
RegisterConnectionReceivePacketEvent(handler ConnectionReceivePacketEventHandler, priority ...int)
|
RegisterConnectionReceivePacketEvent(handler ConnectionReceivePacketEventHandler, priority ...int)
|
||||||
|
@ -31,6 +41,7 @@ type events struct {
|
||||||
*server
|
*server
|
||||||
|
|
||||||
launchedEventHandlers listings.SyncPrioritySlice[LaunchedEventHandler]
|
launchedEventHandlers listings.SyncPrioritySlice[LaunchedEventHandler]
|
||||||
|
shutdownEventHandlers listings.SyncPrioritySlice[ShutdownEventHandler]
|
||||||
connectionOpenedEventHandlers listings.SyncPrioritySlice[ConnectionOpenedEventHandler]
|
connectionOpenedEventHandlers listings.SyncPrioritySlice[ConnectionOpenedEventHandler]
|
||||||
connectionClosedEventHandlers listings.SyncPrioritySlice[ConnectionClosedEventHandler]
|
connectionClosedEventHandlers listings.SyncPrioritySlice[ConnectionClosedEventHandler]
|
||||||
connectionReceivePacketEventHandlers listings.SyncPrioritySlice[ConnectionReceivePacketEventHandler]
|
connectionReceivePacketEventHandlers listings.SyncPrioritySlice[ConnectionReceivePacketEventHandler]
|
||||||
|
@ -92,3 +103,16 @@ func (s *events) onConnectionReceivePacket(conn Conn, packet Packet) {
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *events) RegisterShutdownEvent(handler ShutdownEventHandler, priority ...int) {
|
||||||
|
s.shutdownEventHandlers.AppendByOptionalPriority(handler, priority...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *events) onShutdown() {
|
||||||
|
_ = s.server.reactor.SystemDispatch(NativeMessage(s.server, func(srv *server) {
|
||||||
|
s.shutdownEventHandlers.RangeValue(func(index int, value ShutdownEventHandler) bool {
|
||||||
|
value(s.server)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type notify struct {
|
||||||
|
server *server
|
||||||
|
|
||||||
|
systemSignal chan os.Signal
|
||||||
|
lifeCycleLimit chan struct{}
|
||||||
|
lifeCycleTimer *time.Timer
|
||||||
|
lifeCycleTime chan time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *notify) init(srv *server) *notify {
|
||||||
|
n.server = srv
|
||||||
|
n.systemSignal = make(chan os.Signal, 1)
|
||||||
|
n.lifeCycleLimit = make(chan struct{}, 1)
|
||||||
|
n.lifeCycleTime = make(chan time.Duration, 1)
|
||||||
|
n.lifeCycleTimer = time.NewTimer(math.MaxInt64)
|
||||||
|
n.lifeCycleTimer.Stop()
|
||||||
|
signal.Notify(n.systemSignal, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *notify) run() {
|
||||||
|
defer func() {
|
||||||
|
if err := n.server.Shutdown(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-n.systemSignal:
|
||||||
|
return
|
||||||
|
case <-n.lifeCycleLimit:
|
||||||
|
n.systemSignal <- syscall.SIGQUIT
|
||||||
|
case <-n.lifeCycleTimer.C:
|
||||||
|
n.systemSignal <- syscall.SIGQUIT
|
||||||
|
case d := <-n.lifeCycleTime:
|
||||||
|
n.lifeCycleTimer.Stop()
|
||||||
|
if d > 0 {
|
||||||
|
n.lifeCycleTimer.Reset(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewOptions() *Options {
|
||||||
|
return DefaultOptions()
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultOptions() *Options {
|
||||||
|
return &Options{
|
||||||
|
ServerMessageChannelSize: 1024 * 4,
|
||||||
|
ActorMessageChannelSize: 1024,
|
||||||
|
ServerMessageBufferInitialSize: 1024,
|
||||||
|
ActorMessageBufferInitialSize: 1024,
|
||||||
|
MessageErrorHandler: nil,
|
||||||
|
LifeCycleLimit: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
server *server
|
||||||
|
rw sync.RWMutex
|
||||||
|
ServerMessageChannelSize int // 服务器 Actor 消息处理管道大小
|
||||||
|
ActorMessageChannelSize int // Actor 消息处理管道大小
|
||||||
|
ServerMessageBufferInitialSize int // 服务器 Actor 消息写入缓冲区初始化大小
|
||||||
|
ActorMessageBufferInitialSize int // Actor 消息写入缓冲区初始化大小
|
||||||
|
MessageErrorHandler func(srv Server, message Message, err error) // 消息错误处理器
|
||||||
|
LifeCycleLimit time.Duration // 服务器生命周期上限,在服务器启动后达到生命周期上限将关闭服务器
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) init(srv *server) *Options {
|
||||||
|
opt.server = srv
|
||||||
|
return opt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) Apply(options ...*Options) {
|
||||||
|
opt.rw.Lock()
|
||||||
|
defer opt.rw.Unlock()
|
||||||
|
for _, option := range options {
|
||||||
|
option.rw.RLock()
|
||||||
|
|
||||||
|
opt.ServerMessageChannelSize = option.ServerMessageChannelSize
|
||||||
|
opt.ActorMessageChannelSize = option.ActorMessageChannelSize
|
||||||
|
opt.ServerMessageBufferInitialSize = option.ServerMessageBufferInitialSize
|
||||||
|
opt.ActorMessageBufferInitialSize = option.ActorMessageBufferInitialSize
|
||||||
|
opt.MessageErrorHandler = option.MessageErrorHandler
|
||||||
|
opt.LifeCycleLimit = option.LifeCycleLimit
|
||||||
|
|
||||||
|
option.rw.RUnlock()
|
||||||
|
}
|
||||||
|
if opt.server != nil && !opt.server.state.LaunchedAt.IsZero() {
|
||||||
|
opt.active()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) active() {
|
||||||
|
opt.server.notify.lifeCycleTime <- opt.getLifeCycleLimit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithServerMessageChannelSize 设置服务器 Actor 用于处理消息的管道大小,当管道由于逻辑阻塞而导致满载时,会导致新消息无法及时从缓冲区拿出,从而增加内存的消耗,但是并不会影响消息的写入
|
||||||
|
func (opt *Options) WithServerMessageChannelSize(size int) *Options {
|
||||||
|
return opt.modifyOptionsValue(func(opt *Options) {
|
||||||
|
opt.ServerMessageChannelSize = size
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) getServerMessageChannelSize() int {
|
||||||
|
return getOptionsValue(opt, func(opt *Options) int {
|
||||||
|
return opt.ServerMessageChannelSize
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithActorMessageChannelSize 设置 Actor 用于处理消息的管道大小,当管道由于逻辑阻塞而导致满载时,会导致新消息无法及时从缓冲区拿出,从而增加内存的消耗,但是并不会影响消息的写入
|
||||||
|
func (opt *Options) WithActorMessageChannelSize(size int) *Options {
|
||||||
|
return opt.modifyOptionsValue(func(opt *Options) {
|
||||||
|
opt.ActorMessageChannelSize = size
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) getActorMessageChannelSize() int {
|
||||||
|
return getOptionsValue(opt, func(opt *Options) int {
|
||||||
|
return opt.ActorMessageChannelSize
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithServerMessageBufferInitialSize 设置服务器 Actor 消息环形缓冲区 buffer.Ring 的初始大小,适当的值可以避免频繁扩容
|
||||||
|
// - 由于扩容是按照当前大小的 2 倍进行扩容,过大的值也可能会导致内存消耗过高
|
||||||
|
func (opt *Options) WithServerMessageBufferInitialSize(size int) *Options {
|
||||||
|
return opt.modifyOptionsValue(func(opt *Options) {
|
||||||
|
opt.ServerMessageBufferInitialSize = size
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) getServerMessageBufferInitialSize() int {
|
||||||
|
return getOptionsValue(opt, func(opt *Options) int {
|
||||||
|
return opt.ServerMessageBufferInitialSize
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithActorMessageBufferInitialSize 设置 Actor 消息环形缓冲区 buffer.Ring 的初始大小,适当的值可以避免频繁扩容
|
||||||
|
// - 由于扩容是按照当前大小的 2 倍进行扩容,过大的值也可能会导致内存消耗过高
|
||||||
|
func (opt *Options) WithActorMessageBufferInitialSize(size int) *Options {
|
||||||
|
return opt.modifyOptionsValue(func(opt *Options) {
|
||||||
|
opt.ActorMessageBufferInitialSize = size
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) getActorMessageBufferInitialSize() int {
|
||||||
|
return getOptionsValue(opt, func(opt *Options) int {
|
||||||
|
return opt.ActorMessageBufferInitialSize
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMessageErrorHandler 设置消息错误处理器,当消息处理出现错误时,会调用该处理器进行处理
|
||||||
|
// - 如果在运行时设置,后续消息错误将会使用新的 handler 进行处理
|
||||||
|
func (opt *Options) WithMessageErrorHandler(handler func(srv Server, message Message, err error)) *Options {
|
||||||
|
return opt.modifyOptionsValue(func(opt *Options) {
|
||||||
|
opt.MessageErrorHandler = handler
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) getMessageErrorHandler() func(srv Server, message Message, err error) {
|
||||||
|
return getOptionsValue(opt, func(opt *Options) func(srv Server, message Message, err error) {
|
||||||
|
return opt.MessageErrorHandler
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLifeCycleLimit 设置服务器生命周期上限,在服务器启动后达到生命周期上限将关闭服务器
|
||||||
|
// - 如果设置为 <= 0 的值,将不限制服务器生命周期
|
||||||
|
// - 该函数支持运行时设置
|
||||||
|
func (opt *Options) WithLifeCycleLimit(limit time.Duration) *Options {
|
||||||
|
return opt.modifyOptionsValue(func(opt *Options) {
|
||||||
|
opt.LifeCycleLimit = limit
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLifeCycleEnd 设置服务器生命周期终点,在服务器达到该时间后将关闭服务器
|
||||||
|
// - 如果设置 end 为零值或小于当前时间的值,将不限制服务器生命周期
|
||||||
|
// - 该函数支持运行时设置
|
||||||
|
func (opt *Options) WithLifeCycleEnd(end time.Time) *Options {
|
||||||
|
return opt.modifyOptionsValue(func(opt *Options) {
|
||||||
|
now := time.Now()
|
||||||
|
if end.Before(now) {
|
||||||
|
opt.LifeCycleLimit = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
opt.LifeCycleLimit = end.Sub(now)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// getLifeCycleLimit 获取服务器生命周期上限
|
||||||
|
func (opt *Options) getLifeCycleLimit() time.Duration {
|
||||||
|
return getOptionsValue(opt, func(opt *Options) time.Duration {
|
||||||
|
return opt.LifeCycleLimit
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opt *Options) modifyOptionsValue(handler func(opt *Options)) *Options {
|
||||||
|
opt.rw.Lock()
|
||||||
|
handler(opt)
|
||||||
|
opt.rw.Unlock()
|
||||||
|
return opt
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOptionsValue[V any](opt *Options, handler func(opt *Options) V) V {
|
||||||
|
opt.rw.RLock()
|
||||||
|
defer opt.rw.RUnlock()
|
||||||
|
return handler(opt)
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/pprof"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
httpPProf *http.Server // HTTP PProf 服务器
|
||||||
|
httpPProfMutex sync.Mutex // HTTP PProf 服务器互斥锁
|
||||||
|
)
|
||||||
|
|
||||||
|
// EnableHttpPProf 设置启用 http pprof
|
||||||
|
// - 该函数支持运行时调用
|
||||||
|
func EnableHttpPProf(addr, prefix string, errorHandler func(err error)) {
|
||||||
|
httpPProfMutex.Lock()
|
||||||
|
defer httpPProfMutex.Unlock()
|
||||||
|
if httpPProf != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc(fmt.Sprintf("GET %s/", prefix), pprof.Index)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("GET %s/heap", prefix), pprof.Handler("heap").ServeHTTP)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("GET %s/goroutine", prefix), pprof.Handler("goroutine").ServeHTTP)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("GET %s/block", prefix), pprof.Handler("block").ServeHTTP)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("GET %s/threadcreate", prefix), pprof.Handler("threadcreate").ServeHTTP)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("GET %s/cmdline", prefix), pprof.Cmdline)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("GET %s/profile", prefix), pprof.Profile)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("GET %s/symbol", prefix), pprof.Symbol)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("POST %s/symbol", prefix), pprof.Symbol)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("GET %s/trace", prefix), pprof.Trace)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("GET %s/mutex", prefix), pprof.Handler("mutex").ServeHTTP)
|
||||||
|
srv := &http.Server{Addr: addr, Handler: mux}
|
||||||
|
httpPProf = srv
|
||||||
|
go func(srv *http.Server, errHandler func(err error)) {
|
||||||
|
if err := srv.ListenAndServe(); err != nil {
|
||||||
|
errorHandler(err)
|
||||||
|
}
|
||||||
|
}(srv, errorHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableHttpPProf 设置禁用 http pprof
|
||||||
|
// - 该函数支持运行时调用
|
||||||
|
func DisableHttpPProf() {
|
||||||
|
httpPProfMutex.Lock()
|
||||||
|
defer httpPProfMutex.Unlock()
|
||||||
|
if httpPProf == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = httpPProf.Close()
|
||||||
|
httpPProf = nil
|
||||||
|
}
|
|
@ -14,24 +14,25 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
StatusNone = iota - 1 // 事件循环未运行
|
statusNone = iota - 1 // 事件循环未运行
|
||||||
StatusRunning // 事件循环运行中
|
statusRunning // 事件循环运行中
|
||||||
StatusClosing // 事件循环关闭中
|
statusClosing // 事件循环关闭中
|
||||||
StatusClosed // 事件循环已关闭
|
statusClosed // 事件循环已关闭
|
||||||
)
|
)
|
||||||
|
|
||||||
var sysIdent = &identifiable{ident: "system"}
|
var sysIdent = &identifiable{ident: "system"}
|
||||||
|
|
||||||
// NewReactor 创建一个新的 Reactor 实例,初始化系统级别的队列和多个 Socket 对应的队列
|
// NewReactor 创建一个新的 Reactor 实例,初始化系统级别的队列和多个 Socket 对应的队列
|
||||||
func NewReactor[M any](systemQueueSize, queueSize int, handler MessageHandler[M], errorHandler ErrorHandler[M]) *Reactor[M] {
|
func NewReactor[M any](systemQueueSize, queueSize, systemBufferSize, queueBufferSize int, handler MessageHandler[M], errorHandler ErrorHandler[M]) *Reactor[M] {
|
||||||
r := &Reactor[M]{
|
r := &Reactor[M]{
|
||||||
logger: log.Default().Logger,
|
logger: log.Default().Logger,
|
||||||
systemQueue: newQueue[M](-1, systemQueueSize, 1024),
|
systemQueue: newQueue[M](-1, systemQueueSize, systemBufferSize),
|
||||||
identifiers: haxmap.New[string, *identifiable](),
|
identifiers: haxmap.New[string, *identifiable](),
|
||||||
lb: loadbalancer.NewRoundRobin[int, *queue[M]](),
|
lb: loadbalancer.NewRoundRobin[int, *queue[M]](),
|
||||||
errorHandler: errorHandler,
|
errorHandler: errorHandler,
|
||||||
queueSize: queueSize,
|
queueSize: queueSize,
|
||||||
state: StatusNone,
|
queueBufferSize: queueBufferSize,
|
||||||
|
state: statusNone,
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultNum := runtime.NumCPU()
|
defaultNum := runtime.NumCPU()
|
||||||
|
@ -79,25 +80,20 @@ func NewReactor[M any](systemQueueSize, queueSize int, handler MessageHandler[M]
|
||||||
|
|
||||||
// Reactor 是一个消息反应器,管理系统级别的队列和多个 Socket 对应的队列
|
// Reactor 是一个消息反应器,管理系统级别的队列和多个 Socket 对应的队列
|
||||||
type Reactor[M any] struct {
|
type Reactor[M any] struct {
|
||||||
logger *slog.Logger // 日志记录器
|
logger *slog.Logger // 日志记录器
|
||||||
state int32 // 状态
|
state int32 // 状态
|
||||||
systemQueue *queue[M] // 系统级别的队列
|
systemQueue *queue[M] // 系统级别的队列
|
||||||
queueSize int // Socket 队列大小
|
queueSize int // 队列管道大小
|
||||||
queues []*queue[M] // Socket 使用的队列
|
queueBufferSize int // 队列缓冲区大小
|
||||||
queueRW sync.RWMutex // 队列读写锁
|
queues []*queue[M] // 所有使用的队列
|
||||||
identifiers *haxmap.Map[string, *identifiable] // 标识符到队列索引的映射及消息计数
|
queueRW sync.RWMutex // 队列读写锁
|
||||||
lb *loadbalancer.RoundRobin[int, *queue[M]] // 负载均衡器
|
identifiers *haxmap.Map[string, *identifiable] // 标识符到队列索引的映射及消息计数
|
||||||
wg sync.WaitGroup // 等待组
|
lb *loadbalancer.RoundRobin[int, *queue[M]] // 负载均衡器
|
||||||
cwg sync.WaitGroup // 关闭等待组
|
wg sync.WaitGroup // 等待组
|
||||||
handler queueMessageHandler[M] // 消息处理器
|
cwg sync.WaitGroup // 关闭等待组
|
||||||
errorHandler ErrorHandler[M] // 错误处理器
|
handler queueMessageHandler[M] // 消息处理器
|
||||||
debug bool // 是否开启调试模式
|
errorHandler ErrorHandler[M] // 错误处理器
|
||||||
}
|
debug bool // 是否开启调试模式
|
||||||
|
|
||||||
// SetLogger 设置日志记录器
|
|
||||||
func (r *Reactor[M]) SetLogger(logger *slog.Logger) *Reactor[M] {
|
|
||||||
r.logger = logger
|
|
||||||
return r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDebug 设置是否开启调试模式
|
// SetDebug 设置是否开启调试模式
|
||||||
|
@ -116,7 +112,7 @@ func (r *Reactor[M]) AutoDispatch(ident string, msg M) error {
|
||||||
|
|
||||||
// SystemDispatch 将消息分发到系统级别的队列
|
// SystemDispatch 将消息分发到系统级别的队列
|
||||||
func (r *Reactor[M]) SystemDispatch(msg M) error {
|
func (r *Reactor[M]) SystemDispatch(msg M) error {
|
||||||
if atomic.LoadInt32(&r.state) > StatusRunning {
|
if atomic.LoadInt32(&r.state) > statusRunning {
|
||||||
r.queueRW.RUnlock()
|
r.queueRW.RUnlock()
|
||||||
return fmt.Errorf("reactor closing or closed")
|
return fmt.Errorf("reactor closing or closed")
|
||||||
}
|
}
|
||||||
|
@ -126,7 +122,7 @@ func (r *Reactor[M]) SystemDispatch(msg M) error {
|
||||||
// Dispatch 将消息分发到 ident 使用的队列,当 ident 首次使用时,将会根据负载均衡策略选择一个队列
|
// Dispatch 将消息分发到 ident 使用的队列,当 ident 首次使用时,将会根据负载均衡策略选择一个队列
|
||||||
func (r *Reactor[M]) Dispatch(ident string, msg M) error {
|
func (r *Reactor[M]) Dispatch(ident string, msg M) error {
|
||||||
r.queueRW.RLock()
|
r.queueRW.RLock()
|
||||||
if atomic.LoadInt32(&r.state) > StatusRunning {
|
if atomic.LoadInt32(&r.state) > statusRunning {
|
||||||
r.queueRW.RUnlock()
|
r.queueRW.RUnlock()
|
||||||
return fmt.Errorf("reactor closing or closed")
|
return fmt.Errorf("reactor closing or closed")
|
||||||
}
|
}
|
||||||
|
@ -140,7 +136,7 @@ func (r *Reactor[M]) Dispatch(ident string, msg M) error {
|
||||||
|
|
||||||
// Run 启动 Reactor,运行系统级别的队列和多个 Socket 对应的队列
|
// Run 启动 Reactor,运行系统级别的队列和多个 Socket 对应的队列
|
||||||
func (r *Reactor[M]) Run() {
|
func (r *Reactor[M]) Run() {
|
||||||
if !atomic.CompareAndSwapInt32(&r.state, StatusNone, StatusRunning) {
|
if !atomic.CompareAndSwapInt32(&r.state, statusNone, statusRunning) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.queueRW.Lock()
|
r.queueRW.Lock()
|
||||||
|
@ -153,7 +149,7 @@ func (r *Reactor[M]) Run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reactor[M]) noneLockAddQueue() {
|
func (r *Reactor[M]) noneLockAddQueue() {
|
||||||
q := newQueue[M](len(r.queues), r.queueSize, 1024*8)
|
q := newQueue[M](len(r.queues), r.queueSize, r.queueBufferSize)
|
||||||
r.lb.Add(q) // 运行前添加到负载均衡器,未运行时允许接收消息
|
r.lb.Add(q) // 运行前添加到负载均衡器,未运行时允许接收消息
|
||||||
r.queues = append(r.queues, q)
|
r.queues = append(r.queues, q)
|
||||||
}
|
}
|
||||||
|
@ -187,7 +183,7 @@ func (r *Reactor[M]) runQueue(q *queue[M]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reactor[M]) Close() {
|
func (r *Reactor[M]) Close() {
|
||||||
if !atomic.CompareAndSwapInt32(&r.state, StatusRunning, StatusClosing) {
|
if !atomic.CompareAndSwapInt32(&r.state, statusRunning, statusClosing) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.queueRW.Lock()
|
r.queueRW.Lock()
|
||||||
|
@ -196,6 +192,6 @@ func (r *Reactor[M]) Close() {
|
||||||
q.Close()
|
q.Close()
|
||||||
}
|
}
|
||||||
r.cwg.Wait()
|
r.cwg.Wait()
|
||||||
atomic.StoreInt32(&r.state, StatusClosed)
|
atomic.StoreInt32(&r.state, statusClosed)
|
||||||
r.queueRW.Unlock()
|
r.queueRW.Unlock()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kercylan98/minotaur/server/internal/v2/reactor"
|
"github.com/kercylan98/minotaur/server/internal/v2/reactor"
|
||||||
"github.com/kercylan98/minotaur/utils/network"
|
"github.com/kercylan98/minotaur/utils/network"
|
||||||
"golang.org/x/net/context"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server interface {
|
type Server interface {
|
||||||
|
@ -26,24 +24,36 @@ type Server interface {
|
||||||
type server struct {
|
type server struct {
|
||||||
*controller
|
*controller
|
||||||
*events
|
*events
|
||||||
|
*Options
|
||||||
state *State
|
state *State
|
||||||
|
notify *notify
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
network Network
|
network Network
|
||||||
reactor *reactor.Reactor[Message]
|
reactor *reactor.Reactor[Message]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(network Network) Server {
|
func NewServer(network Network, options ...*Options) Server {
|
||||||
srv := &server{
|
srv := &server{
|
||||||
network: network,
|
network: network,
|
||||||
|
Options: DefaultOptions(),
|
||||||
}
|
}
|
||||||
srv.ctx, srv.cancel = context.WithCancel(context.Background())
|
srv.ctx, srv.cancel = context.WithCancel(context.Background())
|
||||||
|
srv.notify = new(notify).init(srv)
|
||||||
srv.controller = new(controller).init(srv)
|
srv.controller = new(controller).init(srv)
|
||||||
srv.events = new(events).init(srv)
|
srv.events = new(events).init(srv)
|
||||||
srv.reactor = reactor.NewReactor[Message](1024*8, 1024, func(msg Message) {
|
|
||||||
msg.Execute()
|
|
||||||
}, nil)
|
|
||||||
srv.state = new(State).init(srv)
|
srv.state = new(State).init(srv)
|
||||||
|
srv.reactor = reactor.NewReactor[Message](
|
||||||
|
srv.getServerMessageChannelSize(), srv.getActorMessageChannelSize(),
|
||||||
|
srv.getServerMessageBufferInitialSize(), srv.getActorMessageBufferInitialSize(),
|
||||||
|
func(msg Message) {
|
||||||
|
msg.Execute()
|
||||||
|
}, func(msg Message, err error) {
|
||||||
|
if handler := srv.getMessageErrorHandler(); handler != nil {
|
||||||
|
handler(srv, msg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
srv.Options.init(srv).Apply(options...)
|
||||||
return srv
|
return srv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,17 +71,14 @@ func (s *server) Run() (err error) {
|
||||||
}
|
}
|
||||||
}(s)
|
}(s)
|
||||||
|
|
||||||
var systemSignal = make(chan os.Signal)
|
s.Options.active()
|
||||||
signal.Notify(systemSignal, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
|
s.notify.run()
|
||||||
<-systemSignal
|
|
||||||
if err := s.Shutdown(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Shutdown() (err error) {
|
func (s *server) Shutdown() (err error) {
|
||||||
defer s.cancel()
|
defer s.cancel()
|
||||||
|
s.events.onShutdown()
|
||||||
err = s.network.OnShutdown()
|
err = s.network.OnShutdown()
|
||||||
s.reactor.Close()
|
s.reactor.Close()
|
||||||
return
|
return
|
||||||
|
|
|
@ -4,17 +4,26 @@ import (
|
||||||
"github.com/gobwas/ws"
|
"github.com/gobwas/ws"
|
||||||
"github.com/kercylan98/minotaur/server/internal/v2"
|
"github.com/kercylan98/minotaur/server/internal/v2"
|
||||||
"github.com/kercylan98/minotaur/server/internal/v2/network"
|
"github.com/kercylan98/minotaur/server/internal/v2/network"
|
||||||
|
"github.com/kercylan98/minotaur/utils/times"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewServer(t *testing.T) {
|
func TestNewServer(t *testing.T) {
|
||||||
srv := server.NewServer(network.WebSocket(":9999"))
|
server.EnableHttpPProf(":9998", "/debug/pprof", func(err error) {
|
||||||
|
panic(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
srv := server.NewServer(network.WebSocket(":9999"), server.NewOptions().WithLifeCycleLimit(times.Second*3))
|
||||||
|
|
||||||
srv.RegisterLaunchedEvent(func(srv server.Server, ip string, launchedAt time.Time) {
|
srv.RegisterLaunchedEvent(func(srv server.Server, ip string, launchedAt time.Time) {
|
||||||
t.Log("launched", ip, launchedAt)
|
t.Log("launched", ip, launchedAt)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
srv.RegisterShutdownEvent(func(srv server.Server) {
|
||||||
|
t.Log("shutdown")
|
||||||
|
})
|
||||||
|
|
||||||
srv.RegisterConnectionOpenedEvent(func(srv server.Server, conn server.Conn) {
|
srv.RegisterConnectionOpenedEvent(func(srv server.Server, conn server.Conn) {
|
||||||
if err := conn.WritePacket(server.NewPacket([]byte("hello")).SetContext(ws.OpText)); err != nil {
|
if err := conn.WritePacket(server.NewPacket([]byte("hello")).SetContext(ws.OpText)); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
|
Loading…
Reference in New Issue