Merge branch 'master' into qiangg_garray2

This commit is contained in:
John 2019-02-20 16:28:24 +08:00
commit 7e06bf6705
9 changed files with 104 additions and 93 deletions

16
g/g_setting.go Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// 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,
// You can obtain one at https://github.com/gogf/gf.
package g
import "github.com/gogf/gf/g/net/ghttp"
// SetServerGraceful enables/disables graceful reload feature of ghttp Web Server.
//
// 是否开启WebServer的平滑重启特性。
func SetServerGraceful(enabled bool) {
ghttp.SetGraceful(enabled)
}

View File

@ -140,17 +140,24 @@ var (
doneChan = make(chan struct{}, 1000)
// 用于服务进程初始化,只能初始化一次,采用“懒初始化”(在server运行时才初始化)
serverProcInited = gtype.NewBool()
serverProcessInited = gtype.NewBool()
// 是否开启WebServer平滑重启特性, 会开启额外的本地端口监听,用于进程管理通信
gracefulEnabled = true
)
// 是否开启平滑重启特性
func SetGraceful(enabled bool) {
gracefulEnabled = enabled
}
// Web Server进程初始化.
// 注意该方法不能放置于包初始化方法init中不使用ghttp.Server的功能便不能初始化对应的协程goroutine逻辑.
func serverProcInit() {
if serverProcInited.Val() {
func serverProcessInit() {
if serverProcessInited.Val() {
return
}
serverProcInited.Set(true)
serverProcessInited.Set(true)
// 如果是完整重启,那么需要等待主进程销毁后,才开始执行监听,防止端口冲突
if genv.Get(gADMIN_ACTION_RESTART_ENVKEY) != "" {
if p, e := os.FindProcess(gproc.PPid()); e == nil {
@ -164,7 +171,9 @@ func serverProcInit() {
// 信号量管理操作监听
go handleProcessSignal()
// 异步监听进程间消息
go handleProcessMessage()
if gracefulEnabled {
go handleProcessMessage()
}
}
// 获取/创建一个默认配置的HTTP Server(默认监听端口是80)
@ -207,7 +216,7 @@ func GetServer(name...interface{}) (*Server) {
// 需要结合Wait方式一起使用
func (s *Server) Start() error {
// 服务进程初始化,只会初始化一次
serverProcInit()
serverProcessInit()
// 当前Web Server状态判断
if s.Status() == SERVER_STATUS_RUNNING {
@ -253,7 +262,7 @@ func (s *Server) Start() error {
if gproc.IsChild() {
gtimer.SetTimeout(2*time.Second, func() {
if err := gproc.Send(gproc.PPid(), []byte("exit"), gADMIN_GPROC_COMM_GROUP); err != nil {
panic(err)
glog.Error("ghttp server error in process communication:", err)
}
})
}

View File

@ -117,23 +117,23 @@ func newSchedule(pattern string) (*cronSchedule, error) {
schedule.hour = m
}
// 天
if m, err := parseItem(match[4], 1, 31, false); err != nil {
if m, err := parseItem(match[4], 1, 31, true); err != nil {
return nil, err
} else {
schedule.day = m
}
// 周
if m, err := parseItem(match[5], 0, 6, false); err != nil {
return nil, err
} else {
schedule.week = m
}
// 月
if m, err := parseItem(match[6], 1, 12, false); err != nil {
if m, err := parseItem(match[5], 1, 12, false); err != nil {
return nil, err
} else {
schedule.month = m
}
// 周
if m, err := parseItem(match[6], 0, 6, true); err != nil {
return nil, err
} else {
schedule.week = m
}
return schedule, nil
} else {
return nil, errors.New(fmt.Sprintf(`invalid pattern: "%s"`, pattern))
@ -200,14 +200,14 @@ func parseItemValue(value string, valueType byte) (int, error) {
} else {
// 英文字母
switch valueType {
case 'w':
if i, ok := weekMap[strings.ToLower(value)]; ok {
return int(i), nil
}
case 'm':
if i, ok := monthMap[strings.ToLower(value)]; ok {
return int(i), nil
}
case 'w':
if i, ok := weekMap[strings.ToLower(value)]; ok {
return int(i), nil
}
}
}
return 0, errors.New(fmt.Sprintf(`invalid pattern value: "%s"`, value))
@ -234,10 +234,10 @@ func (s *cronSchedule) meet(t time.Time) bool {
if _, ok := s.day[t.Day()]; !ok {
return false
}
if _, ok := s.week[int(t.Weekday())]; !ok {
if _, ok := s.month[int(t.Month())]; !ok {
return false
}
if _, ok := s.month[int(t.Month())]; !ok {
if _, ok := s.week[int(t.Weekday())]; !ok {
return false
}
return true

View File

@ -47,31 +47,16 @@ func (c *Cache) GetBinContents(path string) []byte {
return b
}
// 添加文件监控
// 添加文件监控,一旦文件有变化立即清除缓存,下一次读取的时候再执行缓存。
func (c *Cache) addMonitor(path string) {
// 防止多goroutine同时调用
if c.cache.Contains(path) {
return
}
gfsnotify.Add(path, func(event *gfsnotify.Event) {
//glog.Debug("gfcache:", event)
length := 0
if r := c.cache.Get(path); r != nil {
length = len(r.([]byte))
}
// 是否删除
if event.IsRemove() {
c.cache.Remove(path)
c.size.Add(-length)
return
}
// 更新缓存内容
if c.cap.Val() == 0 || c.size.Val() < c.cap.Val() {
b := gfile.GetBinContents(path)
if len(b) > 0 {
c.size.Add(len(b) - length)
c.cache.Set(path, b)
}
c.size.Add(-len(r.([]byte)))
}
})
}

View File

@ -27,8 +27,10 @@ const (
gPROC_TEMP_DIR_ENV_KEY = "GPROC_TEMP_DIR"
)
// 进程开始执行时间
var processStartTime = time.Now()
var (
// 进程开始执行时间
processStartTime = time.Now()
)
// 获取当前进程ID
func Pid() int {

View File

@ -3,6 +3,7 @@
// 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,
// You can obtain one at https://github.com/gogf/gf.
// "不要通过共享内存来通信,而应该通过通信来共享内存"
@ -26,16 +27,43 @@ const (
)
var (
// 是否已开启TCP端口监听服务(使用int而非bool以便于使用原子操作判断是否开启)
tcpListeningCount = gtype.NewInt()
// 是否已开启TCP端口监听服务
tcpListened = gtype.NewBool()
)
// 获取其他进程传递到当前进程的消息包,阻塞执行。
// 进程只有在执行该方法后才会打开请求端口,默认情况下不允许进程间通信。
func Receive(group...string) *Msg {
// 一个进程只能开启一个监听goroutine
if tcpListened.Set(true) == false {
go startTcpListening()
}
queue := (*gqueue.Queue)(nil)
groupName := gPROC_COMM_DEAFULT_GRUOP_NAME
if len(group) > 0 {
groupName = group[0]
}
if v := commReceiveQueues.Get(groupName); v == nil {
commReceiveQueues.LockFunc(func(m map[string]interface{}) {
if v, ok := m[groupName]; ok {
queue = v.(*gqueue.Queue)
} else {
queue = gqueue.New(gPROC_MSG_QUEUE_MAX_LENGTH)
m[groupName] = queue
}
})
} else {
queue = v.(*gqueue.Queue)
}
if v := queue.Pop(); v != nil {
return v.(*Msg)
}
return nil
}
// 创建本地进程TCP通信服务
func startTcpListening() {
// 一个进程只能开启一个监听goroutine
if tcpListeningCount.Add(1) != 1 {
return
}
var listen *net.TCPListener
for i := gPROC_DEFAULT_TCP_PORT; ; i++ {
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("127.0.0.1:%d", i))
@ -48,7 +76,6 @@ func startTcpListening() {
}
// 将监听的端口保存到通信文件中(字符串类型存放)
gfile.PutContents(getCommFilePath(Pid()), gconv.String(i))
//glog.Printfln("%d: gproc listening on [%s]", Pid(), addr)
break
}
for {
@ -133,32 +160,3 @@ func bufferToMsgs(buffer []byte) []*Msg {
return msgs
}
// 获取其他进程传递到当前进程的消息包,阻塞执行。
func Receive(group...string) *Msg {
// 开启接收协程时才会开启端口监听
go startTcpListening()
var queue *gqueue.Queue
groupName := gPROC_COMM_DEAFULT_GRUOP_NAME
if len(group) > 0 {
groupName = group[0]
}
if v := commReceiveQueues.Get(groupName); v == nil {
commReceiveQueues.LockFunc(func(m map[string]interface{}) {
if v, ok := m[groupName]; ok {
queue = v.(*gqueue.Queue)
} else {
queue = gqueue.New(gPROC_MSG_QUEUE_MAX_LENGTH)
m[groupName] = queue
}
})
} else {
queue = v.(*gqueue.Queue)
}
if v := queue.Pop(); v != nil {
return v.(*Msg)
}
return nil
}

View File

@ -7,16 +7,16 @@
package gproc
import (
"github.com/gogf/gf/g/net/gtcp"
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g/encoding/gbinary"
"fmt"
"errors"
"time"
"bytes"
"errors"
"fmt"
"github.com/gogf/gf/g/encoding/gbinary"
"github.com/gogf/gf/g/net/gtcp"
"github.com/gogf/gf/g/os/gfcache"
"github.com/gogf/gf/g/os/glog"
"github.com/gogf/gf/g/util/gconv"
"io"
"time"
)
const (
@ -26,7 +26,7 @@ const (
gPROC_COMM_DEAFULT_GRUOP_NAME = "" // 默认分组名称
)
// 向指定gproc进程发送数据
// 向指定gproc进程发送数据.
// 数据格式:总长度(24bit)|发送进程PID(24bit)|接收进程PID(24bit)|分组长度(8bit)|分组名称(变长)|校验(32bit)|参数(变长)
func Send(pid int, data []byte, group...string) error {
groupName := gPROC_COMM_DEAFULT_GRUOP_NAME
@ -85,6 +85,6 @@ func getConnByPid(pid int) (*gtcp.Conn, error) {
// 获取指定进程监听的端口号
func getPortByPid(pid int) int {
path := getCommFilePath(pid)
content := gfile.GetContents(path)
content := gfcache.GetContents(path)
return gconv.Int(content)
}

View File

@ -1,17 +1,18 @@
package main
import (
"fmt"
"github.com/gogf/gf/g/os/gcron"
"github.com/gogf/gf/g/os/glog"
"time"
)
func main() {
cron := gcron.New()
glog.Println("start")
cron.DelayAddOnce(1, "* * * * * *", func() {
glog.Println("run")
})
func test() {
}
func main() {
_, err := gcron.Add("*/10 * * * * ?", test)
fmt.Println(err)
fmt.Println(gcron.Entries())
time.Sleep(10*time.Second)
}

View File

@ -1,5 +1,5 @@
package gf
const VERSION = "v1.5.3"
const VERSION = "v1.5.4"
const AUTHORS = "john<john@goframe.org>"