perf(cmpp): add durable inbound fast path

This commit is contained in:
hectorzhao
2026-08-20 17:34:45 +08:00
parent 26ef67fb6a
commit 0b63bcd74e
29 changed files with 1136 additions and 87 deletions
+11
View File
@@ -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)
}
}
}