- timer task shceuled to order goroutine to avoid concurrent problem.

This commit is contained in:
gazebo
2018-07-22 23:11:20 +08:00
parent 52ac5ca64a
commit ae214d38b9
10 changed files with 55 additions and 32 deletions

View File

@@ -5,7 +5,7 @@ import (
"time" "time"
"git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/routinepool" "git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/scheduler" "git.rosy.net.cn/jx-callback/business/scheduler"
_ "git.rosy.net.cn/jx-callback/business/scheduler/defsch" // 导入缺省订单调度器 _ "git.rosy.net.cn/jx-callback/business/scheduler/defsch" // 导入缺省订单调度器
@@ -20,11 +20,9 @@ const (
var ( var (
OrderManager *OrderController OrderManager *OrderController
WaybillManager *WaybillController WaybillManager *WaybillController
routinePool *routinepool.Pool
) )
func init() { func init() {
routinePool = routinepool.New(1000, 1000)
OrderManager = NewOrderManager() OrderManager = NewOrderManager()
WaybillManager = NewWaybillManager() WaybillManager = NewWaybillManager()
scheduler.CurrentScheduler.RegisterOrderManager(OrderManager) scheduler.CurrentScheduler.RegisterOrderManager(OrderManager)
@@ -51,13 +49,6 @@ func addOrderOrWaybillStatus(status *model.OrderStatus, db orm.Ormer) (isDuplica
return isDuplicated, err return isDuplicated, err
} }
func CallMsgHandler(handler func(), primaryID string) {
// handler()
routinePool.CallFun(func() {
handler()
}, primaryID)
}
func GetDataCityCodeFromOrder(order *model.GoodsOrder) (retVal string, err error) { func GetDataCityCodeFromOrder(order *model.GoodsOrder) (retVal string, err error) {
var sql string var sql string
if order.VendorID == model.VendorIDJD { if order.VendorID == model.VendorIDJD {
@@ -110,47 +101,47 @@ func LoadPendingOrders() {
orderNew := *order orderNew := *order
orderNew.Status = model.OrderStatusNew orderNew.Status = model.OrderStatusNew
orderNew.StatusTime = order.OrderCreatedAt orderNew.StatusTime = order.OrderCreatedAt
routinePool.CallFunAsync(func() { jxutils.CallMsgHandlerAsync(func() {
scheduler.CurrentScheduler.OnOrderNew(&orderNew) scheduler.CurrentScheduler.OnOrderNew(&orderNew)
}, order.VendorOrderID) }, order.VendorOrderID)
for _, bill := range billsMap[order.VendorOrderID] { for _, bill := range billsMap[order.VendorOrderID] {
if order.Status > model.OrderStatusNew && !isNoNewSent && order.StatusTime.Sub(bill.WaybillCreatedAt) < 0 { if order.Status > model.OrderStatusNew && !isNoNewSent && order.StatusTime.Sub(bill.WaybillCreatedAt) < 0 {
isNoNewSent = true isNoNewSent = true
order2 := *order order2 := *order
routinePool.CallFunAsync(func() { jxutils.CallMsgHandlerAsync(func() {
scheduler.CurrentScheduler.OnOrderStatusChanged(model.Order2Status(&order2)) scheduler.CurrentScheduler.OnOrderStatusChanged(model.Order2Status(&order2))
}, order.VendorOrderID) }, order.VendorOrderID)
} }
billNew := *bill billNew := *bill
billNew.Status = model.OrderStatusNew billNew.Status = model.OrderStatusNew
billNew.StatusTime = order.OrderCreatedAt billNew.StatusTime = order.OrderCreatedAt
routinePool.CallFunAsync(func() { jxutils.CallMsgHandlerAsync(func() {
scheduler.CurrentScheduler.OnWaybillStatusChanged(&billNew) scheduler.CurrentScheduler.OnWaybillStatusChanged(&billNew)
}, bill.VendorOrderID) }, bill.VendorOrderID)
if order.Status > model.OrderStatusNew && !isNoNewSent && order.StatusTime.Sub(bill.StatusTime) < 0 { if order.Status > model.OrderStatusNew && !isNoNewSent && order.StatusTime.Sub(bill.StatusTime) < 0 {
isNoNewSent = true isNoNewSent = true
order2 := *order order2 := *order
routinePool.CallFunAsync(func() { jxutils.CallMsgHandlerAsync(func() {
scheduler.CurrentScheduler.OnOrderStatusChanged(model.Order2Status(&order2)) scheduler.CurrentScheduler.OnOrderStatusChanged(model.Order2Status(&order2))
}, order.VendorOrderID) }, order.VendorOrderID)
} }
if bill.Status > model.WaybillStatusNew { if bill.Status > model.WaybillStatusNew {
bill2 := *bill bill2 := *bill
routinePool.CallFunAsync(func() { jxutils.CallMsgHandlerAsync(func() {
scheduler.CurrentScheduler.OnWaybillStatusChanged(&bill2) scheduler.CurrentScheduler.OnWaybillStatusChanged(&bill2)
}, bill.VendorOrderID) }, bill.VendorOrderID)
} }
if order.Status > model.OrderStatusNew && !isNoNewSent { if order.Status > model.OrderStatusNew && !isNoNewSent {
isNoNewSent = true isNoNewSent = true
order2 := *order order2 := *order
routinePool.CallFunAsync(func() { jxutils.CallMsgHandlerAsync(func() {
scheduler.CurrentScheduler.OnOrderStatusChanged(model.Order2Status(&order2)) scheduler.CurrentScheduler.OnOrderStatusChanged(model.Order2Status(&order2))
}, order.VendorOrderID) }, order.VendorOrderID)
} }
} }
if order.Status > model.OrderStatusNew && !isNoNewSent { if order.Status > model.OrderStatusNew && !isNoNewSent {
order2 := *order order2 := *order
routinePool.CallFunAsync(func() { jxutils.CallMsgHandlerAsync(func() {
scheduler.CurrentScheduler.OnOrderStatusChanged(model.Order2Status(&order2)) scheduler.CurrentScheduler.OnOrderStatusChanged(model.Order2Status(&order2))
}, order.VendorOrderID) }, order.VendorOrderID)
} }

View File

@@ -18,7 +18,7 @@ func init() {
} }
func (c *WaybillController) OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { func (c *WaybillController) OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) {
controller.CallMsgHandler(func() { jxutils.CallMsgHandler(func() {
retVal = c.onWaybillMsg(msg) retVal = c.onWaybillMsg(msg)
}, msg.OrderID) }, msg.OrderID)
return retVal return retVal

View File

@@ -3,7 +3,6 @@ package elm
import ( import (
"git.rosy.net.cn/baseapi/platformapi/elmapi" "git.rosy.net.cn/baseapi/platformapi/elmapi"
"git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/controller"
"git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model"
) )
@@ -46,7 +45,7 @@ func (c *Controller) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.Call
retVal = elmapi.Err2CallbackResponse(err, "") retVal = elmapi.Err2CallbackResponse(err, "")
} else { } else {
innerMsg.MsgType = msg.Type innerMsg.MsgType = msg.Type
controller.CallMsgHandler(func() { jxutils.CallMsgHandler(func() {
retVal = new(OrderController).onOrderUserUrgeOrder(&innerMsg) retVal = new(OrderController).onOrderUserUrgeOrder(&innerMsg)
}, jxutils.ComposeUniversalOrderID(innerMsg.OrderID, model.VendorIDELM)) }, jxutils.ComposeUniversalOrderID(innerMsg.OrderID, model.VendorIDELM))
} }

View File

@@ -43,21 +43,21 @@ func init() {
} }
func (c *OrderController) OnOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) { func (c *OrderController) OnOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) {
controller.CallMsgHandler(func() { jxutils.CallMsgHandler(func() {
retVal = c.onOrderStatusMsg(msg) retVal = c.onOrderStatusMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM)) }, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
return retVal return retVal
} }
func (c *OrderController) OnOrderNewMsg(msg map[string]interface{}) (retVal *elmapi.CallbackResponse) { func (c *OrderController) OnOrderNewMsg(msg map[string]interface{}) (retVal *elmapi.CallbackResponse) {
controller.CallMsgHandler(func() { jxutils.CallMsgHandler(func() {
retVal = c.onOrderNew(msg) retVal = c.onOrderNew(msg)
}, jxutils.ComposeUniversalOrderID(msg["orderId"].(string), model.VendorIDELM)) }, jxutils.ComposeUniversalOrderID(msg["orderId"].(string), model.VendorIDELM))
return retVal return retVal
} }
func (c *OrderController) OnOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) { func (c *OrderController) OnOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) {
controller.CallMsgHandler(func() { jxutils.CallMsgHandler(func() {
retVal = c.onOrderCancelRefundMsg(msg) retVal = c.onOrderCancelRefundMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM)) }, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
return retVal return retVal

View File

@@ -15,7 +15,7 @@ type WaybillController struct {
} }
func (c *WaybillController) OnWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { func (c *WaybillController) OnWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) {
controller.CallMsgHandler(func() { jxutils.CallMsgHandler(func() {
retVal = c.onWaybillStatusMsg(msg) retVal = c.onWaybillStatusMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM)) }, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
return retVal return retVal

View File

@@ -36,7 +36,7 @@ func init() {
} }
func (c *OrderController) OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { func (c *OrderController) OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
controller.CallMsgHandler(func() { jxutils.CallMsgHandler(func() {
retVal = c.onOrderMsg(msg) retVal = c.onOrderMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD)) }, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
return retVal return retVal

View File

@@ -13,7 +13,7 @@ type WaybillController struct {
} }
func (c *WaybillController) OnWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { func (c *WaybillController) OnWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) {
controller.CallMsgHandler(func() { jxutils.CallMsgHandler(func() {
retVal = c.onWaybillMsg(msg) retVal = c.onWaybillMsg(msg)
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDJD)) }, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDJD))
return retVal return retVal

View File

@@ -23,14 +23,14 @@ func init() {
} }
func (c *WaybillController) OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { func (c *WaybillController) OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) {
controller.CallMsgHandler(func() { jxutils.CallMsgHandler(func() {
retVal = c.onWaybillMsg(msg) retVal = c.onWaybillMsg(msg)
}, msg.OrderID) }, msg.OrderID)
return retVal return retVal
} }
func (c *WaybillController) OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) { func (c *WaybillController) OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) {
controller.CallMsgHandler(func() { jxutils.CallMsgHandler(func() {
order := &model.Waybill{ order := &model.Waybill{
VendorWaybillID: msg.MtPeisongID, VendorWaybillID: msg.MtPeisongID,
VendorWaybillID2: utils.Int64ToStr(msg.DeliveryID), VendorWaybillID2: utils.Int64ToStr(msg.DeliveryID),

View File

@@ -10,6 +10,7 @@ import (
"git.rosy.net.cn/baseapi/platformapi/autonavi" "git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/routinepool"
"git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals/api" "git.rosy.net.cn/jx-callback/globals/api"
) )
@@ -18,12 +19,17 @@ const (
DefaultOrderCacheTimeout = 24 * time.Hour DefaultOrderCacheTimeout = 24 * time.Hour
) )
var (
routinePool *routinepool.Pool
)
type SyncMapWithTimeout struct { type SyncMapWithTimeout struct {
sync.Map sync.Map
} }
func init() { func init() {
rand.Seed(time.Now().Unix()) rand.Seed(time.Now().Unix())
routinePool = routinepool.New(1000, 1000)
} }
func (m *SyncMapWithTimeout) StoreWithTimeout(key, value interface{}, timeout time.Duration) { func (m *SyncMapWithTimeout) StoreWithTimeout(key, value interface{}, timeout time.Duration) {
@@ -142,3 +148,15 @@ func StandardPrice2Int(value float64) int64 {
func IntPrice2StandardString(value int64) string { func IntPrice2StandardString(value int64) string {
return fmt.Sprintf("%.2f", IntPrice2Standard(value)) return fmt.Sprintf("%.2f", IntPrice2Standard(value))
} }
func CallMsgHandler(handler func(), primaryID string) {
routinePool.CallFun(func() {
handler()
}, primaryID)
}
func CallMsgHandlerAsync(handler func(), primaryID string) {
routinePool.CallFunAsync(func() {
handler()
}, primaryID)
}

View File

@@ -48,7 +48,18 @@ func init() {
Timeout: 1 * time.Second, Timeout: 1 * time.Second,
TimeoutAction: func(order *model.GoodsOrder) (err error) { TimeoutAction: func(order *model.GoodsOrder) (err error) {
_ = sch.handleAutoAcceptOrder(order.VendorOrderID, order.VendorID, order.ConsigneeMobile, jxutils.GetJxStoreIDFromOrder(order), nil, func(isAcceptIt bool) error { _ = sch.handleAutoAcceptOrder(order.VendorOrderID, order.VendorID, order.ConsigneeMobile, jxutils.GetJxStoreIDFromOrder(order), nil, func(isAcceptIt bool) error {
return sch.AcceptOrRefuseOrder(order, isAcceptIt) if err = sch.AcceptOrRefuseOrder(order, isAcceptIt); err != nil {
// 为了解决京东新消息与接单消息乱序的问题
if errWithCode, ok := err.(*utils.ErrorWithCode); ok && errWithCode.Level() == 1 && errWithCode.IntCode() == -1 {
if order2, err2 := sch.CurOrderManager.LoadOrder(order.VendorOrderID, order.VendorID); err2 == nil && order2.Status > order.Status {
sch.OnOrderStatusChanged(model.Order2Status(order2))
err = nil
} else {
err = err2
}
}
}
return err
}) })
return nil return nil
}, },
@@ -75,7 +86,7 @@ func (s *DefScheduler) OnOrderNew(order *model.GoodsOrder) (err error) {
order: order, order: order,
} }
s.orderMap.Store(jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), watchInfo) s.orderMap.Store(jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), watchInfo)
s.resetTimer(watchInfo, model.OrderStatusNew, order.OrderCreatedAt, 0) s.resetTimer(watchInfo, watchInfo.order.Status, order.OrderCreatedAt, 0)
return err return err
} }
@@ -301,9 +312,13 @@ func (s *DefScheduler) resetTimer(savedOrderInfo *WatchOrderInfo, status int, be
timeout := jxutils.GetRealTimeout(beginTime, config.Timeout, minTimeout) + gap timeout := jxutils.GetRealTimeout(beginTime, config.Timeout, minTimeout) + gap
globals.SugarLogger.Debugf("resetTimer timeout:%v, orderID:%s", timeout, savedOrderInfo.order.VendorOrderID) globals.SugarLogger.Debugf("resetTimer timeout:%v, orderID:%s", timeout, savedOrderInfo.order.VendorOrderID)
savedOrderInfo.timerStatus = status savedOrderInfo.timerStatus = status
order := savedOrderInfo.order
savedOrderInfo.timer = time.AfterFunc(timeout, func() { savedOrderInfo.timer = time.AfterFunc(timeout, func() {
config.TimeoutAction(savedOrderInfo.order) // order 事件序列化
savedOrderInfo.timerStatus = 0 // todo 可能有线程安全问题,考虑加入订单队列 jxutils.CallMsgHandlerAsync(func() {
config.TimeoutAction(order)
savedOrderInfo.timerStatus = 0
}, order.VendorOrderID)
}) })
} }
} else { } else {