加入等待继电器释放,加入程序停止执行时释放所有资源

This commit is contained in:
2025-02-28 17:05:07 +08:00
parent 4973b8471e
commit 3a2fc431ac
5 changed files with 75 additions and 9 deletions

View File

@@ -11,7 +11,7 @@ log:
maxAge: 30 maxAge: 30
compress: true compress: true
mqtt: mqtt:
url: mqtt://58.144.199.46:1883 url: mqtt://wushan-mqtt.chaoshengshuzi.com:1883
aliyun: aliyun:
accessKeyID: accessKeyID:
accessKeySecret: accessKeySecret:

View File

@@ -126,7 +126,7 @@ func Run() {
if config.C.Relay != "" { if config.C.Relay != "" {
r, err = relay.New(config.C.Relay) r, err = relay.New(config.C.Relay)
if err != nil { if err != nil {
zap.S().Panicln("继电器连接异常: ", err) zap.S().Errorln("继电器连接异常: ", err)
} }
defer r.Close() defer r.Close()
} }
@@ -179,6 +179,9 @@ func Run() {
if e := cm.Disconnect(ctx); e != nil { if e := cm.Disconnect(ctx); e != nil {
zap.S().Errorln("断开连接异常", e) zap.S().Errorln("断开连接异常", e)
} }
if e := router.Disconnect(ctx); e != nil {
zap.S().Errorln("停止所以任务超时", e)
}
zap.S().Infoln("关闭完成") zap.S().Infoln("关闭完成")
} }

View File

@@ -35,7 +35,12 @@ func (c HandlersChain) Last() HandlerFunc {
type Engine struct { type Engine struct {
mu sync.RWMutex mu sync.RWMutex
queueWg sync.WaitGroup
ctx context.Context ctx context.Context
cancelCtx context.CancelFunc
done chan struct{}
Handlers HandlersChain Handlers HandlersChain
defaultHandler HandlersChain defaultHandler HandlersChain
subscriptions map[string]HandlersChain subscriptions map[string]HandlersChain
@@ -44,8 +49,11 @@ type Engine struct {
} }
func New(ctx context.Context) *Engine { func New(ctx context.Context) *Engine {
c, cancel := context.WithCancel(ctx)
return &Engine{ return &Engine{
ctx: ctx, ctx: c,
cancelCtx: cancel,
done: make(chan struct{}),
Handlers: make(HandlersChain, 0), Handlers: make(HandlersChain, 0),
subscriptions: make(map[string]HandlersChain), subscriptions: make(map[string]HandlersChain),
aliases: make(map[uint16]string), aliases: make(map[uint16]string),
@@ -54,8 +62,11 @@ func New(ctx context.Context) *Engine {
} }
func Default(ctx context.Context) *Engine { func Default(ctx context.Context) *Engine {
c, cancel := context.WithCancel(ctx)
engine := &Engine{ engine := &Engine{
ctx: ctx, ctx: c,
cancelCtx: cancel,
done: make(chan struct{}),
Handlers: make(HandlersChain, 0), Handlers: make(HandlersChain, 0),
subscriptions: make(map[string]HandlersChain), subscriptions: make(map[string]HandlersChain),
aliases: make(map[uint16]string), aliases: make(map[uint16]string),
@@ -108,13 +119,21 @@ func (e *Engine) Route(pb *packets.Publish) {
for route, handlers := range e.subscriptions { for route, handlers := range e.subscriptions {
if match(route, topic) { if match(route, topic) {
e.debug.Println("found handler for:", route) e.debug.Println("found handler for:", route)
go WithLeafContext(e.ctx, m, e, handlers).Next() e.queueWg.Add(1)
go func() {
defer e.queueWg.Done()
WithLeafContext(e.ctx, m, e, handlers).Next()
}()
handlerCalled = true handlerCalled = true
} }
} }
if !handlerCalled && e.defaultHandler != nil { if !handlerCalled && e.defaultHandler != nil {
go WithLeafContext(e.ctx, m, e, e.defaultHandler).Next() e.queueWg.Add(1)
go func() {
defer e.queueWg.Done()
WithLeafContext(e.ctx, m, e, e.defaultHandler).Next()
}()
} }
} }
@@ -134,6 +153,21 @@ func (e *Engine) DefaultHandler(h HandlerFunc) {
e.defaultHandler = e.combineHandlers(HandlersChain{h}) e.defaultHandler = e.combineHandlers(HandlersChain{h})
} }
func (e *Engine) Disconnect(ctx context.Context) error {
go func() {
e.queueWg.Wait()
close(e.done)
}()
e.cancelCtx()
select {
case <-e.done: // wait for goroutine to exit
return nil
case <-ctx.Done():
return ctx.Err()
}
}
func (e *Engine) combineHandlers(handlers HandlersChain) HandlersChain { func (e *Engine) combineHandlers(handlers HandlersChain) HandlersChain {
finalSize := len(e.Handlers) + len(handlers) finalSize := len(e.Handlers) + len(handlers)
assert1(finalSize < int(abortIndex), "too many handlers") assert1(finalSize < int(abortIndex), "too many handlers")

View File

@@ -51,7 +51,7 @@ func InitProLogger(cls *TenCls) {
cn := zapcore.NewJSONEncoder(nc) cn := zapcore.NewJSONEncoder(nc)
// 多个输出 // 多个输出
mws := zapcore.NewMultiWriteSyncer(zapcore.AddSync(cls), zapcore.AddSync(os.Stdout)) mws := zapcore.NewMultiWriteSyncer(zapcore.AddSync(cls), zapcore.AddSync(config.C.Log.File), zapcore.AddSync(os.Stdout))
// 核心配置 // 核心配置
core := zapcore.NewCore(cn, mws, level) core := zapcore.NewCore(cn, mws, level)

View File

@@ -1,9 +1,15 @@
package relay package relay
import ( import (
"context"
"errors"
"github.com/grid-x/modbus" "github.com/grid-x/modbus"
"go.uber.org/zap" "go.uber.org/zap"
"io" "io"
"io/fs"
"os"
"strings"
"time"
) )
type Relay interface { type Relay interface {
@@ -56,6 +62,29 @@ func (r *device) Off(num int) error {
func New(address string) (Relay, error) { func New(address string) (Relay, error) {
zap.S().Infoln("连接继电器: ", address) zap.S().Infoln("连接继电器: ", address)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
a := make(chan struct{})
go func() {
defer close(a)
for {
select {
case <-ctx.Done():
zap.S().Infoln("等待继电器资源释放超时:", address)
return
case <-time.After(3 * time.Second):
_, err := os.OpenFile(address, os.O_RDWR, 0666)
var e *fs.PathError
if errors.As(err, &e) && strings.Contains(e.Error(), "busy") {
zap.S().Infoln("等待继电器资源释放:", address)
} else {
return
}
}
}
}()
<-a
h := modbus.NewRTUClientHandler(address) h := modbus.NewRTUClientHandler(address)
h.SlaveID = 1 h.SlaveID = 1
h.BaudRate = 9600 h.BaudRate = 9600