This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user