瀏覽代碼

feat:xiugai

wangchuanjin 5 月之前
父節點
當前提交
f793e38504

+ 1 - 1
pushentniche/go.mod

@@ -4,7 +4,7 @@ go 1.18
 
 
 require (
 require (
 	app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b
 	app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b
-	bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116081127-732973c81d06
+	bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8
 	github.com/ClickHouse/clickhouse-go/v2 v2.2.0
 	github.com/ClickHouse/clickhouse-go/v2 v2.2.0
 	github.com/gogf/gf/v2 v2.6.4
 	github.com/gogf/gf/v2 v2.6.4
 	go.mongodb.org/mongo-driver v1.11.4
 	go.mongodb.org/mongo-driver v1.11.4

+ 2 - 2
pushentniche/go.sum

@@ -2,8 +2,8 @@ app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d h1:WPsYuuptAd3UEgN+j
 app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d/go.mod h1:91/lSD/hS+ckMVP3WdidRzDhC60lLMdyce9QHy0cSMA=
 app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d/go.mod h1:91/lSD/hS+ckMVP3WdidRzDhC60lLMdyce9QHy0cSMA=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b h1:IjAmZuaG4voMYPuIh+phJYI4fwMM/cLfZ5LEz7wrEos=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b h1:IjAmZuaG4voMYPuIh+phJYI4fwMM/cLfZ5LEz7wrEos=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b/go.mod h1:XHNATN6tsJKHdCB0DbUtFdPPHXexTUFyB3RlO+lUUoM=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b/go.mod h1:XHNATN6tsJKHdCB0DbUtFdPPHXexTUFyB3RlO+lUUoM=
-bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116081127-732973c81d06 h1:J7KIv7rUH8S7wPVEoTVCzNhJp9WGTzkDJWrrpulY6SE=
-bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116081127-732973c81d06/go.mod h1:Q+r+DRzSIHAsYBA7i39O2UrZB6ZhRtfCjVpN7n1p+Fg=
+bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8 h1:LdzhsXqq4t42fqjZb/BwIRHFjNnRLs3Z+y+leCmrEhc=
+bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8/go.mod h1:Q+r+DRzSIHAsYBA7i39O2UrZB6ZhRtfCjVpN7n1p+Fg=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0 h1:60fFbyRAnn5vrnsPk99pVB2aJVin6nDIkNnmekdpFso=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0 h1:60fFbyRAnn5vrnsPk99pVB2aJVin6nDIkNnmekdpFso=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0/go.mod h1:rRiGzKG4F/fmkNxXQCxrkxNWc8yf1SmW8qWCKfGIQSM=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0/go.mod h1:rRiGzKG4F/fmkNxXQCxrkxNWc8yf1SmW8qWCKfGIQSM=
 bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.17 h1:QHjAuAYPJjml8e19ytWxgKAboo9+f6aQUH/s1UUEfrA=
 bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.17 h1:QHjAuAYPJjml8e19ytWxgKAboo9+f6aQUH/s1UUEfrA=

+ 5 - 0
pushentniche/push/config.json

@@ -98,6 +98,11 @@
 		"available":true,
 		"available":true,
 		"checkMaxPushPersion":0,
 		"checkMaxPushPersion":0,
 		"selectPoolSize":5,
 		"selectPoolSize":5,
+		"isRecommendNewest":true,
+		"wxNodeNum":2, 
+		"dayNum":7,
+		"count":1000000,
+		"retain":100000,
 		"wx":{
 		"wx":{
 			"id":"ahEQafQBYZX8cVYXko-XaU1QkJ8MHiR-O9UNv_BRMzk",
 			"id":"ahEQafQBYZX8cVYXko-XaU1QkJ8MHiR-O9UNv_BRMzk",
 			"url":"/jy_mobile/tabbar/recommendedlist"
 			"url":"/jy_mobile/tabbar/recommendedlist"

+ 14 - 3
pushentniche/push/config/config.go

@@ -76,9 +76,14 @@ type config struct {
 		} `json:"app"`
 		} `json:"app"`
 	} `json:"subMsgTip"`
 	} `json:"subMsgTip"`
 	NoMsgTip struct {
 	NoMsgTip struct {
-		Available           bool `json:"available"`
-		CheckMaxPushPersion int  `json:"checkMaxPushPersion"`
-		SelectPoolSize      int  `json:"selectPoolSize"`
+		Available           bool  `json:"available"`
+		CheckMaxPushPersion int   `json:"checkMaxPushPersion"`
+		SelectPoolSize      int   `json:"selectPoolSize"`
+		IsRecommendNewest   bool  `json:"isRecommendNewest"`
+		WxNodeNum           int64 `json:"wxNodeNum"`
+		DayNum              int64 `json:"dayNum"`
+		Count               int64 `json:"count"`
+		Retain              int64 `json:"retain"`
 		Wx                  struct {
 		Wx                  struct {
 			Id  string
 			Id  string
 			Url string
 			Url string
@@ -111,15 +116,21 @@ type pushMail struct {
 	MailReTry    int    `json:"mailReTry"`
 	MailReTry    int    `json:"mailReTry"`
 }
 }
 
 
+type task struct {
+	NoMsgTipLastId int64
+}
+
 var (
 var (
 	Gmails         []*mail.GmailAuth
 	Gmails         []*mail.GmailAuth
 	Config         *config
 	Config         *config
 	FastigiumStart int
 	FastigiumStart int
 	FastigiumEnd   int
 	FastigiumEnd   int
+	Task           *task
 )
 )
 
 
 func init() {
 func init() {
 	util.ReadConfig("./config.json", &Config)
 	util.ReadConfig("./config.json", &Config)
+	util.ReadConfig("./task.json", &Task)
 	//
 	//
 	if fastigiumTimes := strings.Split(Config.FastigiumTime, "-"); len(fastigiumTimes) == 2 {
 	if fastigiumTimes := strings.Split(Config.FastigiumTime, "-"); len(fastigiumTimes) == 2 {
 		FastigiumStart = util.IntAll(fastigiumTimes[0])
 		FastigiumStart = util.IntAll(fastigiumTimes[0])

+ 100 - 24
pushentniche/push/job/nomsgtipjob.go

@@ -6,9 +6,11 @@ import (
 	. "pushentniche/push/config"
 	. "pushentniche/push/config"
 	. "pushentniche/push/db"
 	. "pushentniche/push/db"
 	putil "pushentniche/push/util"
 	putil "pushentniche/push/util"
+	"sort"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
+	"sync/atomic"
 	"time"
 	"time"
 
 
 	util "app.yhyue.com/moapp/jybase/common"
 	util "app.yhyue.com/moapp/jybase/common"
@@ -46,17 +48,14 @@ func (n *NoMsgTipJob) Execute(taskType, hour int) {
 	InitEnt(Mysql, Mgo, DbConf.Mongodb.Main.DbName, Config.TestQuery)
 	InitEnt(Mysql, Mgo, DbConf.Mongodb.Main.DbName, Config.TestQuery)
 	pushPool := make(chan bool, Config.PushPoolSize)
 	pushPool := make(chan bool, Config.PushPoolSize)
 	pushWait := &sync.WaitGroup{}
 	pushWait := &sync.WaitGroup{}
+	lock := &sync.Mutex{}
+	allTipsA, allTipsB := []*UserInfo{}, []*UserInfo{}
 	for _, v := range EntUsers {
 	for _, v := range EntUsers {
-		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
-			logger.Error("推送任务", taskType, "推送放入通道超时,", v.Id)
-		})
 		pushWait.Add(1)
 		pushWait.Add(1)
-		go func(entUser *EntUser, take bool) {
+		go func(entUser *EntUser) {
 			defer util.Catch()
 			defer util.Catch()
 			defer func() {
 			defer func() {
-				if take {
-					<-pushPool
-				}
+				<-pushPool
 				pushWait.Done()
 				pushWait.Done()
 			}()
 			}()
 			user, userObj := NewMyUserInfoByEntUserId(Mgo, Mysql, fmt.Sprint(entUser.Id))
 			user, userObj := NewMyUserInfoByEntUserId(Mgo, Mysql, fmt.Sprint(entUser.Id))
@@ -86,24 +85,46 @@ func (n *NoMsgTipJob) Execute(taskType, hour int) {
 			if taskType == 1 || (taskType == 2 && user.PushSet.SubSet.RateMode == 2) || (taskType == 3 && user.PushSet.SubSet.RateMode == 3) ||
 			if taskType == 1 || (taskType == 2 && user.PushSet.SubSet.RateMode == 2) || (taskType == 3 && user.PushSet.SubSet.RateMode == 3) ||
 				(taskType == 4 && user.PushSet.SubSet.RateMode == 4) || (taskType == 5 && (user.PushSet.SubSet.RateMode == 3 || user.PushSet.SubSet.RateMode == 4)) ||
 				(taskType == 4 && user.PushSet.SubSet.RateMode == 4) || (taskType == 5 && (user.PushSet.SubSet.RateMode == 3 || user.PushSet.SubSet.RateMode == 4)) ||
 				(taskType == 6 && user.PushSet.SubSet.RateMode == 0) || (taskType == 7 && user.PushSet.SubSet.RateMode == 1) {
 				(taskType == 6 && user.PushSet.SubSet.RateMode == 0) || (taskType == 7 && user.PushSet.SubSet.RateMode == 1) {
-				n.tip(taskType, hour, user)
+				if n.isTip(taskType, hour, user) {
+					lock.Lock()
+					if int64(user.Entniche.UserId) > Task.NoMsgTipLastId {
+						allTipsA = append(allTipsA, user)
+					} else {
+						allTipsB = append(allTipsB, user)
+					}
+					lock.Unlock()
+				}
 			}
 			}
-		}(v, isTake)
+		}(v)
 	}
 	}
 	pushWait.Wait()
 	pushWait.Wait()
+	sort.Slice(allTipsA, func(i, j int) bool {
+		return allTipsA[i].Entniche.UserId < allTipsA[j].Entniche.UserId
+	})
+	sort.Slice(allTipsB, func(i, j int) bool {
+		return allTipsB[i].Entniche.UserId < allTipsB[j].Entniche.UserId
+	})
+	var noMsgTipLastId int64
+	wxTplSurplus := WxNoMsgTmplUsableNum(Mgo_Log, Config.NoMsgTip.WxNodeNum, Config.NoMsgTip.DayNum, Config.NoMsgTip.Count, Config.NoMsgTip.Retain)
+	if Config.NoMsgTip.IsRecommendNewest {
+		VarRecommend.SetNewest(1)
+	}
+	n.beforeTip(taskType, allTipsA, wxTplSurplus, &noMsgTipLastId)
+	n.beforeTip(taskType, allTipsB, wxTplSurplus, &noMsgTipLastId)
+	Task.NoMsgTipLastId = noMsgTipLastId
 	logger.Info("无消息提醒任务结束。。。", taskType, hour)
 	logger.Info("无消息提醒任务结束。。。", taskType, hour)
 }
 }
 
 
 //提醒
 //提醒
-func (n *NoMsgTipJob) tip(taskType, hour int, user *UserInfo) {
+func (n *NoMsgTipJob) isTip(taskType, hour int, user *UserInfo) bool {
 	now := time.Now()
 	now := time.Now()
 	if user.VipStatus != 1 && user.MemberStatus != 1 && user.NicheStatus != 1 {
 	if user.VipStatus != 1 && user.MemberStatus != 1 && user.NicheStatus != 1 {
 		if prevTipUnix, err := redis.GetNewInt(Pushcache_2_c, PrevNoMsgTipKey(user)); err != nil {
 		if prevTipUnix, err := redis.GetNewInt(Pushcache_2_c, PrevNoMsgTipKey(user)); err != nil {
 			logger.Error("无消息提醒任务", taskType, "redis判断三天前是否提醒过出错", err)
 			logger.Error("无消息提醒任务", taskType, "redis判断三天前是否提醒过出错", err)
-			return
+			return false
 		} else if now.Unix() < int64(prevTipUnix+ThreeDay) {
 		} else if now.Unix() < int64(prevTipUnix+ThreeDay) {
 			logger.Info("无消息提醒任务", taskType, "三天内已经提醒过,过滤掉", user.Id)
 			logger.Info("无消息提醒任务", taskType, "三天内已经提醒过,过滤掉", user.Id)
-			return
+			return false
 		}
 		}
 	}
 	}
 	startEndMd := ""
 	startEndMd := ""
@@ -116,7 +137,7 @@ func (n *NoMsgTipJob) tip(taskType, hour int, user *UserInfo) {
 	} else if user.PushSet.SubSet.RateMode == 2 {
 	} else if user.PushSet.SubSet.RateMode == 2 {
 		isOver, start, end := TimesIsOver(user.PushSet.SubSet.Times, hour)
 		isOver, start, end := TimesIsOver(user.PushSet.SubSet.Times, hour)
 		if taskType != 1 && !isOver {
 		if taskType != 1 && !isOver {
-			return
+			return false
 		}
 		}
 		startUnix = start.Unix()
 		startUnix = start.Unix()
 		endUnix = end.Unix()
 		endUnix = end.Unix()
@@ -137,44 +158,99 @@ func (n *NoMsgTipJob) tip(taskType, hour int, user *UserInfo) {
 		startUnix = start.Unix()
 		startUnix = start.Unix()
 		endUnix = now.Unix()
 		endUnix = now.Unix()
 	} else {
 	} else {
-		return
+		return false
 	}
 	}
 	if exists, err := redis.Exists(Pushcache_2_c, HasPushKey(user)); err != nil {
 	if exists, err := redis.Exists(Pushcache_2_c, HasPushKey(user)); err != nil {
 		logger.Error("无消息提醒任务", taskType, "redis判断今天订阅是否推送过出错", err, user.Entniche.UserId)
 		logger.Error("无消息提醒任务", taskType, "redis判断今天订阅是否推送过出错", err, user.Entniche.UserId)
-		return
+		return false
 	} else if exists {
 	} else if exists {
 		logger.Info("无消息提醒任务", taskType, "redis判断今天订阅推送过,过滤掉", user.Entniche.UserId)
 		logger.Info("无消息提醒任务", taskType, "redis判断今天订阅推送过,过滤掉", user.Entniche.UserId)
-		return
+		return false
 	} else if exists, err := redis.Exists(Pushcache_2_c, HasDisPushKey(user)); err != nil {
 	} else if exists, err := redis.Exists(Pushcache_2_c, HasDisPushKey(user)); err != nil {
 		logger.Error("无消息提醒任务", taskType, "redis判断今天分发是否推送过出错", err, user.Entniche.UserId)
 		logger.Error("无消息提醒任务", taskType, "redis判断今天分发是否推送过出错", err, user.Entniche.UserId)
-		return
+		return false
 	} else if exists {
 	} else if exists {
 		logger.Info("无消息提醒任务", taskType, "redis判断今天分发推送过,过滤掉", user.Entniche.UserId)
 		logger.Info("无消息提醒任务", taskType, "redis判断今天分发推送过,过滤掉", user.Entniche.UserId)
-		return
+		return false
 	} else if exists, err := redis.Exists(Pushcache_2_c, NoMsgTipKey(user)); err != nil {
 	} else if exists, err := redis.Exists(Pushcache_2_c, NoMsgTipKey(user)); err != nil {
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否提醒过出错", err, user.Entniche.UserId)
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否提醒过出错", err, user.Entniche.UserId)
-		return
+		return false
 	} else if exists {
 	} else if exists {
 		logger.Info("无消息提醒任务", taskType, "redis判断今天提醒过,过滤掉", user.Entniche.UserId)
 		logger.Info("无消息提醒任务", taskType, "redis判断今天提醒过,过滤掉", user.Entniche.UserId)
-		return
+		return false
 	} else if n.pushCount(user, startUnix, endUnix) != 0 {
 	} else if n.pushCount(user, startUnix, endUnix) != 0 {
 		logger.Info("无消息提醒任务", taskType, "mysql判断用户该时间段推送过,过滤掉", startUnix, endUnix, user.Entniche.UserId)
 		logger.Info("无消息提醒任务", taskType, "mysql判断用户该时间段推送过,过滤掉", startUnix, endUnix, user.Entniche.UserId)
-		return
+		return false
+	}
+	user.Extend = &UserInfoExtend{
+		Object: map[string]interface{}{"startEndMd": startEndMd},
+	}
+	return true
+}
+
+//
+func (n *NoMsgTipJob) beforeTip(taskType int, allTip []*UserInfo, wxTplSurplus int64, noMsgTipLastId *int64) {
+	pushPool := make(chan bool, Config.PushPoolSize)
+	pushWait := &sync.WaitGroup{}
+	for _, v := range allTip {
+		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
+			logger.Error("推送任务", taskType, "推送放入通道超时,", v.Id)
+		})
+		pushWait.Add(1)
+		go func(user *UserInfo, take bool) {
+			defer util.Catch()
+			defer func() {
+				if take {
+					<-pushPool
+				}
+				pushWait.Done()
+			}()
+			n.toTip(taskType, user, wxTplSurplus, noMsgTipLastId)
+		}(v, isTake)
 	}
 	}
+}
+
+//
+func (n *NoMsgTipJob) toTip(taskType int, user *UserInfo, wxTplSurplus int64, noMsgTipLastId *int64) {
 	firstTitle, area, jcly, mailContent, infoCount, firstAutoId := n.SubRecommend(user)
 	firstTitle, area, jcly, mailContent, infoCount, firstAutoId := n.SubRecommend(user)
 	if infoCount == 0 {
 	if infoCount == 0 {
 		logger.Info("无消息提醒任务", taskType, "没有要推荐的信息,过滤掉", user.Entniche.UserId)
 		logger.Info("无消息提醒任务", taskType, "没有要推荐的信息,过滤掉", user.Entniche.UserId)
 		return
 		return
 	}
 	}
+	now := time.Now()
 	redis.Put(Pushcache_2_c, NoMsgTipKey(user), 1, OneDaySecond)
 	redis.Put(Pushcache_2_c, NoMsgTipKey(user), 1, OneDaySecond)
 	redis.Put(Pushcache_2_c, PrevNoMsgTipKey(user), time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Unix(), ThreeDay+OneDaySecond)
 	redis.Put(Pushcache_2_c, PrevNoMsgTipKey(user), time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Unix(), ThreeDay+OneDaySecond)
 	logger.Info("无消息提醒任务", taskType, "开始推送", user.Entniche.UserId, "rateMode", user.PushSet.SubSet.RateMode, "jpushid", user.Jpushid, "opushid", user.Opushid, "appponetype", user.AppPhoneType, "email", user.PushSet.Email)
 	logger.Info("无消息提醒任务", taskType, "开始推送", user.Entniche.UserId, "rateMode", user.PushSet.SubSet.RateMode, "jpushid", user.Jpushid, "opushid", user.Opushid, "appponetype", user.AppPhoneType, "email", user.PushSet.Email)
 	ut1, _, ut3 := GetUserType(user)
 	ut1, _, ut3 := GetUserType(user)
+	startEndMd, _ := user.Extend.Object["startEndMd"].(string)
 	var isWxPushOk, isAppPushOk, isMailPushOk bool
 	var isWxPushOk, isAppPushOk, isMailPushOk bool
 	if user.PushSet.SubSet.WxPush == 1 {
 	if user.PushSet.SubSet.WxPush == 1 {
-		logger.Info("无消息提醒任务", taskType, "开始微信推送", user.Entniche.UserId)
-		isWxPushOk = n.sendWeixin(user, ut3, firstTitle, area, jcly, infoCount)
-		logger.Info("无消息提醒任务", taskType, "微信推送结束", isWxPushOk, user.Entniche.UserId)
+		isWxPush := false
+		if wxTplSurplus < 0 {
+			isWxPush = true
+		} else {
+			key := fmt.Sprintf(Redis_NoMsgTipWxTmplCount, FormatDate(&now, Date_yyyyMMdd))
+			maxNum, err := redis.IncrByErr(Pushcache_2_c, key)
+			if err != nil {
+				logger.Error("无消息提醒任务", taskType, "从redis获取noMsgTipWxTmplCount出错", err)
+			}
+			if maxNum == 1 {
+				redis.SetExpire(Pushcache_2_c, key, OneDaySecond)
+			}
+			if maxNum <= wxTplSurplus {
+				isWxPush = true
+			}
+		}
+		if isWxPush {
+			logger.Info("无消息提醒任务", taskType, "开始微信推送", user.Entniche.UserId)
+			isWxPushOk = n.sendWeixin(user, ut3, firstTitle, area, jcly, infoCount)
+			logger.Info("无消息提醒任务", taskType, "微信推送结束", isWxPushOk, user.Entniche.UserId)
+		} else {
+			if atomic.LoadInt64(noMsgTipLastId) < int64(user.Entniche.UserId) {
+				atomic.StoreInt64(noMsgTipLastId, int64(user.Entniche.UserId))
+			}
+			logger.Info("无消息提醒任务", taskType, "超过剩余模板消息量,不再推送微信", user.Entniche.UserId)
+		}
 	}
 	}
 	if user.PushSet.SubSet.AppPush == 1 {
 	if user.PushSet.SubSet.AppPush == 1 {
 		logger.Info("无消息提醒任务", taskType, "开始app推送", user.Entniche.UserId)
 		logger.Info("无消息提醒任务", taskType, "开始app推送", user.Entniche.UserId)

+ 1 - 0
pushentniche/push/task.json

@@ -0,0 +1 @@
+{"noMsgTipLastId":0}

+ 1 - 1
pushmember/go.mod

@@ -4,7 +4,7 @@ go 1.18
 
 
 require (
 require (
 	app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b
 	app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b
-	bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116070132-e8ff14c2cd7e
+	bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8
 	bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.17
 	bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.17
 	github.com/ClickHouse/clickhouse-go/v2 v2.2.0
 	github.com/ClickHouse/clickhouse-go/v2 v2.2.0
 )
 )

+ 2 - 2
pushmember/go.sum

@@ -2,8 +2,8 @@ app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d h1:WPsYuuptAd3UEgN+j
 app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d/go.mod h1:91/lSD/hS+ckMVP3WdidRzDhC60lLMdyce9QHy0cSMA=
 app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d/go.mod h1:91/lSD/hS+ckMVP3WdidRzDhC60lLMdyce9QHy0cSMA=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b h1:IjAmZuaG4voMYPuIh+phJYI4fwMM/cLfZ5LEz7wrEos=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b h1:IjAmZuaG4voMYPuIh+phJYI4fwMM/cLfZ5LEz7wrEos=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b/go.mod h1:XHNATN6tsJKHdCB0DbUtFdPPHXexTUFyB3RlO+lUUoM=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b/go.mod h1:XHNATN6tsJKHdCB0DbUtFdPPHXexTUFyB3RlO+lUUoM=
-bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116070132-e8ff14c2cd7e h1:gupic2bm20p3Jaug19YIVLzicZfLBgwxC3VygFfvFRU=
-bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116070132-e8ff14c2cd7e/go.mod h1:Q+r+DRzSIHAsYBA7i39O2UrZB6ZhRtfCjVpN7n1p+Fg=
+bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8 h1:LdzhsXqq4t42fqjZb/BwIRHFjNnRLs3Z+y+leCmrEhc=
+bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8/go.mod h1:Q+r+DRzSIHAsYBA7i39O2UrZB6ZhRtfCjVpN7n1p+Fg=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0 h1:60fFbyRAnn5vrnsPk99pVB2aJVin6nDIkNnmekdpFso=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0 h1:60fFbyRAnn5vrnsPk99pVB2aJVin6nDIkNnmekdpFso=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0/go.mod h1:rRiGzKG4F/fmkNxXQCxrkxNWc8yf1SmW8qWCKfGIQSM=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0/go.mod h1:rRiGzKG4F/fmkNxXQCxrkxNWc8yf1SmW8qWCKfGIQSM=
 bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.17 h1:QHjAuAYPJjml8e19ytWxgKAboo9+f6aQUH/s1UUEfrA=
 bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.17 h1:QHjAuAYPJjml8e19ytWxgKAboo9+f6aQUH/s1UUEfrA=

+ 5 - 0
pushmember/push/config.json

@@ -80,6 +80,11 @@
 		"available":true,
 		"available":true,
 		"checkMaxPushPersion":0,
 		"checkMaxPushPersion":0,
 		"selectPoolSize":5,
 		"selectPoolSize":5,
+		"isRecommendNewest":true,
+		"wxNodeNum":2, 
+		"dayNum":7,
+		"count":1000000,
+		"retain":100000,
 		"wx":{
 		"wx":{
 			"id":"WHcFvQgOLdlLOdXEfBe-Oy5SwrMK2zQqEKogJvXd7m0",
 			"id":"WHcFvQgOLdlLOdXEfBe-Oy5SwrMK2zQqEKogJvXd7m0",
 			"url":"/jy_mobile/tabbar/recommendedlist"
 			"url":"/jy_mobile/tabbar/recommendedlist"

+ 13 - 3
pushmember/push/config/config.go

@@ -63,9 +63,14 @@ type config struct {
 		Url   string `json:"url"`
 		Url   string `json:"url"`
 	} `json:"appMsg"`
 	} `json:"appMsg"`
 	NoMsgTip struct {
 	NoMsgTip struct {
-		Available           bool `json:"available"`
-		CheckMaxPushPersion int  `json:"checkMaxPushPersion"`
-		SelectPoolSize      int  `json:"selectPoolSize"`
+		Available           bool  `json:"available"`
+		CheckMaxPushPersion int   `json:"checkMaxPushPersion"`
+		SelectPoolSize      int   `json:"selectPoolSize"`
+		IsRecommendNewest   bool  `json:"isRecommendNewest"`
+		WxNodeNum           int64 `json:"wxNodeNum"`
+		DayNum              int64 `json:"dayNum"`
+		Count               int64 `json:"count"`
+		Retain              int64 `json:"retain"`
 		Wx                  struct {
 		Wx                  struct {
 			Id  string
 			Id  string
 			Url string
 			Url string
@@ -91,16 +96,21 @@ type pushMail struct {
 	MailPoolSize int    `json:"mailPoolSize"`
 	MailPoolSize int    `json:"mailPoolSize"`
 	MailReTry    int    `json:"mailReTry"`
 	MailReTry    int    `json:"mailReTry"`
 }
 }
+type task struct {
+	NoMsgTipLastId string
+}
 
 
 var (
 var (
 	Gmails         []*mail.GmailAuth
 	Gmails         []*mail.GmailAuth
 	Config         *config
 	Config         *config
 	FastigiumStart int
 	FastigiumStart int
 	FastigiumEnd   int
 	FastigiumEnd   int
+	Task           *task
 )
 )
 
 
 func init() {
 func init() {
 	util.ReadConfig("./config.json", &Config)
 	util.ReadConfig("./config.json", &Config)
+	util.ReadConfig("./task.json", &Task)
 	//
 	//
 	if fastigiumTimes := strings.Split(Config.FastigiumTime, "-"); len(fastigiumTimes) == 2 {
 	if fastigiumTimes := strings.Split(Config.FastigiumTime, "-"); len(fastigiumTimes) == 2 {
 		FastigiumStart = util.IntAll(fastigiumTimes[0])
 		FastigiumStart = util.IntAll(fastigiumTimes[0])

+ 93 - 12
pushmember/push/job/nomsgtipjob.go

@@ -6,9 +6,11 @@ import (
 	. "pushmember/push/config"
 	. "pushmember/push/config"
 	. "pushmember/push/db"
 	. "pushmember/push/db"
 	putil "pushmember/push/util"
 	putil "pushmember/push/util"
+	"sort"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
+	"sync/atomic"
 	"time"
 	"time"
 
 
 	util "app.yhyue.com/moapp/jybase/common"
 	util "app.yhyue.com/moapp/jybase/common"
@@ -59,6 +61,8 @@ func (n *NoMsgTipJob) Execute(taskType, hour int) {
 	it := sess.DB(DbConf.Mongodb.Main.DbName).C(Mgo_User).Find(query).Select(UserCollFields).Iter()
 	it := sess.DB(DbConf.Mongodb.Main.DbName).C(Mgo_User).Find(query).Select(UserCollFields).Iter()
 	pushPool := make(chan bool, Config.PushPoolSize)
 	pushPool := make(chan bool, Config.PushPoolSize)
 	pushWait := &sync.WaitGroup{}
 	pushWait := &sync.WaitGroup{}
+	lock := &sync.Mutex{}
+	allTipsA, allTipsB := []*UserInfo{}, []*UserInfo{}
 	for temp := make(map[string]interface{}); it.Next(&temp); {
 	for temp := make(map[string]interface{}); it.Next(&temp); {
 		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
 		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
 			logger.Error("推送任务", taskType, "推送放入通道超时,", temp["_id"])
 			logger.Error("推送任务", taskType, "推送放入通道超时,", temp["_id"])
@@ -85,17 +89,39 @@ func (n *NoMsgTipJob) Execute(taskType, hour int) {
 			}
 			}
 			if taskType == 1 || (taskType == 6 && user.PushSet.SubSet.RateMode == 1) || (taskType == 2 && user.PushSet.SubSet.RateMode == 2) || (taskType == 3 && user.PushSet.SubSet.RateMode == 3) ||
 			if taskType == 1 || (taskType == 6 && user.PushSet.SubSet.RateMode == 1) || (taskType == 2 && user.PushSet.SubSet.RateMode == 2) || (taskType == 3 && user.PushSet.SubSet.RateMode == 3) ||
 				(taskType == 4 && user.PushSet.SubSet.RateMode == 4) || (taskType == 5 && (user.PushSet.SubSet.RateMode == 3 || user.PushSet.SubSet.RateMode == 4)) {
 				(taskType == 4 && user.PushSet.SubSet.RateMode == 4) || (taskType == 5 && (user.PushSet.SubSet.RateMode == 3 || user.PushSet.SubSet.RateMode == 4)) {
-				n.tip(taskType, hour, user)
+				if n.isTip(taskType, hour, user) {
+					lock.Lock()
+					if user.Id > Task.NoMsgTipLastId {
+						allTipsA = append(allTipsA, user)
+					} else {
+						allTipsB = append(allTipsB, user)
+					}
+					lock.Unlock()
+				}
 			}
 			}
 		}(temp, isTake)
 		}(temp, isTake)
 		temp = make(map[string]interface{})
 		temp = make(map[string]interface{})
 	}
 	}
 	pushWait.Wait()
 	pushWait.Wait()
+	sort.Slice(allTipsA, func(i, j int) bool {
+		return allTipsA[i].Id < allTipsA[j].Id
+	})
+	sort.Slice(allTipsB, func(i, j int) bool {
+		return allTipsB[i].Id < allTipsB[j].Id
+	})
+	var noMsgTipLastId atomic.Value
+	wxTmplUsableNum := WxNoMsgTmplUsableNum(Mgo_Log, Config.NoMsgTip.WxNodeNum, Config.NoMsgTip.DayNum, Config.NoMsgTip.Count, Config.NoMsgTip.Retain)
+	if Config.NoMsgTip.IsRecommendNewest {
+		VarRecommend.SetNewest(1)
+	}
+	n.beforeTip(taskType, allTipsA, wxTmplUsableNum, noMsgTipLastId)
+	n.beforeTip(taskType, allTipsB, wxTmplUsableNum, noMsgTipLastId)
+	Task.NoMsgTipLastId = noMsgTipLastId.Load().(string)
 	logger.Info("无消息提醒任务结束。。。", taskType, hour)
 	logger.Info("无消息提醒任务结束。。。", taskType, hour)
 }
 }
 
 
 //提醒
 //提醒
-func (n *NoMsgTipJob) tip(taskType, hour int, user *UserInfo) {
+func (n *NoMsgTipJob) isTip(taskType, hour int, user *UserInfo) bool {
 	now := time.Now()
 	now := time.Now()
 	startEndMd := ""
 	startEndMd := ""
 	var startUnix, endUnix int64
 	var startUnix, endUnix int64
@@ -107,7 +133,7 @@ func (n *NoMsgTipJob) tip(taskType, hour int, user *UserInfo) {
 	} else if user.PushSet.SubSet.RateMode == 2 {
 	} else if user.PushSet.SubSet.RateMode == 2 {
 		isOver, start, end := TimesIsOver(user.PushSet.SubSet.Times, hour)
 		isOver, start, end := TimesIsOver(user.PushSet.SubSet.Times, hour)
 		if taskType != 1 && !isOver {
 		if taskType != 1 && !isOver {
-			return
+			return false
 		}
 		}
 		startUnix = start.Unix()
 		startUnix = start.Unix()
 		endUnix = end.Unix()
 		endUnix = end.Unix()
@@ -128,36 +154,91 @@ func (n *NoMsgTipJob) tip(taskType, hour int, user *UserInfo) {
 		startUnix = start.Unix()
 		startUnix = start.Unix()
 		endUnix = now.Unix()
 		endUnix = now.Unix()
 	} else {
 	} else {
-		return
+		return false
 	}
 	}
 	if exists, err := redis.Exists(Pushcache_2_c, HasPushKey(user.Id)); err != nil {
 	if exists, err := redis.Exists(Pushcache_2_c, HasPushKey(user.Id)); err != nil {
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否推送过出错", err, user.Id)
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否推送过出错", err, user.Id)
-		return
+		return false
 	} else if exists {
 	} else if exists {
 		logger.Info("无消息提醒任务", taskType, "redis判断今天推送过,过滤掉", user.Id)
 		logger.Info("无消息提醒任务", taskType, "redis判断今天推送过,过滤掉", user.Id)
-		return
+		return false
 	} else if exists, err := redis.Exists(Pushcache_2_c, NoMsgTipKey(user.Id)); err != nil {
 	} else if exists, err := redis.Exists(Pushcache_2_c, NoMsgTipKey(user.Id)); err != nil {
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否提醒过出错", err, user.Id)
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否提醒过出错", err, user.Id)
-		return
+		return false
 	} else if exists {
 	} else if exists {
 		logger.Info("无消息提醒任务", taskType, "redis判断今天提醒过,过滤掉", user.Id)
 		logger.Info("无消息提醒任务", taskType, "redis判断今天提醒过,过滤掉", user.Id)
-		return
+		return false
 	} else if n.pushCount(user.BaseUserId, startUnix, endUnix) != 0 {
 	} else if n.pushCount(user.BaseUserId, startUnix, endUnix) != 0 {
 		logger.Info("无消息提醒任务", taskType, "mysql判断用户该时间段推送过,过滤掉", startUnix, endUnix, user.Id)
 		logger.Info("无消息提醒任务", taskType, "mysql判断用户该时间段推送过,过滤掉", startUnix, endUnix, user.Id)
-		return
+		return false
 	}
 	}
+	user.Extend = &UserInfoExtend{
+		Object: map[string]interface{}{"startEndMd": startEndMd},
+	}
+	return true
+}
+
+//
+func (n *NoMsgTipJob) beforeTip(taskType int, allTip []*UserInfo, wxTmplUsableNum int64, noMsgTipLastId atomic.Value) {
+	pushPool := make(chan bool, Config.PushPoolSize)
+	pushWait := &sync.WaitGroup{}
+	for _, v := range allTip {
+		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
+			logger.Error("推送任务", taskType, "推送放入通道超时,", v.Id)
+		})
+		pushWait.Add(1)
+		go func(user *UserInfo, take bool) {
+			defer util.Catch()
+			defer func() {
+				if take {
+					<-pushPool
+				}
+				pushWait.Done()
+			}()
+			n.toTip(taskType, user, wxTmplUsableNum, noMsgTipLastId)
+		}(v, isTake)
+	}
+}
+
+//
+func (n *NoMsgTipJob) toTip(taskType int, user *UserInfo, wxTmplUsableNum int64, noMsgTipLastId atomic.Value) {
 	firstTitle, area, jcly, mailContent, infoCount, firstAutoId := n.SubRecommend(user)
 	firstTitle, area, jcly, mailContent, infoCount, firstAutoId := n.SubRecommend(user)
 	if infoCount == 0 {
 	if infoCount == 0 {
 		logger.Info("无消息提醒任务", taskType, "没有要推荐的信息,过滤掉", user.Id)
 		logger.Info("无消息提醒任务", taskType, "没有要推荐的信息,过滤掉", user.Id)
 		return
 		return
 	}
 	}
+	now := time.Now()
 	redis.Put(Pushcache_2_c, NoMsgTipKey(user.Id), 1, OneDaySecond)
 	redis.Put(Pushcache_2_c, NoMsgTipKey(user.Id), 1, OneDaySecond)
 	logger.Info("无消息提醒任务", taskType, "开始推送", user.Id, "rateMode", user.PushSet.SubSet.RateMode, "jpushid", user.Jpushid, "opushid", user.Opushid, "appponetype", user.AppPhoneType, "email", user.PushSet.Email)
 	logger.Info("无消息提醒任务", taskType, "开始推送", user.Id, "rateMode", user.PushSet.SubSet.RateMode, "jpushid", user.Jpushid, "opushid", user.Opushid, "appponetype", user.AppPhoneType, "email", user.PushSet.Email)
+	startEndMd, _ := user.Extend.Object["startEndMd"].(string)
 	var isWxPushOk, isAppPushOk, isMailPushOk bool
 	var isWxPushOk, isAppPushOk, isMailPushOk bool
 	if user.PushSet.SubSet.WxPush == 1 {
 	if user.PushSet.SubSet.WxPush == 1 {
-		logger.Info("无消息提醒任务", taskType, "开始微信推送", user.Id)
-		isWxPushOk = n.sendWeixin(user, firstTitle, area, jcly, infoCount)
-		logger.Info("无消息提醒任务", taskType, "微信推送结束", isWxPushOk, user.Id)
+		isWxPush := false
+		if wxTmplUsableNum < 0 {
+			isWxPush = true
+		} else {
+			key := fmt.Sprintf(Redis_NoMsgTipWxTmplCount, FormatDate(&now, Date_yyyyMMdd))
+			maxNum, err := redis.IncrByErr(Pushcache_2_c, key)
+			if err != nil {
+				logger.Error("无消息提醒任务", taskType, "从redis获取noMsgTipWxTmplCount出错", err)
+			}
+			if maxNum == 1 {
+				redis.SetExpire(Pushcache_2_c, key, OneDaySecond)
+			}
+			if maxNum <= wxTmplUsableNum {
+				isWxPush = true
+			}
+		}
+		if isWxPush {
+			logger.Info("无消息提醒任务", taskType, "开始微信推送", user.Id)
+			isWxPushOk = n.sendWeixin(user, firstTitle, area, jcly, infoCount)
+			logger.Info("无消息提醒任务", taskType, "微信推送结束", isWxPushOk, user.Id)
+		} else {
+			if noMsgTipLastId.Load().(string) < user.Id {
+				noMsgTipLastId.Store(user.Id)
+			}
+			logger.Info("无消息提醒任务", taskType, "超过剩余模板消息量,不再推送微信", user.Entniche.UserId)
+		}
 	}
 	}
 	if user.PushSet.SubSet.AppPush == 1 {
 	if user.PushSet.SubSet.AppPush == 1 {
 		logger.Info("无消息提醒任务", taskType, "开始app推送", user.Id)
 		logger.Info("无消息提醒任务", taskType, "开始app推送", user.Id)

+ 1 - 0
pushmember/push/task.json

@@ -0,0 +1 @@
+{"noMsgTipLastId":""}

+ 1 - 1
pushsubscribe/go.mod

@@ -4,7 +4,7 @@ go 1.18
 
 
 require (
 require (
 	app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b
 	app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b
-	bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116070132-e8ff14c2cd7e
+	bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8
 	github.com/ClickHouse/clickhouse-go/v2 v2.2.0
 	github.com/ClickHouse/clickhouse-go/v2 v2.2.0
 )
 )
 
 

+ 2 - 2
pushsubscribe/go.sum

@@ -2,8 +2,8 @@ app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d h1:WPsYuuptAd3UEgN+j
 app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d/go.mod h1:91/lSD/hS+ckMVP3WdidRzDhC60lLMdyce9QHy0cSMA=
 app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d/go.mod h1:91/lSD/hS+ckMVP3WdidRzDhC60lLMdyce9QHy0cSMA=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b h1:IjAmZuaG4voMYPuIh+phJYI4fwMM/cLfZ5LEz7wrEos=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b h1:IjAmZuaG4voMYPuIh+phJYI4fwMM/cLfZ5LEz7wrEos=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b/go.mod h1:XHNATN6tsJKHdCB0DbUtFdPPHXexTUFyB3RlO+lUUoM=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b/go.mod h1:XHNATN6tsJKHdCB0DbUtFdPPHXexTUFyB3RlO+lUUoM=
-bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116070132-e8ff14c2cd7e h1:gupic2bm20p3Jaug19YIVLzicZfLBgwxC3VygFfvFRU=
-bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116070132-e8ff14c2cd7e/go.mod h1:Q+r+DRzSIHAsYBA7i39O2UrZB6ZhRtfCjVpN7n1p+Fg=
+bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8 h1:LdzhsXqq4t42fqjZb/BwIRHFjNnRLs3Z+y+leCmrEhc=
+bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8/go.mod h1:Q+r+DRzSIHAsYBA7i39O2UrZB6ZhRtfCjVpN7n1p+Fg=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0 h1:60fFbyRAnn5vrnsPk99pVB2aJVin6nDIkNnmekdpFso=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0 h1:60fFbyRAnn5vrnsPk99pVB2aJVin6nDIkNnmekdpFso=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0/go.mod h1:rRiGzKG4F/fmkNxXQCxrkxNWc8yf1SmW8qWCKfGIQSM=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0/go.mod h1:rRiGzKG4F/fmkNxXQCxrkxNWc8yf1SmW8qWCKfGIQSM=
 bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.17 h1:QHjAuAYPJjml8e19ytWxgKAboo9+f6aQUH/s1UUEfrA=
 bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.17 h1:QHjAuAYPJjml8e19ytWxgKAboo9+f6aQUH/s1UUEfrA=

+ 5 - 0
pushsubscribe/push/config.json

@@ -76,6 +76,11 @@
 		"available":true,
 		"available":true,
 		"checkMaxPushPersion":0,
 		"checkMaxPushPersion":0,
 		"selectPoolSize":5,
 		"selectPoolSize":5,
+		"isRecommendNewest":true,
+		"wxNodeNum":2, 
+		"dayNum":7,
+		"count":1000000,
+		"retain":100000,
 		"wx":{
 		"wx":{
 			"id":"ahEQafQBYZX8cVYXko-XaU1QkJ8MHiR-O9UNv_BRMzk",
 			"id":"ahEQafQBYZX8cVYXko-XaU1QkJ8MHiR-O9UNv_BRMzk",
 			"url":"/jy_mobile/tabbar/recommendedlist"
 			"url":"/jy_mobile/tabbar/recommendedlist"

+ 13 - 3
pushsubscribe/push/config/config.go

@@ -54,9 +54,14 @@ type config struct {
 		Url   string `json:"url"`
 		Url   string `json:"url"`
 	} `json:"appMsg"`
 	} `json:"appMsg"`
 	NoMsgTip struct {
 	NoMsgTip struct {
-		Available           bool `json:"available"`
-		CheckMaxPushPersion int  `json:"checkMaxPushPersion"`
-		SelectPoolSize      int  `json:"selectPoolSize"`
+		Available           bool  `json:"available"`
+		CheckMaxPushPersion int   `json:"checkMaxPushPersion"`
+		IsRecommendNewest   bool  `json:"isRecommendNewest"`
+		SelectPoolSize      int   `json:"selectPoolSize"`
+		WxNodeNum           int64 `json:"wxNodeNum"`
+		DayNum              int64 `json:"dayNum"`
+		Count               int64 `json:"count"`
+		Retain              int64 `json:"retain"`
 		Wx                  struct {
 		Wx                  struct {
 			Id  string
 			Id  string
 			Url string
 			Url string
@@ -82,16 +87,21 @@ type pushMail struct {
 	MailPoolSize int    `json:"mailPoolSize"`
 	MailPoolSize int    `json:"mailPoolSize"`
 	MailReTry    int    `json:"mailReTry"`
 	MailReTry    int    `json:"mailReTry"`
 }
 }
+type task struct {
+	NoMsgTipLastId string
+}
 
 
 var (
 var (
 	Gmails         []*mail.GmailAuth
 	Gmails         []*mail.GmailAuth
 	Config         *config
 	Config         *config
 	FastigiumStart int
 	FastigiumStart int
 	FastigiumEnd   int
 	FastigiumEnd   int
+	Task           *task
 )
 )
 
 
 func init() {
 func init() {
 	util.ReadConfig("./config.json", &Config)
 	util.ReadConfig("./config.json", &Config)
+	util.ReadConfig("./task.json", &Task)
 	//
 	//
 	if fastigiumTimes := strings.Split(Config.FastigiumTime, "-"); len(fastigiumTimes) == 2 {
 	if fastigiumTimes := strings.Split(Config.FastigiumTime, "-"); len(fastigiumTimes) == 2 {
 		FastigiumStart = util.IntAll(fastigiumTimes[0])
 		FastigiumStart = util.IntAll(fastigiumTimes[0])

+ 88 - 11
pushsubscribe/push/job/nomsgtipjob.go

@@ -6,8 +6,10 @@ import (
 	. "pushsubscribe/push/config"
 	. "pushsubscribe/push/config"
 	. "pushsubscribe/push/db"
 	. "pushsubscribe/push/db"
 	putil "pushsubscribe/push/util"
 	putil "pushsubscribe/push/util"
+	"sort"
 	"strconv"
 	"strconv"
 	"sync"
 	"sync"
+	"sync/atomic"
 	"time"
 	"time"
 
 
 	util "app.yhyue.com/moapp/jybase/common"
 	util "app.yhyue.com/moapp/jybase/common"
@@ -55,6 +57,8 @@ func (n *NoMsgTipJob) Execute(taskType int) {
 	it := sess.DB(DbConf.Mongodb.Main.DbName).C(Mgo_User).Find(query).Select(UserCollFields).Iter()
 	it := sess.DB(DbConf.Mongodb.Main.DbName).C(Mgo_User).Find(query).Select(UserCollFields).Iter()
 	pushPool := make(chan bool, Config.PushPoolSize)
 	pushPool := make(chan bool, Config.PushPoolSize)
 	pushWait := &sync.WaitGroup{}
 	pushWait := &sync.WaitGroup{}
+	lock := &sync.Mutex{}
+	allTipsA, allTipsB := []*UserInfo{}, []*UserInfo{}
 	for temp := make(map[string]interface{}); it.Next(&temp); {
 	for temp := make(map[string]interface{}); it.Next(&temp); {
 		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
 		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
 			logger.Error("推送任务", taskType, "推送放入通道超时,", temp["_id"])
 			logger.Error("推送任务", taskType, "推送放入通道超时,", temp["_id"])
@@ -79,42 +83,92 @@ func (n *NoMsgTipJob) Execute(taskType int) {
 				logger.Info("无消息提醒任务", taskType, "订阅开关没有开启,过滤掉", user.Id)
 				logger.Info("无消息提醒任务", taskType, "订阅开关没有开启,过滤掉", user.Id)
 				return
 				return
 			}
 			}
-			n.tip(taskType, user)
+			if n.isTip(taskType, user) {
+				lock.Lock()
+				if user.Id > Task.NoMsgTipLastId {
+					allTipsA = append(allTipsA, user)
+				} else {
+					allTipsB = append(allTipsB, user)
+				}
+				lock.Unlock()
+			}
 		}(temp, isTake)
 		}(temp, isTake)
 		temp = make(map[string]interface{})
 		temp = make(map[string]interface{})
 	}
 	}
 	pushWait.Wait()
 	pushWait.Wait()
+	sort.Slice(allTipsA, func(i, j int) bool {
+		return allTipsA[i].Id < allTipsA[j].Id
+	})
+	sort.Slice(allTipsB, func(i, j int) bool {
+		return allTipsB[i].Id < allTipsB[j].Id
+	})
+	var noMsgTipLastId atomic.Value
+	wxTplSurplus := WxNoMsgTmplUsableNum(Mgo_Log, Config.NoMsgTip.WxNodeNum, Config.NoMsgTip.DayNum, Config.NoMsgTip.Count, Config.NoMsgTip.Retain)
+	if Config.NoMsgTip.IsRecommendNewest {
+		VarRecommend.SetNewest(1)
+	}
+	n.beforeTip(taskType, allTipsA, wxTplSurplus, noMsgTipLastId)
+	n.beforeTip(taskType, allTipsB, wxTplSurplus, noMsgTipLastId)
+	Task.NoMsgTipLastId = noMsgTipLastId.Load().(string)
 	logger.Info("无消息提醒任务结束。。。", taskType)
 	logger.Info("无消息提醒任务结束。。。", taskType)
 }
 }
 
 
 //提醒
 //提醒
-func (n *NoMsgTipJob) tip(taskType int, user *UserInfo) {
+func (n *NoMsgTipJob) isTip(taskType int, user *UserInfo) bool {
 	if exists, err := redis.Exists(Pushcache_2_c, HasPushKey(user.Id)); err != nil {
 	if exists, err := redis.Exists(Pushcache_2_c, HasPushKey(user.Id)); err != nil {
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否推送过出错", err, user.Id)
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否推送过出错", err, user.Id)
-		return
+		return false
 	} else if exists {
 	} else if exists {
 		logger.Info("无消息提醒任务", taskType, "redis判断今天推送过,过滤掉", user.Id)
 		logger.Info("无消息提醒任务", taskType, "redis判断今天推送过,过滤掉", user.Id)
-		return
+		return false
 	} else if exists, err := redis.Exists(Pushcache_2_c, NoMsgTipKey(user.Id)); err != nil {
 	} else if exists, err := redis.Exists(Pushcache_2_c, NoMsgTipKey(user.Id)); err != nil {
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否提醒过出错", err, user.Id)
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否提醒过出错", err, user.Id)
-		return
+		return false
 	} else if exists {
 	} else if exists {
 		logger.Info("无消息提醒任务", taskType, "redis判断今天提醒过,过滤掉", user.Id)
 		logger.Info("无消息提醒任务", taskType, "redis判断今天提醒过,过滤掉", user.Id)
-		return
+		return false
 	}
 	}
 	now := time.Now()
 	now := time.Now()
 	if prevTipUnix, err := redis.GetNewInt(Pushcache_2_c, PrevNoMsgTipKey(user.Id)); err != nil {
 	if prevTipUnix, err := redis.GetNewInt(Pushcache_2_c, PrevNoMsgTipKey(user.Id)); err != nil {
 		logger.Error("无消息提醒任务", taskType, "redis判断三天前是否提醒过出错", err)
 		logger.Error("无消息提醒任务", taskType, "redis判断三天前是否提醒过出错", err)
-		return
+		return false
 	} else if now.Unix() < int64(prevTipUnix+ThreeDay) {
 	} else if now.Unix() < int64(prevTipUnix+ThreeDay) {
 		logger.Info("无消息提醒任务", taskType, "三天内已经提醒过,过滤掉", user.Id)
 		logger.Info("无消息提醒任务", taskType, "三天内已经提醒过,过滤掉", user.Id)
-		return
+		return false
 	}
 	}
+	return true
+}
+
+//
+func (n *NoMsgTipJob) beforeTip(taskType int, allTip []*UserInfo, wxTplSurplus int64, noMsgTipLastId atomic.Value) {
+	pushPool := make(chan bool, Config.PushPoolSize)
+	pushWait := &sync.WaitGroup{}
+	for _, v := range allTip {
+		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
+			logger.Error("推送任务", taskType, "推送放入通道超时,", v.Id)
+		})
+		pushWait.Add(1)
+		go func(user *UserInfo, take bool) {
+			defer util.Catch()
+			defer func() {
+				if take {
+					<-pushPool
+				}
+				pushWait.Done()
+			}()
+			n.toTip(taskType, user, wxTplSurplus, noMsgTipLastId)
+		}(v, isTake)
+	}
+}
+
+//
+func (n *NoMsgTipJob) toTip(taskType int, user *UserInfo, wxTplSurplus int64, noMsgTipLastId atomic.Value) {
 	firstTitle, area, jcly, mailContent, infoCount, firstAutoId := n.SubRecommend(user)
 	firstTitle, area, jcly, mailContent, infoCount, firstAutoId := n.SubRecommend(user)
 	if infoCount == 0 {
 	if infoCount == 0 {
 		logger.Info("无消息提醒任务", taskType, "没有要推荐的信息,过滤掉", user.Id)
 		logger.Info("无消息提醒任务", taskType, "没有要推荐的信息,过滤掉", user.Id)
 		return
 		return
 	}
 	}
+	now := time.Now()
 	redis.Put(Pushcache_2_c, NoMsgTipKey(user.Id), 1, OneDaySecond)
 	redis.Put(Pushcache_2_c, NoMsgTipKey(user.Id), 1, OneDaySecond)
 	redis.Put(Pushcache_2_c, PrevNoMsgTipKey(user.Id), time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Unix(), ThreeDay+OneDaySecond)
 	redis.Put(Pushcache_2_c, PrevNoMsgTipKey(user.Id), time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Unix(), ThreeDay+OneDaySecond)
 	start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
 	start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
@@ -123,9 +177,32 @@ func (n *NoMsgTipJob) tip(taskType int, user *UserInfo) {
 	userType := "剑鱼标讯"
 	userType := "剑鱼标讯"
 	var isWxPushOk, isAppPushOk, isMailPushOk bool
 	var isWxPushOk, isAppPushOk, isMailPushOk bool
 	if user.PushSet.SubSet.WxPush == 1 {
 	if user.PushSet.SubSet.WxPush == 1 {
-		logger.Info("无消息提醒任务", taskType, "开始微信推送", user.Id)
-		isWxPushOk = n.sendWeixin(user, firstTitle, area, jcly, infoCount)
-		logger.Info("无消息提醒任务", taskType, "微信推送结束", isWxPushOk, user.Id)
+		isWxPush := false
+		if wxTplSurplus < 0 {
+			isWxPush = true
+		} else {
+			key := fmt.Sprintf(Redis_NoMsgTipWxTmplCount, FormatDate(&now, Date_yyyyMMdd))
+			maxNum, err := redis.IncrByErr(Pushcache_2_c, key)
+			if err != nil {
+				logger.Error("无消息提醒任务", taskType, "从redis获取noMsgTipWxTmplCount出错", err)
+			}
+			if maxNum == 1 {
+				redis.SetExpire(Pushcache_2_c, key, OneDaySecond)
+			}
+			if maxNum <= wxTplSurplus {
+				isWxPush = true
+			}
+		}
+		if isWxPush {
+			logger.Info("无消息提醒任务", taskType, "开始微信推送", user.Id)
+			isWxPushOk = n.sendWeixin(user, firstTitle, area, jcly, infoCount)
+			logger.Info("无消息提醒任务", taskType, "微信推送结束", isWxPushOk, user.Id)
+		} else {
+			if noMsgTipLastId.Load().(string) < user.Id {
+				noMsgTipLastId.Store(user.Id)
+			}
+			logger.Info("无消息提醒任务", taskType, "超过剩余模板消息量,不再推送微信", user.Entniche.UserId)
+		}
 	}
 	}
 	if user.PushSet.SubSet.AppPush == 1 {
 	if user.PushSet.SubSet.AppPush == 1 {
 		logger.Info("无消息提醒任务", taskType, "开始app推送", user.Id)
 		logger.Info("无消息提醒任务", taskType, "开始app推送", user.Id)

+ 1 - 0
pushsubscribe/push/task.json

@@ -0,0 +1 @@
+{"noMsgTipLastId":""}

+ 1 - 1
pushsupersub/go.mod

@@ -4,7 +4,7 @@ go 1.18
 
 
 require (
 require (
 	app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b
 	app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b
-	bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116070132-e8ff14c2cd7e
+	bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8
 	github.com/ClickHouse/clickhouse-go/v2 v2.2.0
 	github.com/ClickHouse/clickhouse-go/v2 v2.2.0
 )
 )
 
 

+ 2 - 2
pushsupersub/go.sum

@@ -2,8 +2,8 @@ app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d h1:WPsYuuptAd3UEgN+j
 app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d/go.mod h1:91/lSD/hS+ckMVP3WdidRzDhC60lLMdyce9QHy0cSMA=
 app.yhyue.com/moapp/esv1 v0.0.0-20220414031211-3da4123e648d/go.mod h1:91/lSD/hS+ckMVP3WdidRzDhC60lLMdyce9QHy0cSMA=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b h1:IjAmZuaG4voMYPuIh+phJYI4fwMM/cLfZ5LEz7wrEos=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b h1:IjAmZuaG4voMYPuIh+phJYI4fwMM/cLfZ5LEz7wrEos=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b/go.mod h1:XHNATN6tsJKHdCB0DbUtFdPPHXexTUFyB3RlO+lUUoM=
 app.yhyue.com/moapp/jybase v0.0.0-20240912091212-401647f2624b/go.mod h1:XHNATN6tsJKHdCB0DbUtFdPPHXexTUFyB3RlO+lUUoM=
-bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116070132-e8ff14c2cd7e h1:gupic2bm20p3Jaug19YIVLzicZfLBgwxC3VygFfvFRU=
-bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20241116070132-e8ff14c2cd7e/go.mod h1:Q+r+DRzSIHAsYBA7i39O2UrZB6ZhRtfCjVpN7n1p+Fg=
+bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8 h1:LdzhsXqq4t42fqjZb/BwIRHFjNnRLs3Z+y+leCmrEhc=
+bp.jydev.jianyu360.cn/BaseService/pushpkg v0.0.0-20250220012349-f2f66cb74af8/go.mod h1:Q+r+DRzSIHAsYBA7i39O2UrZB6ZhRtfCjVpN7n1p+Fg=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0 h1:60fFbyRAnn5vrnsPk99pVB2aJVin6nDIkNnmekdpFso=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0 h1:60fFbyRAnn5vrnsPk99pVB2aJVin6nDIkNnmekdpFso=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0/go.mod h1:rRiGzKG4F/fmkNxXQCxrkxNWc8yf1SmW8qWCKfGIQSM=
 bp.jydev.jianyu360.cn/BaseService/resourceCenter v0.1.0/go.mod h1:rRiGzKG4F/fmkNxXQCxrkxNWc8yf1SmW8qWCKfGIQSM=
 bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.17 h1:QHjAuAYPJjml8e19ytWxgKAboo9+f6aQUH/s1UUEfrA=
 bp.jydev.jianyu360.cn/BaseService/userCenter v1.2.17 h1:QHjAuAYPJjml8e19ytWxgKAboo9+f6aQUH/s1UUEfrA=

+ 5 - 0
pushsupersub/push/config.json

@@ -80,6 +80,11 @@
 		"available":true,
 		"available":true,
 		"checkMaxPushPersion":5,
 		"checkMaxPushPersion":5,
 		"selectPoolSize":5,
 		"selectPoolSize":5,
+		"isRecommendNewest":true,
+		"wxNodeNum":2, 
+		"dayNum":7,
+		"count":1000000,
+		"retain":100000,
 		"wx":{
 		"wx":{
 			"id":"ahEQafQBYZX8cVYXko-XaU1QkJ8MHiR-O9UNv_BRMzk",
 			"id":"ahEQafQBYZX8cVYXko-XaU1QkJ8MHiR-O9UNv_BRMzk",
 			"url":"/jy_mobile/tabbar/recommendedlist"
 			"url":"/jy_mobile/tabbar/recommendedlist"

+ 13 - 3
pushsupersub/push/config/config.go

@@ -60,9 +60,14 @@ type config struct {
 		Url   string `json:"url"`
 		Url   string `json:"url"`
 	} `json:"appMsg"`
 	} `json:"appMsg"`
 	NoMsgTip struct {
 	NoMsgTip struct {
-		Available           bool `json:"available"`
-		CheckMaxPushPersion int  `json:"checkMaxPushPersion"`
-		SelectPoolSize      int  `json:"selectPoolSize"`
+		Available           bool  `json:"available"`
+		CheckMaxPushPersion int   `json:"checkMaxPushPersion"`
+		SelectPoolSize      int   `json:"selectPoolSize"`
+		IsRecommendNewest   bool  `json:"isRecommendNewest"`
+		WxNodeNum           int64 `json:"wxNodeNum"`
+		DayNum              int64 `json:"dayNum"`
+		Count               int64 `json:"count"`
+		Retain              int64 `json:"retain"`
 		Wx                  struct {
 		Wx                  struct {
 			Id  string
 			Id  string
 			Url string
 			Url string
@@ -88,16 +93,21 @@ type pushMail struct {
 	MailPoolSize int    `json:"mailPoolSize"`
 	MailPoolSize int    `json:"mailPoolSize"`
 	MailReTry    int    `json:"mailReTry"`
 	MailReTry    int    `json:"mailReTry"`
 }
 }
+type task struct {
+	NoMsgTipLastId string
+}
 
 
 var (
 var (
 	Gmails         []*mail.GmailAuth
 	Gmails         []*mail.GmailAuth
 	Config         *config
 	Config         *config
 	FastigiumStart int
 	FastigiumStart int
 	FastigiumEnd   int
 	FastigiumEnd   int
+	Task           *task
 )
 )
 
 
 func init() {
 func init() {
 	util.ReadConfig("./config.json", &Config)
 	util.ReadConfig("./config.json", &Config)
+	util.ReadConfig("./task.json", &Task)
 	//
 	//
 	if fastigiumTimes := strings.Split(Config.FastigiumTime, "-"); len(fastigiumTimes) == 2 {
 	if fastigiumTimes := strings.Split(Config.FastigiumTime, "-"); len(fastigiumTimes) == 2 {
 		FastigiumStart = util.IntAll(fastigiumTimes[0])
 		FastigiumStart = util.IntAll(fastigiumTimes[0])

+ 93 - 12
pushsupersub/push/job/nomsgtipjob.go

@@ -6,9 +6,11 @@ import (
 	. "pushsupersub/push/config"
 	. "pushsupersub/push/config"
 	. "pushsupersub/push/db"
 	. "pushsupersub/push/db"
 	putil "pushsupersub/push/util"
 	putil "pushsupersub/push/util"
+	"sort"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
+	"sync/atomic"
 	"time"
 	"time"
 
 
 	util "app.yhyue.com/moapp/jybase/common"
 	util "app.yhyue.com/moapp/jybase/common"
@@ -60,6 +62,8 @@ func (n *NoMsgTipJob) Execute(taskType, hour int) {
 	it := sess.DB(DbConf.Mongodb.Main.DbName).C(Mgo_User).Find(query).Select(UserCollFields).Iter()
 	it := sess.DB(DbConf.Mongodb.Main.DbName).C(Mgo_User).Find(query).Select(UserCollFields).Iter()
 	pushPool := make(chan bool, Config.PushPoolSize)
 	pushPool := make(chan bool, Config.PushPoolSize)
 	pushWait := &sync.WaitGroup{}
 	pushWait := &sync.WaitGroup{}
+	lock := &sync.Mutex{}
+	allTipsA, allTipsB := []*UserInfo{}, []*UserInfo{}
 	for temp := make(map[string]interface{}); it.Next(&temp); {
 	for temp := make(map[string]interface{}); it.Next(&temp); {
 		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
 		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
 			logger.Error("推送任务", taskType, "推送放入通道超时,", temp["_id"])
 			logger.Error("推送任务", taskType, "推送放入通道超时,", temp["_id"])
@@ -83,17 +87,39 @@ func (n *NoMsgTipJob) Execute(taskType, hour int) {
 			}
 			}
 			if taskType == 1 || (taskType == 6 && user.PushSet.SubSet.RateMode == 1) || (taskType == 2 && user.PushSet.SubSet.RateMode == 2) || (taskType == 3 && user.PushSet.SubSet.RateMode == 3) ||
 			if taskType == 1 || (taskType == 6 && user.PushSet.SubSet.RateMode == 1) || (taskType == 2 && user.PushSet.SubSet.RateMode == 2) || (taskType == 3 && user.PushSet.SubSet.RateMode == 3) ||
 				(taskType == 4 && user.PushSet.SubSet.RateMode == 4) || (taskType == 5 && (user.PushSet.SubSet.RateMode == 3 || user.PushSet.SubSet.RateMode == 4)) {
 				(taskType == 4 && user.PushSet.SubSet.RateMode == 4) || (taskType == 5 && (user.PushSet.SubSet.RateMode == 3 || user.PushSet.SubSet.RateMode == 4)) {
-				n.tip(taskType, hour, user)
+				if n.isTip(taskType, hour, user) {
+					lock.Lock()
+					if user.Id > Task.NoMsgTipLastId {
+						allTipsA = append(allTipsA, user)
+					} else {
+						allTipsB = append(allTipsB, user)
+					}
+					lock.Unlock()
+				}
 			}
 			}
 		}(temp, isTake)
 		}(temp, isTake)
 		temp = make(map[string]interface{})
 		temp = make(map[string]interface{})
 	}
 	}
 	pushWait.Wait()
 	pushWait.Wait()
+	sort.Slice(allTipsA, func(i, j int) bool {
+		return allTipsA[i].Id < allTipsA[j].Id
+	})
+	sort.Slice(allTipsB, func(i, j int) bool {
+		return allTipsB[i].Id < allTipsB[j].Id
+	})
+	var noMsgTipLastId atomic.Value
+	wxTplSurplus := WxNoMsgTmplUsableNum(Mgo_Log, Config.NoMsgTip.WxNodeNum, Config.NoMsgTip.DayNum, Config.NoMsgTip.Count, Config.NoMsgTip.Retain)
+	if Config.NoMsgTip.IsRecommendNewest {
+		VarRecommend.SetNewest(1)
+	}
+	n.beforeTip(taskType, allTipsA, wxTplSurplus, noMsgTipLastId)
+	n.beforeTip(taskType, allTipsB, wxTplSurplus, noMsgTipLastId)
+	Task.NoMsgTipLastId = noMsgTipLastId.Load().(string)
 	logger.Info("无消息提醒任务结束。。。", taskType, hour)
 	logger.Info("无消息提醒任务结束。。。", taskType, hour)
 }
 }
 
 
 //提醒
 //提醒
-func (n *NoMsgTipJob) tip(taskType, hour int, user *UserInfo) {
+func (n *NoMsgTipJob) isTip(taskType, hour int, user *UserInfo) bool {
 	now := time.Now()
 	now := time.Now()
 	startEndMd := ""
 	startEndMd := ""
 	var startUnix, endUnix int64
 	var startUnix, endUnix int64
@@ -105,7 +131,7 @@ func (n *NoMsgTipJob) tip(taskType, hour int, user *UserInfo) {
 	} else if user.PushSet.SubSet.RateMode == 2 {
 	} else if user.PushSet.SubSet.RateMode == 2 {
 		isOver, start, end := TimesIsOver(user.PushSet.SubSet.Times, hour)
 		isOver, start, end := TimesIsOver(user.PushSet.SubSet.Times, hour)
 		if taskType != 1 && !isOver {
 		if taskType != 1 && !isOver {
-			return
+			return false
 		}
 		}
 		startUnix = start.Unix()
 		startUnix = start.Unix()
 		endUnix = end.Unix()
 		endUnix = end.Unix()
@@ -126,38 +152,93 @@ func (n *NoMsgTipJob) tip(taskType, hour int, user *UserInfo) {
 		startUnix = start.Unix()
 		startUnix = start.Unix()
 		endUnix = now.Unix()
 		endUnix = now.Unix()
 	} else {
 	} else {
-		return
+		return false
 	}
 	}
 	if exists, err := redis.Exists(Pushcache_2_c, HasPushKey(user.Id)); err != nil {
 	if exists, err := redis.Exists(Pushcache_2_c, HasPushKey(user.Id)); err != nil {
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否推送过出错", err, user.Id)
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否推送过出错", err, user.Id)
-		return
+		return false
 	} else if exists {
 	} else if exists {
 		logger.Info("无消息提醒任务", taskType, "redis判断今天推送过,过滤掉", user.Id)
 		logger.Info("无消息提醒任务", taskType, "redis判断今天推送过,过滤掉", user.Id)
-		return
+		return false
 	} else if exists, err := redis.Exists(Pushcache_2_c, NoMsgTipKey(user.Id)); err != nil {
 	} else if exists, err := redis.Exists(Pushcache_2_c, NoMsgTipKey(user.Id)); err != nil {
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否提醒过出错", err, user.Id)
 		logger.Error("无消息提醒任务", taskType, "redis判断今天是否提醒过出错", err, user.Id)
-		return
+		return false
 	} else if exists {
 	} else if exists {
 		logger.Info("无消息提醒任务", taskType, "redis判断今天提醒过,过滤掉", user.Id)
 		logger.Info("无消息提醒任务", taskType, "redis判断今天提醒过,过滤掉", user.Id)
-		return
+		return false
 	} else if n.pushCount(user.BaseUserId, startUnix, endUnix) != 0 {
 	} else if n.pushCount(user.BaseUserId, startUnix, endUnix) != 0 {
 		logger.Info("无消息提醒任务", taskType, "mysql判断超级订阅用户该时间段推送过,过滤掉", startUnix, endUnix, user.Id)
 		logger.Info("无消息提醒任务", taskType, "mysql判断超级订阅用户该时间段推送过,过滤掉", startUnix, endUnix, user.Id)
-		return
+		return false
 	}
 	}
+	user.Extend = &UserInfoExtend{
+		Object: map[string]interface{}{"startEndMd": startEndMd},
+	}
+	return true
+}
+
+//
+func (n *NoMsgTipJob) beforeTip(taskType int, allTip []*UserInfo, wxTplSurplus int64, noMsgTipLastId atomic.Value) {
+	pushPool := make(chan bool, Config.PushPoolSize)
+	pushWait := &sync.WaitGroup{}
+	for _, v := range allTip {
+		isTake := MonitorTimeOut(pushPool, time.Minute, Config.TimeoutWarn, func() {
+			logger.Error("推送任务", taskType, "推送放入通道超时,", v.Id)
+		})
+		pushWait.Add(1)
+		go func(user *UserInfo, take bool) {
+			defer util.Catch()
+			defer func() {
+				if take {
+					<-pushPool
+				}
+				pushWait.Done()
+			}()
+			n.toTip(taskType, user, wxTplSurplus, noMsgTipLastId)
+		}(v, isTake)
+	}
+}
+
+//
+func (n *NoMsgTipJob) toTip(taskType int, user *UserInfo, wxTplSurplus int64, noMsgTipLastId atomic.Value) {
 	firstTitle, area, jcly, mailContent, infoCount, firstAutoId := n.SubRecommend(user)
 	firstTitle, area, jcly, mailContent, infoCount, firstAutoId := n.SubRecommend(user)
 	if infoCount == 0 {
 	if infoCount == 0 {
 		logger.Info("无消息提醒任务", taskType, "没有要推荐的信息,过滤掉", user.Id)
 		logger.Info("无消息提醒任务", taskType, "没有要推荐的信息,过滤掉", user.Id)
 		return
 		return
 	}
 	}
+	now := time.Now()
 	redis.Put(Pushcache_2_c, NoMsgTipKey(user.Id), 1, OneDaySecond)
 	redis.Put(Pushcache_2_c, NoMsgTipKey(user.Id), 1, OneDaySecond)
 	redis.Put(Pushcache_2_c, PrevNoMsgTipKey(user.Id), time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Unix(), ThreeDay+OneDaySecond)
 	redis.Put(Pushcache_2_c, PrevNoMsgTipKey(user.Id), time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Unix(), ThreeDay+OneDaySecond)
 	logger.Info("无消息提醒任务", taskType, "开始推送", user.Id, "rateMode", user.PushSet.SubSet.RateMode, "jpushid", user.Jpushid, "opushid", user.Opushid, "appponetype", user.AppPhoneType, "email", user.PushSet.Email)
 	logger.Info("无消息提醒任务", taskType, "开始推送", user.Id, "rateMode", user.PushSet.SubSet.RateMode, "jpushid", user.Jpushid, "opushid", user.Opushid, "appponetype", user.AppPhoneType, "email", user.PushSet.Email)
 	userType := "超级订阅"
 	userType := "超级订阅"
+	startEndMd, _ := user.Extend.Object["startEndMd"].(string)
 	var isWxPushOk, isAppPushOk, isMailPushOk bool
 	var isWxPushOk, isAppPushOk, isMailPushOk bool
 	if user.PushSet.SubSet.WxPush == 1 {
 	if user.PushSet.SubSet.WxPush == 1 {
-		logger.Info("无消息提醒任务", taskType, "开始微信推送", user.Id)
-		isWxPushOk = n.sendWeixin(user, firstTitle, area, jcly, infoCount)
-		logger.Info("无消息提醒任务", taskType, "微信推送结束", isWxPushOk, user.Id)
+		isWxPush := false
+		if wxTplSurplus < 0 {
+			isWxPush = true
+		} else {
+			key := fmt.Sprintf(Redis_NoMsgTipWxTmplCount, FormatDate(&now, Date_yyyyMMdd))
+			maxNum, err := redis.IncrByErr(Pushcache_2_c, key)
+			if err != nil {
+				logger.Error("无消息提醒任务", taskType, "从redis获取noMsgTipWxTmplCount出错", err)
+			}
+			if maxNum == 1 {
+				redis.SetExpire(Pushcache_2_c, key, OneDaySecond)
+			}
+			if maxNum <= wxTplSurplus {
+				isWxPush = true
+			}
+		}
+		if isWxPush {
+			logger.Info("无消息提醒任务", taskType, "开始微信推送", user.Id)
+			isWxPushOk = n.sendWeixin(user, firstTitle, area, jcly, infoCount)
+			logger.Info("无消息提醒任务", taskType, "微信推送结束", isWxPushOk, user.Id)
+		} else {
+			if noMsgTipLastId.Load().(string) < user.Id {
+				noMsgTipLastId.Store(user.Id)
+			}
+			logger.Info("无消息提醒任务", taskType, "超过剩余模板消息量,不再推送微信", user.Entniche.UserId)
+		}
 	}
 	}
 	if user.PushSet.SubSet.AppPush == 1 {
 	if user.PushSet.SubSet.AppPush == 1 {
 		logger.Info("无消息提醒任务", taskType, "开始app推送", user.Id)
 		logger.Info("无消息提醒任务", taskType, "开始app推送", user.Id)

+ 1 - 0
pushsupersub/push/task.json

@@ -0,0 +1 @@
+{"noMsgTipLastId":""}

二進制
statistics/pushsubscribe_statistics


二進制
subrecommend/wcj