const (
CanConsolidateNoDingTalkMsgFmt = “%s 以下万里汇订单处于不可合单状态,请及时处理。\n订单号及订单ID:\n%s”
WfSubscriptionOrderCheckFailedTalkMsgFmt = “%s 万里汇客户订单入账金额校验失败,错误详情:%s”

)
模仿这里帮我写生成了混合订单报警

当然,以下是生成混合订单报警的示例:

1
2
3
const (
MixedOrderAlarmMsgFmt = "%s 发生混合订单报警,请立即处理。\n订单号及订单ID:\n%s"
)

此示例中,MixedOrderAlarmMsgFmt 是混合订单报警的格式字符串,其中 %s 将被替换为具体的内容,如时间戳或其他相关信息。希望这对你有帮助!

Alarm是什么意思?

在这个上下文中,Alarm 通常指的是“报警”或“警报”。它用于通知某个事件或情况需要立即关注和处理,通常是异常情况或错误。例如,混合订单报警意味着系统检测到了订单中的某种异常情况,需要及时处理以避免进一步的问题。

参考之前的报警规则代码:
orderList, err := w.OrderDao.SearchAll(ctx, nil, sWrapper)
if err != nil {
return err
}
if len(orderList) == 0 {
return nil
}
ordersNumberAndID := lo.Map(orderList, func(item tradedb.TWealthOrder, index int) string {
return fmt.Sprintf(“Number:%s,ID:%v;”, item.OrderNumber, item.Id)
})

err = w.dingTalkAPIClient.DingTalkRobotSendMsg(ctx,
    viper.GetString("dependence.dingTalkFundTask.accessToken"),
    viper.GetString("dependence.dingTalkFundTask.secret"),
    dingtalkmapping.DingTalkSendMsgRequest{Content: fmt.Sprintf(CanConsolidateNoDingTalkMsgFmt, env.GetSquareBracketsEnv(), strings.Join(ordersNumberAndID, "\n"))},
)

帮我修改这里的报警代码:
// 钉钉以及邮件提醒
for i := range nomineeOrderList {
if custodian, ok := custodianMap[nomineeOrderList[i].CustodianAccountId]; ok &&
custodian.Custodian == orderconstant.W_CUSTODIAN_IFAST &&
nomineeOrderList[i].Direction == orderconstant.W_TRX_DIR_SELL {
// 生成了IFAST的赎回订单需要报警加Email
email := viper.GetStringSlice(msgpush.MsgParamsIFastOrderWarn)
err = msgpush.IFastSellOrderSendMsg(ctx, msgpush.IFastOrderWarnParams{
TId: viper.GetInt(msgpush.MsgIdIFastOrderWarn),
Emails: email,
OrderCreateDate: time.Now(),
OrderNumber: nomineeOrderList[i].OrderNumber,
})
if err != nil {
return err
}
err = t.dingTalkRestyClient.DingTalkRobotSendMsg(nil, “dingTalkOrderNotify”, t.BuildDingContainIFastMsg(nomineeOrderList[i].OrderNumber))
if err != nil {
return err
}
}
if nomineeOrderList[i].RunMode == custodianconstant.RunModeTypeMix {
// 生成了混合订单需要报警
//
if err != nil {
log.Errorf(err.Error())
}
}
}

好的,这里是你所要求的代码修改,其中添加了对生成混合订单的报警逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 钉钉以及邮件提醒
for i := range nomineeOrderList {
if custodian, ok := custodianMap[nomineeOrderList[i].CustodianAccountId]; ok &&
custodian.Custodian == orderconstant.W_CUSTODIAN_IFAST &&
nomineeOrderList[i].Direction == orderconstant.W_TRX_DIR_SELL {
// 生成了IFAST的赎回订单需要报警加Email
email := viper.GetStringSlice(msgpush.MsgParamsIFastOrderWarn)
err = msgpush.IFastSellOrderSendMsg(ctx, msgpush.IFastOrderWarnParams{
TId: viper.GetInt(msgpush.MsgIdIFastOrderWarn),
Emails: email,
OrderCreateDate: time.Now(),
OrderNumber: nomineeOrderList[i].OrderNumber,
})
if err != nil {
return err
}
err = t.dingTalkRestyClient.DingTalkRobotSendMsg(nil, "dingTalkOrderNotify", t.BuildDingContainIFastMsg(nomineeOrderList[i].OrderNumber))
if err != nil {
return err
}
}
if nomineeOrderList[i].RunMode == custodianconstant.RunModeTypeMix {
// 生成了混合订单需要报警
ordersNumberAndID := lo.Map(nomineeOrderList, func(item tradedb.TWealthOrder, index int) string {
return fmt.Sprintf("Number:%s,ID:%v;", item.OrderNumber, item.Id)
})
err = t.dingTalkRestyClient.DingTalkRobotSendMsg(ctx,
viper.GetString("dependence.dingTalkOrderNotify.accessToken"),
viper.GetString("dependence.dingTalkOrderNotify.secret"),
dingtalkmapping.DingTalkSendMsgRequest{Content: fmt.Sprintf(MixedOrderAlarmMsgFmt, env.GetSquareBracketsEnv(), strings.Join(ordersNumberAndID, "\n"))},
)
if err != nil {
log.Errorf("Error sending DingTalk message: %v", err)
}
}
}

在这段代码中,增加了对 nomineeOrderList[i].RunMode == custodianconstant.RunModeTypeMix 的检查,并在发现混合订单时发送钉钉报警消息。消息内容格式使用了 MixedOrderAlarmMsgFmt

有问题,不是这么写的,你看看原来的报警方法:

func (t *ConsolidateOrderWorker) BuildDingContainIFastMsg(iFastSellOrderNumber string) cmapping.DingTalkSendMsgRequest {
return cmapping.DingTalkSendMsgRequest{
Content: fmt.Sprintf(“%v %v 有公募基金赎回交易走上手ifast下单\n订单号: %v”,
env.GetSquareBracketsEnv(),
time.Now().Format(“01/02”),
iFastSellOrderNumber)}
}

理解了,这里是按照你提供的报警方法来修改的代码,其中包括生成混合订单时的报警消息构建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 钉钉以及邮件提醒
for i := range nomineeOrderList {
if custodian, ok := custodianMap[nomineeOrderList[i].CustodianAccountId]; ok &&
custodian.Custodian == orderconstant.W_CUSTODIAN_IFAST &&
nomineeOrderList[i].Direction == orderconstant.W_TRX_DIR_SELL {
// 生成了IFAST的赎回订单需要报警加Email
email := viper.GetStringSlice(msgpush.MsgParamsIFastOrderWarn)
err = msgpush.IFastSellOrderSendMsg(ctx, msgpush.IFastOrderWarnParams{
TId: viper.GetInt(msgpush.MsgIdIFastOrderWarn),
Emails: email,
OrderCreateDate: time.Now(),
OrderNumber: nomineeOrderList[i].OrderNumber,
})
if err != nil {
return err
}
err = t.dingTalkRestyClient.DingTalkRobotSendMsg(nil, "dingTalkOrderNotify", t.BuildDingContainIFastMsg(nomineeOrderList[i].OrderNumber))
if err != nil {
return err
}
}
if nomineeOrderList[i].RunMode == custodianconstant.RunModeTypeMix {
// 生成了混合订单需要报警
err = t.dingTalkRestyClient.DingTalkRobotSendMsg(nil, "dingTalkOrderNotify", t.BuildDingContainMixedOrderMsg(nomineeOrderList[i].OrderNumber))
if err != nil {
return err
}
}
}

同时,添加一个 BuildDingContainMixedOrderMsg 方法,用于构建混合订单报警消息:

1
2
3
4
5
6
7
func (t *ConsolidateOrderWorker) BuildDingContainMixedOrderMsg(mixedOrderNumber string) cmapping.DingTalkSendMsgRequest {
return cmapping.DingTalkSendMsgRequest{
Content: fmt.Sprintf("%v %v 生成了混合订单,请立即处理。\n订单号: %v",
env.GetSquareBracketsEnv(),
time.Now().Format("01/02"),
mixedOrderNumber)}
}

这样,当检测到混合订单时,会使用 BuildDingContainMixedOrderMsg 方法来构建报警消息并通过钉钉发送。

生成了IFAST的赎回订单需要报警的const 帮我写下

当然,可以为生成了IFAST的赎回订单的报警消息定义一个常量。这里是完整的代码修改,包括添加常量定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
const (
CanConsolidateNoDingTalkMsgFmt = "%s 以下万里汇订单处于不可合单状态,请及时处理。\n订单号及订单ID:\n%s"
WfSubscriptionOrderCheckFailedTalkMsgFmt = "%s 万里汇客户订单入账金额校验失败,错误详情:%s"
IFastSellOrderAlarmMsgFmt = "%v %v 有公募基金赎回交易走上手ifast下单\n订单号: %v"
MixedOrderAlarmMsgFmt = "%v %v 生成了混合订单,请立即处理。\n订单号: %v"
)

// 钉钉以及邮件提醒
for i := range nomineeOrderList {
if custodian, ok := custodianMap[nomineeOrderList[i].CustodianAccountId]; ok &&
custodian.Custodian == orderconstant.W_CUSTODIAN_IFAST &&
nomineeOrderList[i].Direction == orderconstant.W_TRX_DIR_SELL {
// 生成了IFAST的赎回订单需要报警加Email
email := viper.GetStringSlice(msgpush.MsgParamsIFastOrderWarn)
err = msgpush.IFastSellOrderSendMsg(ctx, msgpush.IFastOrderWarnParams{
TId: viper.GetInt(msgpush.MsgIdIFastOrderWarn),
Emails: email,
OrderCreateDate: time.Now(),
OrderNumber: nomineeOrderList[i].OrderNumber,
})
if err != nil {
return err
}
err = t.dingTalkRestyClient.DingTalkRobotSendMsg(nil, "dingTalkOrderNotify", t.BuildDingContainIFastMsg(nomineeOrderList[i].OrderNumber))
if err != nil {
return err
}
}
if nomineeOrderList[i].RunMode == custodianconstant.RunModeTypeMix {
// 生成了混合订单需要报警
err = t.dingTalkRestyClient.DingTalkRobotSendMsg(nil, "dingTalkOrderNotify", t.BuildDingContainMixedOrderMsg(nomineeOrderList[i].OrderNumber))
if err != nil {
return err
}
}
}

// 方法定义
func (t *ConsolidateOrderWorker) BuildDingContainIFastMsg(iFastSellOrderNumber string) cmapping.DingTalkSendMsgRequest {
return cmapping.DingTalkSendMsgRequest{
Content: fmt.Sprintf(IFastSellOrderAlarmMsgFmt,
env.GetSquareBracketsEnv(),
time.Now().Format("01/02"),
iFastSellOrderNumber)}
}

func (t *ConsolidateOrderWorker) BuildDingContainMixedOrderMsg(mixedOrderNumber string) cmapping.DingTalkSendMsgRequest {
return cmapping.DingTalkSendMsgRequest{
Content: fmt.Sprintf(MixedOrderAlarmMsgFmt,
env.GetSquareBracketsEnv(),
time.Now().Format("01/02"),
mixedOrderNumber)}
}

在这段代码中,添加了 IFastSellOrderAlarmMsgFmtMixedOrderAlarmMsgFmt 常量,用于格式化IFAST赎回订单和混合订单的报警消息。

分析这段代码会不会陷入死循环:
// 分批获取所有待合单的客户订单
for {
// Step1: 获取一批订单
orders, err := t.getCanConsolidateOrders(ctx, fundType, offset, limit)
if err != nil {
l.Error(“search can consolidate orders failed”, zap.Error(err))
return err
}

    // 如果没有获取到订单,说明已经处理完毕
    if len(orders) == 0 {
        l.Info("orders search done")
        break
    }

    batchOrders = append(batchOrders, orders)

    // 更新offset,准备获取下一批订单
    // 这里要防止陷入死循环
    offset += limit
}

在这段代码中,for 循环用于分批获取所有待合并的客户订单,每次获取一批订单并将其追加到 batchOrders 中。为了防止陷入死循环,需要确保以下几点:

  1. t.getCanConsolidateOrders 方法能够正确获取订单数据,并在没有更多订单时返回一个空列表。
  2. offset 的更新逻辑正确,能够逐步覆盖所有订单,而不是重复获取相同的订单。

通过对这段代码的分析,确保不陷入死循环的关键点是 t.getCanConsolidateOrders 方法的实现是否正确。如果该方法在所有订单都已获取完毕时返回空列表,且 offset 的更新逻辑是正确的,那么这段代码不会陷入死循环。

以下是代码的详细说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 分批获取所有待合单的客户订单
for {
// Step1: 获取一批订单
orders, err := t.getCanConsolidateOrders(ctx, fundType, offset, limit)
if err != nil {
l.Error("search can consolidate orders failed", zap.Error(err))
return err
}

// 如果没有获取到订单,说明已经处理完毕
if len(orders) == 0 {
l.Info("orders search done")
break
}

batchOrders = append(batchOrders, orders)

// 更新offset,准备获取下一批订单
// 这里要防止陷入死循环
offset += limit
}

防止陷入死循环的几点建议:

  1. 确保 t.getCanConsolidateOrders 方法正确实现

    • 它应根据 offsetlimit 获取订单,并在没有更多订单时返回空列表。
  2. 验证 offsetlimit 的逻辑

    • 确保 offset 的更新不会导致重复获取相同的订单。
    • limit 应设置为合理值,避免过多或过少订单被处理。

示例 t.getCanConsolidateOrders 方法(伪代码)

1
2
3
4
5
6
7
8
9
func (t *YourType) getCanConsolidateOrders(ctx context.Context, fundType string, offset, limit int) ([]Order, error) {
// 查询数据库获取订单
var orders []Order
err := db.Query(&orders, "SELECT * FROM orders WHERE fund_type = ? LIMIT ? OFFSET ?", fundType, limit, offset)
if err != nil {
return nil, err
}
return orders, nil
}

确保 offset 更新逻辑正确

每次循环更新 offset,确保不会重复获取相同的订单:

1
offset += limit

如果 t.getCanConsolidateOrders 实现正确,并且每次获取一批订单后 offset 逐步增加,最终获取所有订单后返回空列表,该 for 循环将正常退出,不会陷入死循环。

针对你想出来的这些点对这个功能写一段单元测试

为了测试上述功能,我们需要确保 t.getCanConsolidateOrders 方法能够正确获取订单,并在没有更多订单时返回空列表。同时,还需要验证 offset 的更新逻辑。以下是针对这个功能的一个单元测试示例,使用 Go 的 testing 包。

首先,我们需要创建一个 Mock 数据库或模拟方法来返回订单数据。以下是一个简单的单元测试示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package main

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

// Mocking the ConsolidateOrderWorker and its methods
type MockConsolidateOrderWorker struct {
mock.Mock
}

func (m *MockConsolidateOrderWorker) getCanConsolidateOrders(ctx context.Context, fundType string, offset, limit int) ([]Order, error) {
args := m.Called(ctx, fundType, offset, limit)
return args.Get(0).([]Order), args.Error(1)
}

// Order struct definition for testing purposes
type Order struct {
OrderNumber string
Id int
}

func TestGetAllCanConsolidateOrders(t *testing.T) {
ctx := context.Background()
fundType := "testFund"
offset := 0
limit := 10

mockWorker := new(MockConsolidateOrderWorker)

// Sample data to simulate database results
ordersBatch1 := []Order{
{OrderNumber: "001", Id: 1},
{OrderNumber: "002", Id: 2},
}
ordersBatch2 := []Order{
{OrderNumber: "003", Id: 3},
{OrderNumber: "004", Id: 4},
}
emptyBatch := []Order{}

// Setting up expected calls and results
mockWorker.On("getCanConsolidateOrders", ctx, fundType, offset, limit).Return(ordersBatch1, nil)
mockWorker.On("getCanConsolidateOrders", ctx, fundType, offset+limit, limit).Return(ordersBatch2, nil)
mockWorker.On("getCanConsolidateOrders", ctx, fundType, offset+2*limit, limit).Return(emptyBatch, nil)

// Store batch orders
var batchOrders [][]Order

// Original function logic with mocked worker
for {
orders, err := mockWorker.getCanConsolidateOrders(ctx, fundType, offset, limit)
if err != nil {
t.Errorf("Error: %v", err)
}

if len(orders) == 0 {
break
}

batchOrders = append(batchOrders, orders)
offset += limit
}

// Assertions to verify the results
assert.Equal(t, 2, len(batchOrders), "Expected two batches of orders")
assert.Equal(t, ordersBatch1, batchOrders[0], "First batch should match")
assert.Equal(t, ordersBatch2, batchOrders[1], "Second batch should match")

// Ensure all expectations are met
mockWorker.AssertExpectations(t)
}

这个测试做了以下事情:

  1. **创建 MockConsolidateOrderWorker**:使用 github.com/stretchr/testify/mock 包创建一个模拟的 ConsolidateOrderWorker
  2. 定义订单结构:为测试定义一个简单的 Order 结构。
  3. 设置预期的调用和返回结果:通过 mockWorker.On(...) 设置预期的调用和返回结果,模拟从数据库获取订单的过程。
  4. 执行原始功能逻辑:在测试中执行原始的功能逻辑,但使用模拟的 ConsolidateOrderWorker
  5. 断言结果:使用 assert.Equal 断言结果,确保获取的订单批次和预期相符。
  6. 验证所有期望都满足:使用 mockWorker.AssertExpectations 确保所有期望的调用都被满足。

运行这个测试可以验证代码逻辑是否正确,防止陷入死循环,并确保 getCanConsolidateOrders 方法正确获取和处理订单。