Merge remote-tracking branch 'origin/develop-v2' into develop-v2
# Conflicts: # server/internal/v2/reactor/reactor.go
This commit is contained in:
commit
92f30cdadc
|
@ -0,0 +1,3 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
type
|
|
@ -0,0 +1,7 @@
|
||||||
|
package actor
|
||||||
|
|
||||||
|
import "github.com/kercylan98/minotaur/server/internal/v2/dispatcher"
|
||||||
|
|
||||||
|
type Actor[M any] struct {
|
||||||
|
*dispatcher.Dispatcher[M]
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package balancer
|
||||||
|
|
||||||
|
type Item[Id comparable] interface {
|
||||||
|
// Id 返回唯一标识
|
||||||
|
Id() Id
|
||||||
|
|
||||||
|
// Weight 返回权重
|
||||||
|
Weight() int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Balancer[Id comparable, T Item[Id]] interface {
|
||||||
|
// Add 添加一个负载均衡目标
|
||||||
|
Add(t T)
|
||||||
|
|
||||||
|
// Remove 移除一个负载均衡目标
|
||||||
|
Remove(t T)
|
||||||
|
|
||||||
|
// Next 根据负载均衡策略选择下一个目标
|
||||||
|
Next() T
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package balancer
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
func NewRoundRobin[Id comparable, T Item[Id]]() *RoundRobin[Id, T] {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoundRobin[Id comparable, T Item[Id]] struct {
|
||||||
|
ref map[Id]int
|
||||||
|
items []T
|
||||||
|
rw sync.RWMutex
|
||||||
|
curr int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RoundRobin[Id, T]) Add(t T) {
|
||||||
|
r.rw.Lock()
|
||||||
|
defer r.rw.Unlock()
|
||||||
|
_, exist := r.ref[t.Id()]
|
||||||
|
if exist {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.ref[t.Id()] = len(r.items)
|
||||||
|
r.items = append(r.items, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RoundRobin[Id, T]) Remove(t T) {
|
||||||
|
r.rw.Lock()
|
||||||
|
defer r.rw.Unlock()
|
||||||
|
index, exist := r.ref[t.Id()]
|
||||||
|
if !exist {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.items = append(r.items[:index], r.items[index+1:]...)
|
||||||
|
delete(r.ref, t.Id())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RoundRobin[Id, T]) Next() T {
|
||||||
|
r.rw.RLock()
|
||||||
|
defer r.rw.RUnlock()
|
||||||
|
if r.curr >= len(r.items) {
|
||||||
|
r.curr = 0
|
||||||
|
}
|
||||||
|
t := r.items[r.curr]
|
||||||
|
r.curr++
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
package dispatcher
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"github.com/kercylan98/minotaur/utils/buffer"
|
||||||
|
"github.com/kercylan98/minotaur/utils/log"
|
||||||
|
"github.com/kercylan98/minotaur/utils/super"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewDispatcher 创建一个消息调度器
|
||||||
|
func NewDispatcher[M any](bufferSize int, handler func(M)) *Dispatcher[M] {
|
||||||
|
d := &Dispatcher[M]{
|
||||||
|
buf: buffer.NewRing[M](bufferSize),
|
||||||
|
bufCond: sync.NewCond(&sync.Mutex{}),
|
||||||
|
ctx: context.Background(),
|
||||||
|
}
|
||||||
|
|
||||||
|
d.BindErrorHandler(func(err error) {
|
||||||
|
log.Error("dispatcher", log.Err(err))
|
||||||
|
})
|
||||||
|
|
||||||
|
d.handler = func(m M) {
|
||||||
|
defer func() {
|
||||||
|
if err := super.RecoverTransform(recover()); err != nil {
|
||||||
|
d.errorHandler.Load().(func(error))(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
handler(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatcher 并发安全且不阻塞的消息调度器
|
||||||
|
type Dispatcher[M any] struct {
|
||||||
|
buf *buffer.Ring[M]
|
||||||
|
bufCond *sync.Cond
|
||||||
|
handler func(M)
|
||||||
|
closed bool
|
||||||
|
ctx context.Context
|
||||||
|
errorHandler atomic.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindErrorHandler 绑定一个错误处理器到调度器中
|
||||||
|
func (d *Dispatcher[M]) BindErrorHandler(handler func(error)) {
|
||||||
|
d.errorHandler.Store(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindContext 绑定一个上下文到调度器中
|
||||||
|
func (d *Dispatcher[M]) BindContext(ctx context.Context) {
|
||||||
|
d.bufCond.L.Lock()
|
||||||
|
d.ctx = ctx
|
||||||
|
if _, canceled := d.ctx.Deadline(); canceled {
|
||||||
|
d.closed = true
|
||||||
|
d.bufCond.Signal()
|
||||||
|
d.bufCond.L.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.bufCond.L.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send 发送消息到调度器中等待处理
|
||||||
|
func (d *Dispatcher[M]) Send(m M) error {
|
||||||
|
d.bufCond.L.Lock()
|
||||||
|
if d.closed {
|
||||||
|
d.bufCond.L.Unlock()
|
||||||
|
return errors.New("dispatcher closed")
|
||||||
|
}
|
||||||
|
d.buf.Write(m)
|
||||||
|
d.bufCond.Signal()
|
||||||
|
d.bufCond.L.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start 阻塞式启动调度器,调用后将开始处理消息
|
||||||
|
func (d *Dispatcher[M]) Start() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-d.ctx.Done():
|
||||||
|
d.Stop()
|
||||||
|
default:
|
||||||
|
d.bufCond.L.Lock()
|
||||||
|
if d.buf.Len() == 0 {
|
||||||
|
if d.closed {
|
||||||
|
d.bufCond.L.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.bufCond.Wait()
|
||||||
|
}
|
||||||
|
messages := d.buf.ReadAll()
|
||||||
|
d.bufCond.L.Unlock()
|
||||||
|
for _, msg := range messages {
|
||||||
|
d.handler(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop 停止调度器,调用后将不再接受新消息,但会处理完已有消息
|
||||||
|
func (d *Dispatcher[M]) Stop() {
|
||||||
|
d.bufCond.L.Lock()
|
||||||
|
d.closed = true
|
||||||
|
d.bufCond.Signal()
|
||||||
|
d.bufCond.L.Unlock()
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package reactor
|
||||||
|
|
||||||
|
type Event struct {
|
||||||
|
}
|
Loading…
Reference in New Issue