feat: 实现发送质量监控与报备状态消息通知
CSS quality / css-quality (push) Has been cancelled

This commit is contained in:
hectorzhao
2026-09-06 19:22:49 +08:00
parent 69e3d7368d
commit 457319e627
66 changed files with 6992 additions and 489 deletions
+22 -16
View File
@@ -83,25 +83,31 @@ type Retry struct {
type SubmitResult struct {
Envelope
SubmitID string `json:"submitId"`
SequenceID uint32 `json:"sequenceId"`
GatewayMessageID string `json:"gatewayMessageId"`
SubmitStatus string `json:"submitStatus"`
ErrorCode string `json:"errorCode,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
SubmittedAt time.Time `json:"submittedAt"`
Segments []SubmitSegmentResult `json:"segments,omitempty"`
FirstWireSubmitAt *time.Time `json:"firstWireSubmitAt,omitempty"`
WireTimeSource string `json:"wireTimeSource,omitempty"`
ReceiptRequested bool `json:"receiptRequested"`
SubmitID string `json:"submitId"`
SequenceID uint32 `json:"sequenceId"`
GatewayMessageID string `json:"gatewayMessageId"`
SubmitStatus string `json:"submitStatus"`
ErrorCode string `json:"errorCode,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
SubmittedAt time.Time `json:"submittedAt"`
Segments []SubmitSegmentResult `json:"segments,omitempty"`
}
type SubmitSegmentResult struct {
SegmentTotal int `json:"segmentTotal"`
SegmentIndex int `json:"segmentIndex"`
SequenceID uint32 `json:"sequenceId"`
GatewayMessageID string `json:"gatewayMessageId"`
SubmitStatus string `json:"submitStatus"`
ErrorCode string `json:"errorCode,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
SubmittedAt time.Time `json:"submittedAt"`
FirstWireSubmitAt *time.Time `json:"firstWireSubmitAt,omitempty"`
WireTimeSource string `json:"wireTimeSource,omitempty"`
ReceiptRequested bool `json:"receiptRequested"`
SegmentTotal int `json:"segmentTotal"`
SegmentIndex int `json:"segmentIndex"`
SequenceID uint32 `json:"sequenceId"`
GatewayMessageID string `json:"gatewayMessageId"`
SubmitStatus string `json:"submitStatus"`
ErrorCode string `json:"errorCode,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
SubmittedAt time.Time `json:"submittedAt"`
}
type ReceiptEvent struct {
+32 -10
View File
@@ -40,7 +40,15 @@ func (p *connectionPool) submit(
ctx context.Context,
cmd queue.SubmitCommand,
onSegment func(queue.SubmitSegmentResult) error,
) (queue.SubmitResult, error) {
) (final queue.SubmitResult, finalErr error) {
defer func() {
for _, segment := range final.Segments {
if segment.FirstWireSubmitAt != nil && (final.FirstWireSubmitAt == nil || segment.FirstWireSubmitAt.Before(*final.FirstWireSubmitAt)) {
final.FirstWireSubmitAt = segment.FirstWireSubmitAt
final.WireTimeSource = "gateway_write_complete"
}
}
}()
parts, err := splitSubmitContent(cmd.CMPP.MsgFmt, cmd.Content)
if err != nil {
result := submitResult(cmd, 0, "", "rejected", "ENCODE_FAILED", err.Error())
@@ -96,7 +104,10 @@ func (p *connectionPool) submit(
return result, nil
}
func (c *connection) submitPart(ctx context.Context, cmd queue.SubmitCommand, part submitPart) (uint32, string, queue.SubmitResult, error) {
func (c *connection) submitPart(ctx context.Context, cmd queue.SubmitCommand, part submitPart) (finalSequence uint32, finalID string, final queue.SubmitResult, finalErr error) {
var wireAt *time.Time
wireSource := "not_written"
defer func() { final.FirstWireSubmitAt = wireAt; final.WireTimeSource = wireSource }()
startedAt := time.Now()
defer func() {
c.mu.Lock()
@@ -116,7 +127,13 @@ func (c *connection) submitPart(ctx context.Context, cmd queue.SubmitCommand, pa
return 0, "", result, err
}
c.sendMu.Lock()
wireSource = "write_uncertain"
seq, err := client.SendReqPkt(pkt)
if err == nil {
at := time.Now().UTC()
wireAt = &at
wireSource = "gateway_write_complete"
}
c.sendMu.Unlock()
if err != nil {
c.emitProtocolLog(protocolLogEvent{
@@ -326,6 +343,8 @@ func submitResult(cmd queue.SubmitCommand, sequenceID uint32, gatewayMessageID s
ErrorCode: code,
ErrorMessage: message,
SubmittedAt: time.Now().UTC(),
WireTimeSource: "not_written",
ReceiptRequested: cmd.CMPP.RegisteredDelivery != 0,
}
}
@@ -334,14 +353,17 @@ func submitSegmentResult(part submitPart, sequenceID uint32, gatewayMessageID st
gatewayMessageID = result.GatewayMessageID
}
return queue.SubmitSegmentResult{
SegmentTotal: int(part.PkTotal),
SegmentIndex: int(part.PkNumber),
SequenceID: sequenceID,
GatewayMessageID: gatewayMessageID,
SubmitStatus: result.SubmitStatus,
ErrorCode: result.ErrorCode,
ErrorMessage: result.ErrorMessage,
SubmittedAt: result.SubmittedAt,
FirstWireSubmitAt: result.FirstWireSubmitAt,
WireTimeSource: result.WireTimeSource,
ReceiptRequested: result.ReceiptRequested,
SegmentTotal: int(part.PkTotal),
SegmentIndex: int(part.PkNumber),
SequenceID: sequenceID,
GatewayMessageID: gatewayMessageID,
SubmitStatus: result.SubmitStatus,
ErrorCode: result.ErrorCode,
ErrorMessage: result.ErrorMessage,
SubmittedAt: result.SubmittedAt,
}
}
@@ -0,0 +1,36 @@
package upstream
import (
"context"
"testing"
"time"
)
func TestUnavailableConnectionNeverClaimsWireSubmitTime(t *testing.T) {
conn := &connection{closed: true}
cmd := submitCommandForPacketTest("3.0")
parts, err := splitSubmitContent(cmd.CMPP.MsgFmt, cmd.Content)
if err != nil {
t.Fatal(err)
}
_, _, result, err := conn.submitPart(context.Background(), cmd, parts[0])
if err == nil || result.FirstWireSubmitAt != nil || result.WireTimeSource != "not_written" {
t.Fatalf("invalid pre-write timing: %+v / %v", result, err)
}
}
func TestSegmentCarriesActualWireTimeAndReceiptRequest(t *testing.T) {
cmd := submitCommandForPacketTest("3.0")
cmd.CMPP.RegisteredDelivery = 1
result := submitResult(cmd, 1, "upstream-1", "timeout", "SUBMIT_TIMEOUT", "no response")
at := time.Now().UTC().Add(-5 * time.Second)
result.FirstWireSubmitAt = &at
result.WireTimeSource = "gateway_write_complete"
segment := submitSegmentResult(submitPart{PkTotal: 2, PkNumber: 1}, 1, "upstream-1", result)
if segment.FirstWireSubmitAt == nil || !segment.FirstWireSubmitAt.Equal(at) || segment.WireTimeSource != "gateway_write_complete" || !segment.ReceiptRequested {
t.Fatalf("wire timing was lost: %+v", segment)
}
if !segment.SubmittedAt.After(*segment.FirstWireSubmitAt) {
t.Fatal("response timestamp must not replace earlier wire timestamp")
}
}