- defsch调度器的timer添加条件函数ShouldSetTimer

- 饿百发三方需要在订单创建30分钟后才可以
This commit is contained in:
gazebo
2019-05-14 12:04:45 +08:00
parent 135563ea4d
commit 16c8aa018f
4 changed files with 100 additions and 51 deletions

View File

@@ -25,9 +25,10 @@ import (
)
const (
time2Delivered = 1 * time.Hour // 正常从下单到送达的时间。
minute2Schedule3rdCarrier = 20 // 收到平台方自有配送的新运单消息后等待创建三方配送运单的时间分钟如果是定时达会再根据ExpectedDeliveredTime与dingShiDaAheadTime做调整
minMinute2Schedule3rdCarrier = 5 // 转三方配送最少等待时间(分钟)
time2Delivered = 1 * time.Hour // 正常从下单到送达的时间。
minute2Schedule3rdCarrier = 20 // 收到平台方自有配送的新运单消息后等待创建三方配送运单的时间分钟如果是定时达会再根据ExpectedDeliveredTime与dingShiDaAheadTime做调整
minute2Schedule3rdCarrier4Ebai = 30 // 饿百的最少转自配送需要的时间(分钟)
minMinute2Schedule3rdCarrier = 5 // 转三方配送最少等待时间(分钟)
time2AutoPickupMin = 15 * time.Minute // 自动拣货等待时间这个只有在没有PickDeadline信息才有用否则会根据PickDeadline设置
second2AutoPickupGap = 60 //随机60秒
@@ -71,7 +72,15 @@ type WatchOrderInfo struct {
type StatusActionConfig struct {
partner.StatusActionParams
TimeoutAction func(savedOrderInfo *WatchOrderInfo) (err error) // 超时后需要执行的动作为nil表示此状态不需要执行监控 nil在GetStatusActionConfig返回时表示不修改缺省
TimeoutAction func(savedOrderInfo *WatchOrderInfo) (err error) // 超时后需要执行的动作为nil表示此状态不需要执行监控 nil在GetStatusActionConfig返回时表示不修改缺省
ShouldSetTimer func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool
}
func (c *StatusActionConfig) CallShouldSetTimer(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
if c.ShouldSetTimer != nil {
return c.ShouldSetTimer(savedOrderInfo, bill)
}
return true
}
// 重要:此调度器要求同一定单的处理逻辑必须是序列化了的,不然会有并发问题
@@ -164,6 +173,9 @@ func init() {
})
return nil
},
ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
return savedOrderInfo.order.Status == model.OrderStatusNew
},
},
model.OrderStatusAccepted: &StatusActionConfig{ // 自动拣货
StatusActionParams: partner.StatusActionParams{
@@ -177,6 +189,9 @@ func init() {
}
return nil
},
ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
return savedOrderInfo.autoPickupTimeoutMinute > 0
},
},
model.OrderStatusFinishedPickup: &StatusActionConfig{
StatusActionParams: partner.StatusActionParams{
@@ -190,6 +205,9 @@ func init() {
}
return nil
},
ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
return savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore
},
},
},
map[int]*StatusActionConfig{
@@ -205,6 +223,27 @@ func init() {
}
return nil
},
ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
return savedOrderInfo.storeDeliveryType != scheduler.StoreDeliveryTypeByStore && savedOrderInfo.order.VendorID != model.VendorIDEBAI
},
},
model.WaybillStatusCanceled: &StatusActionConfig{
StatusActionParams: partner.StatusActionParams{
TimerType: partner.TimerTypeBaseOrderCreatedAt,
Timeout: minute2Schedule3rdCarrier4Ebai * time.Minute,
},
TimeoutAction: func(savedOrderInfo *WatchOrderInfo) (err error) {
// 饿百转自送的时机不太清楚,暂时禁用超时转自送,在饿百运单取消时还是会自动创建
order := savedOrderInfo.order
if (order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) && savedOrderInfo.storeDeliveryType != scheduler.StoreDeliveryTypeByStore && order.VendorID == model.VendorIDEBAI { // 非自配送商家使用
return sch.createWaybillOn3rdProviders(savedOrderInfo, nil)
}
return nil
},
ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
order := savedOrderInfo.order
return (order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) && savedOrderInfo.storeDeliveryType != scheduler.StoreDeliveryTypeByStore && order.VendorID == model.VendorIDEBAI
},
},
},
}
@@ -429,7 +468,7 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo
// 之前的条件是order.Status < model.OrderStatusDelivering但像订单902322817000122确实有在配送中取消状态改成非订单结束状态都可以
// OrderStatusFinishedPickup状态的订单依赖于TIMER重新建运单
if bill.DeliveryFlag&model.WaybillDeliveryFlagMaskActiveCancel == 0 {
if order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin && (bill.WaybillVendorID != order.VendorID || order.VendorID == model.VendorIDEBAI) {
if (order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) && bill.WaybillVendorID != order.VendorID {
s.createWaybillOn3rdProviders(savedOrderInfo, nil)
}
}
@@ -468,12 +507,12 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo
weixinmsg.NotifyWaybillStatus(bill, order, false)
})
}
case model.WaybillStatusNeverSend: // 平台不配送,直接创建三方运单
s.resetTimer(savedOrderInfo, bill, isPending)
s.removeWaybillFromMap(savedOrderInfo, bill.WaybillVendorID)
if order.WaybillVendorID == model.VendorIDUnknown {
s.createWaybillOn3rdProviders(savedOrderInfo, nil)
}
// case model.WaybillStatusNeverSend: // 平台不配送,直接创建三方运单
// s.resetTimer(savedOrderInfo, bill, isPending)
// s.removeWaybillFromMap(savedOrderInfo, bill.WaybillVendorID)
// if order.WaybillVendorID == model.VendorIDUnknown {
// s.createWaybillOn3rdProviders(savedOrderInfo, nil)
// }
}
s.updateBillsInfo(savedOrderInfo, bill) // 更新可能的运单状态变化
}
@@ -660,38 +699,40 @@ func (s *DefScheduler) resetTimer(savedOrderInfo *WatchOrderInfo, bill *model.Wa
s.stopTimer(savedOrderInfo)
}
if config != nil && config.TimeoutAction != nil && config.TimerType != partner.TimerTypeByPass {
timeout := config.GetRefTimeout(statusTime)
if config.TimeoutGap != 0 {
timeout += time.Duration(rand.Intn(int(config.TimeoutGap))) * time.Second
}
if isPending && timeout < pendingOrderTimerMaxSecond*time.Second { // 如果是PENDING的订单则将其分布到2--5秒内让后续事件有机会执行
timeout = time.Duration(jxutils.MapValue2Scope(int64(timeout), -pendingOrderTimerMinMinSecond*1000, pendingOrderTimerMaxSecond*1000, pendingOrderTimerMinSecond*1000, pendingOrderTimerMaxSecond*1000)) * time.Millisecond
} else if timeout < 0 {
timeout = 0
}
if timeout == 0 {
config.TimeoutAction(savedOrderInfo)
} else {
timerName := ""
if statusType == scheduler.TimerStatusTypeOrder {
timerName = model.OrderStatusName[status]
} else if statusType == scheduler.TimerStatusTypeWaybill {
timerName = model.WaybillStatusName[status]
if config.CallShouldSetTimer(savedOrderInfo, bill) {
timeout := config.GetRefTimeout(statusTime, order.OrderCreatedAt)
if config.TimeoutGap != 0 {
timeout += time.Duration(rand.Intn(int(config.TimeoutGap))) * time.Second
}
savedOrderInfo.timerStatusType = statusType
savedOrderInfo.timerStatus = status
savedOrderInfo.timerTime = time.Now().Add(timeout)
savedOrderInfo.timer = utils.AfterFuncWithRecover(timeout, func() {
jxutils.CallMsgHandlerAsync(func() {
globals.SugarLogger.Debugf("fire timer:%s, orderID:%s", timerName, order.VendorOrderID)
savedOrderInfo := s.loadSavedOrderFromMap(model.Order2Status(order), true)
config.TimeoutAction(savedOrderInfo)
savedOrderInfo.timerStatus = 0
savedOrderInfo.timerStatusType = scheduler.TimerStatusTypeUnknown
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID))
})
if isPending && timeout < pendingOrderTimerMaxSecond*time.Second { // 如果是PENDING的订单则将其分布到2--5秒内让后续事件有机会执行
timeout = time.Duration(jxutils.MapValue2Scope(int64(timeout), -pendingOrderTimerMinMinSecond*1000, pendingOrderTimerMaxSecond*1000, pendingOrderTimerMinSecond*1000, pendingOrderTimerMaxSecond*1000)) * time.Millisecond
} else if timeout < 0 {
timeout = 0
}
if timeout == 0 {
config.TimeoutAction(savedOrderInfo)
} else {
timerName := ""
if statusType == scheduler.TimerStatusTypeOrder {
timerName = model.OrderStatusName[status]
} else if statusType == scheduler.TimerStatusTypeWaybill {
timerName = model.WaybillStatusName[status]
}
savedOrderInfo.timerStatusType = statusType
savedOrderInfo.timerStatus = status
savedOrderInfo.timerTime = time.Now().Add(timeout)
savedOrderInfo.timer = utils.AfterFuncWithRecover(timeout, func() {
jxutils.CallMsgHandlerAsync(func() {
globals.SugarLogger.Debugf("fire timer:%s, orderID:%s", timerName, order.VendorOrderID)
savedOrderInfo := s.loadSavedOrderFromMap(model.Order2Status(order), true)
config.TimeoutAction(savedOrderInfo)
savedOrderInfo.timerStatus = 0
savedOrderInfo.timerStatusType = scheduler.TimerStatusTypeUnknown
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID))
})
}
globals.SugarLogger.Debugf("resetTimer, orderID:%s, status:%d, timeout:%v", order.VendorOrderID, status, timeout)
}
globals.SugarLogger.Debugf("resetTimer, orderID:%s, status:%d, timeout:%v", order.VendorOrderID, status, timeout)
}
}
}
@@ -701,6 +742,9 @@ func isStatusNewer(curStatusType, curStatus, statusType, status int) bool {
if curStatusType == scheduler.TimerStatusTypeWaybill && statusType == scheduler.TimerStatusTypeOrder && status <= model.OrderStatusFinishedPickup {
return false
}
if curStatusType == scheduler.TimerStatusTypeWaybill {
return curStatus != status
}
return curStatusType != statusType || status >= curStatus
}
@@ -731,7 +775,7 @@ func (s *DefScheduler) mergeOrderStatusConfig(savedOrderInfo *WatchOrderInfo, st
TimeoutGap: -1,
}
timeout := statusTime.Sub(time.Now()) + minMinute2Schedule3rdCarrier*time.Minute
if vendorActionParams.GetRefTimeout(statusTime) < timeout { // 如果非立即达订单根据ExpectedDeliveredTime算出来的timeout太早
if vendorActionParams.GetRefTimeout(statusTime, order.OrderCreatedAt) < timeout { // 如果非立即达订单根据ExpectedDeliveredTime算出来的timeout太早
vendorActionParams.Timeout = timeout
vendorActionParams.TimeoutGap = 0
}

View File

@@ -278,7 +278,6 @@ const (
WaybillStatusDelivered = 105 // todo 这个应该改为110与订单对应
WaybillStatusCanceled = 115
WaybillStatusFailed = 120 // 这个状态存在的意义是区分于WaybillStatusCanceled比如达达平台在这种状态下再次创建运单的方式不一样
WaybillStatusNeverSend = 125 // 这个状态指的是平台方不愿意配送门店自己想办法。与WaybillStatusAcceptCanceled不一样WaybillStatusAcceptCanceled可能之后还会尝试配送
)
const (

View File

@@ -57,10 +57,11 @@ type PrinterStatus struct {
}
const (
TimerTypeNoOverride = 0 // GetStatusActionConfig 返回表示不修改缺省配置
TimerTypeByPass = 1
TimerTypeBaseNow = 2
TimerTypeBaseStatusTime = 3
TimerTypeNoOverride = 0 // GetStatusActionConfig 返回表示不修改缺省配置
TimerTypeByPass = 1
TimerTypeBaseNow = 2
TimerTypeBaseStatusTime = 3
TimerTypeBaseOrderCreatedAt = 4
)
type StatusActionParams struct {
@@ -86,15 +87,20 @@ type WaybillFeeInfo struct {
Waybill *model.Waybill `json:"waybill"`
}
func (s *StatusActionParams) GetRefTimeout(statusTime time.Time) (timeout time.Duration) {
func (s *StatusActionParams) GetRefTimeout(statusTime time.Time, orderCreatedAt time.Time) (timeout time.Duration) {
switch s.TimerType {
case TimerTypeBaseNow:
timeout = s.Timeout
case TimerTypeBaseStatusTime:
timeout = statusTime.Sub(time.Now()) + s.Timeout
case TimerTypeBaseOrderCreatedAt:
timeout = orderCreatedAt.Sub(time.Now()) + s.Timeout
default:
timeout = 0
}
if timeout < 0 {
timeout = 0
}
return timeout
}

View File

@@ -18,10 +18,10 @@ var (
ebaiapi.WaybillStatusCourierPickedup: model.WaybillStatusDelivering,
ebaiapi.WaybillStatusDeliveryCancled: model.WaybillStatusCanceled,
ebaiapi.WaybillStatusFinished: model.WaybillStatusDelivered,
ebaiapi.WaybillStatusExceptional: model.WaybillStatusUnknown,
ebaiapi.WaybillStatusExceptional: model.WaybillStatusCanceled,
ebaiapi.WaybillStatusSelfDelivery: model.WaybillStatusUnknown,
ebaiapi.WaybillStatusDontDeliver: model.WaybillStatusUnknown,
ebaiapi.WaybillStatusDeliveryRejected: model.WaybillStatusNeverSend,
ebaiapi.WaybillStatusDontDeliver: model.WaybillStatusCanceled,
ebaiapi.WaybillStatusDeliveryRejected: model.WaybillStatusCanceled,
}
)