perf(cmpp): add durable inbound fast path
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"cmpp-platform/gateway/internal/metrics"
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
cmpp "github.com/bigwhite/gocmpp"
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
// one internal message mapping per destination while CMPP receives one response.
|
||||
|
||||
type submitRequest struct {
|
||||
RequestID string `json:"requestId,omitempty"`
|
||||
Account string `json:"account"`
|
||||
PhoneNumber string `json:"phoneNumber,omitempty"`
|
||||
PhoneNumbers []string `json:"phoneNumbers,omitempty"`
|
||||
@@ -117,6 +119,7 @@ func (s Server) handleSubmit(response *cmpp.Response, packet *cmpp.Packet, logge
|
||||
releaseSubmitBarrier := beginDownstreamSubmitBarrier(packet.Conn)
|
||||
apiStartedAt := time.Now()
|
||||
result, err := s.submit(remote, submitRequest{
|
||||
RequestID: inboundSubmitRequestID(session.connectionID, req.sequenceID, phones, content, req.srcID, longMessage),
|
||||
Account: account,
|
||||
PhoneNumber: phone,
|
||||
PhoneNumbers: phones,
|
||||
@@ -222,6 +225,14 @@ func (s Server) handleSubmit(response *cmpp.Response, packet *cmpp.Packet, logge
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func inboundSubmitRequestID(connectionID string, sequenceID uint32, phones []string, content string, srcID string, longMessage *inboundLongMessageFragment) string {
|
||||
// The key is stable for an API retry of the same packet but scoped to the authenticated
|
||||
// connection, so a later client session may intentionally reuse the CMPP Sequence_Id.
|
||||
payload := fmt.Sprintf("%s\x00%d\x00%s\x00%s\x00%s\x00%v", connectionID, sequenceID, strings.Join(phones, ","), strings.TrimSpace(srcID), content, longMessage)
|
||||
digest := sha256.Sum256([]byte(payload))
|
||||
return fmt.Sprintf("cmpp-inbound:%x", digest[:])
|
||||
}
|
||||
|
||||
func observeInboundSubmitResponse(handlerStartedAt time.Time, responseReadyAt time.Time, accepted bool, next func(error)) func(error) {
|
||||
return func(sendErr error) {
|
||||
metrics.ObserveInboundStage("response_write", sendErr == nil, time.Since(responseReadyAt))
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package inbound
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestInboundSubmitRequestIDIsStableForRetry(t *testing.T) {
|
||||
fragment := &inboundLongMessageFragment{Reference: 7, Total: 2, Index: 1, Format: 8}
|
||||
first := inboundSubmitRequestID("connection-1", 42, []string{"13800000001"}, "【测试】内容", "1069", fragment)
|
||||
second := inboundSubmitRequestID("connection-1", 42, []string{"13800000001"}, "【测试】内容", "1069", fragment)
|
||||
if first != second {
|
||||
t.Fatalf("retry key changed: %q != %q", first, second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInboundSubmitRequestIDSeparatesPayloadAndSession(t *testing.T) {
|
||||
base := inboundSubmitRequestID("connection-1", 42, []string{"13800000001"}, "content", "1069", nil)
|
||||
cases := []string{
|
||||
inboundSubmitRequestID("connection-2", 42, []string{"13800000001"}, "content", "1069", nil),
|
||||
inboundSubmitRequestID("connection-1", 43, []string{"13800000001"}, "content", "1069", nil),
|
||||
inboundSubmitRequestID("connection-1", 42, []string{"13800000002"}, "content", "1069", nil),
|
||||
inboundSubmitRequestID("connection-1", 42, []string{"13800000001"}, "other", "1069", nil),
|
||||
}
|
||||
for _, candidate := range cases {
|
||||
if candidate == base {
|
||||
t.Fatalf("different submit produced duplicate key %q", base)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user