perf: expand gateway capacity and prevent receipt replay
This commit is contained in:
@@ -18,6 +18,7 @@ const defaultDownstreamAckTimeout = 30 * time.Second
|
||||
|
||||
type downstreamAckTracker struct {
|
||||
deliveryID string
|
||||
claimID string
|
||||
connectionID string
|
||||
sequenceID uint32
|
||||
messageID uint64
|
||||
@@ -69,29 +70,29 @@ func downstreamAckKey(conn *cmpp.Conn, sequenceID uint32) string {
|
||||
return fmt.Sprintf("%p:%d", conn, sequenceID)
|
||||
}
|
||||
|
||||
func registerDownstreamAck(session *downstreamSession, deliveryID string, sequenceID uint32, messageID uint64, deadline time.Time) *downstreamAckTracker {
|
||||
func registerDownstreamAck(session *downstreamSession, deliveryID string, claimID string, sequenceID uint32, messageID uint64, deadline time.Time) *downstreamAckTracker {
|
||||
if session == nil || session.conn == nil || strings.TrimSpace(deliveryID) == "" {
|
||||
return nil
|
||||
}
|
||||
tracker := &downstreamAckTracker{
|
||||
deliveryID: deliveryID, connectionID: session.connectionID,
|
||||
deliveryID: deliveryID, claimID: claimID, connectionID: session.connectionID,
|
||||
sequenceID: sequenceID, messageID: messageID, session: session,
|
||||
}
|
||||
key := downstreamAckKey(session.conn, sequenceID)
|
||||
downstreamAckRegistry.Lock()
|
||||
downstreamAckRegistry.items[key] = tracker
|
||||
downstreamAckRegistry.Unlock()
|
||||
tracker.timer = time.AfterFunc(time.Until(deadline), func() {
|
||||
timedOut := takeDownstreamAck(session.conn, sequenceID)
|
||||
if timedOut == nil || timedOut.session == nil || timedOut.session.deliveryReport == nil {
|
||||
return
|
||||
}
|
||||
timedOut.session.deliveryReport(downstreamDeliveryLifecycleEvent{
|
||||
Kind: "failed", DeliveryID: timedOut.deliveryID, ConnectionID: timedOut.connectionID,
|
||||
Kind: "failed", DeliveryID: timedOut.deliveryID, ClaimID: timedOut.claimID, ConnectionID: timedOut.connectionID,
|
||||
SequenceID: timedOut.sequenceID, MessageID: timedOut.messageID, ObservedAt: time.Now().UTC(),
|
||||
FailureType: "ack_timeout", ErrorMessage: "CMPP_DELIVER_RESP timeout",
|
||||
})
|
||||
})
|
||||
downstreamAckRegistry.Unlock()
|
||||
return tracker
|
||||
}
|
||||
|
||||
@@ -149,7 +150,7 @@ func handleDownstreamAcknowledgement(conn *cmpp.Conn, sequenceID uint32, message
|
||||
}
|
||||
if tracker.session != nil && tracker.session.deliveryReport != nil {
|
||||
go tracker.session.deliveryReport(downstreamDeliveryLifecycleEvent{
|
||||
Kind: "acknowledged", DeliveryID: tracker.deliveryID, ConnectionID: tracker.connectionID,
|
||||
Kind: "acknowledged", DeliveryID: tracker.deliveryID, ClaimID: tracker.claimID, ConnectionID: tracker.connectionID,
|
||||
SequenceID: sequenceID, MessageID: messageID, Result: result, ObservedAt: time.Now().UTC(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
type DownstreamReceipt struct {
|
||||
DeliveryID string `json:"deliveryId,omitempty"`
|
||||
ClaimID string `json:"claimId,omitempty"`
|
||||
Account string `json:"account,omitempty"`
|
||||
ApplicationID string `json:"applicationId,omitempty"`
|
||||
MessageID string `json:"messageId"`
|
||||
@@ -31,6 +32,7 @@ type DownstreamReceipt struct {
|
||||
|
||||
type DownstreamUplink struct {
|
||||
DeliveryID string `json:"deliveryId,omitempty"`
|
||||
ClaimID string `json:"claimId,omitempty"`
|
||||
Account string `json:"account,omitempty"`
|
||||
ApplicationID string `json:"applicationId,omitempty"`
|
||||
MessageID string `json:"messageId,omitempty"`
|
||||
@@ -55,6 +57,7 @@ type DownstreamSendResult struct {
|
||||
type downstreamDeliveryLifecycleEvent struct {
|
||||
Kind string
|
||||
DeliveryID string
|
||||
ClaimID string
|
||||
ConnectionID string
|
||||
SequenceID uint32
|
||||
MessageID uint64
|
||||
@@ -70,7 +73,7 @@ func (s Server) reportDownstreamDelivery(event downstreamDeliveryLifecycleEvent)
|
||||
return
|
||||
}
|
||||
payload := map[string]any{
|
||||
"id": event.DeliveryID, "connectionId": event.ConnectionID,
|
||||
"id": event.DeliveryID, "claimId": event.ClaimID, "connectionId": event.ConnectionID,
|
||||
"sequenceId": strconv.FormatUint(uint64(event.SequenceID), 10),
|
||||
"messageId": strconv.FormatUint(event.MessageID, 10),
|
||||
}
|
||||
@@ -160,7 +163,7 @@ func pushReceiptWithResult(event DownstreamReceipt, allowRecovery bool) (Downstr
|
||||
return DownstreamSendResult{}, err
|
||||
}
|
||||
deliver := downstreamDeliverPacket(session, receiptMessageID, session.srcID, defaultString(event.PhoneNumber, session.phoneNumber), 0, 1, string(receiptBytes))
|
||||
return sendDownstream(session, deliver, event.DeliveryID)
|
||||
return sendDownstream(session, deliver, event.DeliveryID, event.ClaimID)
|
||||
}
|
||||
|
||||
func downstreamReceiptMessageID(event DownstreamReceipt, session *downstreamSession) uint64 {
|
||||
@@ -228,7 +231,7 @@ func PushUplinkWithResult(event DownstreamUplink) (DownstreamSendResult, error)
|
||||
0,
|
||||
content,
|
||||
)
|
||||
return sendDownstream(session, deliver, event.DeliveryID)
|
||||
return sendDownstream(session, deliver, event.DeliveryID, event.ClaimID)
|
||||
}
|
||||
|
||||
func errorMessageWithCode(message string, code string) string {
|
||||
@@ -272,7 +275,7 @@ func findSession(messageID string, account string) *downstreamSession {
|
||||
return nil
|
||||
}
|
||||
|
||||
func sendDownstream(session *downstreamSession, deliver cmpp.Packer, deliveryID string) (DownstreamSendResult, error) {
|
||||
func sendDownstream(session *downstreamSession, deliver cmpp.Packer, deliveryID string, claimID string) (DownstreamSendResult, error) {
|
||||
session.mu.Lock()
|
||||
defer session.mu.Unlock()
|
||||
messageID := downstreamDeliverMessageID(deliver)
|
||||
@@ -289,7 +292,7 @@ func sendDownstream(session *downstreamSession, deliver cmpp.Packer, deliveryID
|
||||
SentAt: formatRFC3339Nano(sentAt),
|
||||
AckDeadlineAt: formatRFC3339Nano(ackDeadlineAt),
|
||||
}
|
||||
tracker := registerDownstreamAck(session, deliveryID, sequenceID, messageID, ackDeadlineAt)
|
||||
tracker := registerDownstreamAck(session, deliveryID, claimID, sequenceID, messageID, ackDeadlineAt)
|
||||
if err := session.conn.SendPkt(deliver, sequenceID); err != nil {
|
||||
removeDownstreamAck(tracker)
|
||||
session.recordDownstreamProtocol(deliver, deliveryID, sequenceID, messageID, "failed", "SEND_FAILED", err)
|
||||
@@ -306,7 +309,7 @@ func sendDownstream(session *downstreamSession, deliver cmpp.Packer, deliveryID
|
||||
result.Sent = true
|
||||
if deliveryID != "" && session.deliveryReport != nil {
|
||||
go session.deliveryReport(downstreamDeliveryLifecycleEvent{
|
||||
Kind: "sent", DeliveryID: deliveryID, ConnectionID: session.connectionID,
|
||||
Kind: "sent", DeliveryID: deliveryID, ClaimID: claimID, ConnectionID: session.connectionID,
|
||||
SequenceID: sequenceID, MessageID: messageID, ObservedAt: sentAt, AckDeadlineAt: ackDeadlineAt,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -15,6 +16,8 @@ import (
|
||||
type pendingDeliveryRequest struct {
|
||||
Account string `json:"account"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
ClaimID string `json:"claimId"`
|
||||
LeaseMS int `json:"leaseMs"`
|
||||
}
|
||||
|
||||
type pendingDelivery struct {
|
||||
@@ -22,6 +25,7 @@ type pendingDelivery struct {
|
||||
DeliveryType string `json:"deliveryType"`
|
||||
Payload json.RawMessage `json:"payload"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
ClaimID string `json:"claimId"`
|
||||
}
|
||||
|
||||
type pendingFlushResult struct {
|
||||
@@ -33,25 +37,96 @@ type pendingFlushResult struct {
|
||||
LastError string
|
||||
}
|
||||
|
||||
type pendingFlushCall struct {
|
||||
done chan struct{}
|
||||
result pendingFlushResult
|
||||
err error
|
||||
}
|
||||
|
||||
var pendingFlushSingleflight = struct {
|
||||
sync.Mutex
|
||||
byAccount map[string]*pendingFlushCall
|
||||
}{byAccount: make(map[string]*pendingFlushCall)}
|
||||
|
||||
type pendingFlushSchedule struct {
|
||||
first time.Time
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
var pendingFlushDebouncer = struct {
|
||||
sync.Mutex
|
||||
byAccount map[string]*pendingFlushSchedule
|
||||
}{byAccount: make(map[string]*pendingFlushSchedule)}
|
||||
|
||||
func (s Server) schedulePendingFlush(account string, logger *log.Logger) {
|
||||
account = strings.TrimSpace(account)
|
||||
if account == "" {
|
||||
return
|
||||
}
|
||||
pendingFlushDebouncer.Lock()
|
||||
if scheduled := pendingFlushDebouncer.byAccount[account]; scheduled != nil {
|
||||
if time.Since(scheduled.first) < 250*time.Millisecond {
|
||||
scheduled.timer.Reset(25 * time.Millisecond)
|
||||
}
|
||||
pendingFlushDebouncer.Unlock()
|
||||
return
|
||||
}
|
||||
scheduled := &pendingFlushSchedule{first: time.Now()}
|
||||
scheduled.timer = time.AfterFunc(25*time.Millisecond, func() {
|
||||
pendingFlushDebouncer.Lock()
|
||||
if pendingFlushDebouncer.byAccount[account] == scheduled {
|
||||
delete(pendingFlushDebouncer.byAccount, account)
|
||||
}
|
||||
pendingFlushDebouncer.Unlock()
|
||||
if _, err := s.flushPending(account, logger); err != nil {
|
||||
logger.Printf("cmpp inbound event=scheduled_pending_flush_failed account=%s error=%q", account, err.Error())
|
||||
}
|
||||
})
|
||||
pendingFlushDebouncer.byAccount[account] = scheduled
|
||||
pendingFlushDebouncer.Unlock()
|
||||
}
|
||||
|
||||
func (s Server) flushPending(account string, logger *log.Logger) (pendingFlushResult, error) {
|
||||
account = strings.TrimSpace(account)
|
||||
result := pendingFlushResult{Account: account}
|
||||
if account == "" {
|
||||
return result, nil
|
||||
}
|
||||
pendingFlushSingleflight.Lock()
|
||||
if active := pendingFlushSingleflight.byAccount[account]; active != nil {
|
||||
pendingFlushSingleflight.Unlock()
|
||||
<-active.done
|
||||
return active.result, active.err
|
||||
}
|
||||
call := &pendingFlushCall{done: make(chan struct{})}
|
||||
pendingFlushSingleflight.byAccount[account] = call
|
||||
pendingFlushSingleflight.Unlock()
|
||||
call.result, call.err = s.flushPendingClaimed(account, logger)
|
||||
pendingFlushSingleflight.Lock()
|
||||
delete(pendingFlushSingleflight.byAccount, account)
|
||||
close(call.done)
|
||||
pendingFlushSingleflight.Unlock()
|
||||
return call.result, call.err
|
||||
}
|
||||
|
||||
func (s Server) flushPendingClaimed(account string, logger *log.Logger) (pendingFlushResult, error) {
|
||||
result := pendingFlushResult{Account: account}
|
||||
claimID := fmt.Sprintf("%s:%s:%d", s.gatewayInstanceID(), account, time.Now().UnixNano())
|
||||
var deliveries []pendingDelivery
|
||||
if err := s.post(context.Background(), "/gateway/events/downstream/pending", pendingDeliveryRequest{Account: account, Limit: 100}, &deliveries); err != nil {
|
||||
if err := s.post(context.Background(), "/gateway/events/downstream/pending", pendingDeliveryRequest{Account: account, Limit: 100, ClaimID: claimID, LeaseMS: 30000}, &deliveries); err != nil {
|
||||
logger.Printf("cmpp inbound pending delivery fetch failed account=%s err=%v", account, err)
|
||||
result.LastError = err.Error()
|
||||
return result, err
|
||||
}
|
||||
result.Deliveries = len(deliveries)
|
||||
for _, delivery := range deliveries {
|
||||
delivery.ClaimID = defaultString(delivery.ClaimID, claimID)
|
||||
sendResult, err := s.pushPendingDelivery(account, delivery)
|
||||
if err != nil {
|
||||
result.FailedCount++
|
||||
result.LastError = err.Error()
|
||||
_ = s.post(context.Background(), "/gateway/events/downstream/failed", map[string]any{
|
||||
"id": delivery.ID, "errorMessage": err.Error(), "failureType": "send_failed",
|
||||
"id": delivery.ID, "claimId": delivery.ClaimID, "errorMessage": err.Error(), "failureType": "send_failed",
|
||||
"connectionId": sendResult.ConnectionID, "sequenceId": sendResult.SequenceID,
|
||||
"messageId": sendResult.MessageID, "sentAt": sendResult.SentAt,
|
||||
}, nil)
|
||||
@@ -63,6 +138,7 @@ func (s Server) flushPending(account string, logger *log.Logger) (pendingFlushRe
|
||||
}
|
||||
if sendResult.ReasonCode == "SUBMIT_RESPONSE_PENDING" {
|
||||
result.WaitingCount++
|
||||
_ = s.releasePendingClaim(delivery, sendResult)
|
||||
continue
|
||||
}
|
||||
errorMessage := defaultString(sendResult.ErrorMessage, "gateway did not complete downstream delivery")
|
||||
@@ -74,8 +150,12 @@ func (s Server) flushPending(account string, logger *log.Logger) (pendingFlushRe
|
||||
result.FailedCount++
|
||||
}
|
||||
result.LastError = errorMessage
|
||||
if sendResult.Retryable {
|
||||
_ = s.releasePendingClaim(delivery, sendResult)
|
||||
continue
|
||||
}
|
||||
_ = s.post(context.Background(), "/gateway/events/downstream/failed", map[string]any{
|
||||
"id": delivery.ID, "errorMessage": errorMessageWithCode(errorMessage, sendResult.ReasonCode),
|
||||
"id": delivery.ID, "claimId": delivery.ClaimID, "errorMessage": errorMessageWithCode(errorMessage, sendResult.ReasonCode),
|
||||
"failureType": failureType, "connectionId": sendResult.ConnectionID,
|
||||
"sequenceId": sendResult.SequenceID, "messageId": sendResult.MessageID, "sentAt": sendResult.SentAt,
|
||||
}, nil)
|
||||
@@ -83,6 +163,14 @@ func (s Server) flushPending(account string, logger *log.Logger) (pendingFlushRe
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s Server) releasePendingClaim(delivery pendingDelivery, sendResult DownstreamSendResult) error {
|
||||
return s.post(context.Background(), "/gateway/events/downstream/failed", map[string]any{
|
||||
"id": delivery.ID, "claimId": delivery.ClaimID,
|
||||
"errorMessage": errorMessageWithCode(defaultString(sendResult.ErrorMessage, "Gateway released downstream delivery claim"), sendResult.ReasonCode),
|
||||
"failureType": "claim_released",
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func (s Server) pushPendingDelivery(account string, delivery pendingDelivery) (DownstreamSendResult, error) {
|
||||
switch delivery.DeliveryType {
|
||||
case "receipt":
|
||||
@@ -91,6 +179,7 @@ func (s Server) pushPendingDelivery(account string, delivery pendingDelivery) (D
|
||||
return DownstreamSendResult{}, err
|
||||
}
|
||||
event.DeliveryID = delivery.ID
|
||||
event.ClaimID = delivery.ClaimID
|
||||
event.Account = defaultString(event.Account, account)
|
||||
allowRecovery := !delivery.CreatedAt.IsZero() && time.Since(delivery.CreatedAt) >= 5*time.Second
|
||||
return pushReceiptWithResult(event, allowRecovery)
|
||||
@@ -100,6 +189,7 @@ func (s Server) pushPendingDelivery(account string, delivery pendingDelivery) (D
|
||||
return DownstreamSendResult{}, err
|
||||
}
|
||||
event.DeliveryID = delivery.ID
|
||||
event.ClaimID = delivery.ClaimID
|
||||
event.Account = defaultString(event.Account, account)
|
||||
return PushUplinkWithResult(event)
|
||||
default:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package inbound
|
||||
|
||||
import (
|
||||
"cmpp-platform/gateway/internal/protocollog"
|
||||
"context"
|
||||
"fmt"
|
||||
cmpp "github.com/bigwhite/gocmpp"
|
||||
@@ -8,20 +9,7 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type protocolLogEvent struct {
|
||||
Protocol string `json:"protocol"`
|
||||
Direction string `json:"direction"`
|
||||
EventType string `json:"eventType"`
|
||||
Status string `json:"status"`
|
||||
TenantID string `json:"tenantId,omitempty"`
|
||||
ApplicationID string `json:"applicationId,omitempty"`
|
||||
Account string `json:"account,omitempty"`
|
||||
MessageID string `json:"messageId,omitempty"`
|
||||
GatewayMessageID string `json:"gatewayMessageId,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
ResultCode string `json:"resultCode,omitempty"`
|
||||
Detail map[string]any `json:"detail,omitempty"`
|
||||
}
|
||||
type protocolLogEvent = protocollog.Event
|
||||
|
||||
func (s Server) submitResponseProtocolLogger(
|
||||
account string,
|
||||
@@ -71,6 +59,15 @@ func protocolSubmitResponseDetail(sequenceID uint32, sendErr error) map[string]a
|
||||
}
|
||||
|
||||
func (s Server) emitProtocolLog(event protocolLogEvent) {
|
||||
event.GatewayInstanceID = s.GatewayInstanceID
|
||||
if s.ProtocolLogPublisher != nil {
|
||||
go func() {
|
||||
if err := s.ProtocolLogPublisher.Publish(context.Background(), event); err != nil {
|
||||
log.Printf("cmpp inbound protocol log Redis publish failed account=%s message_id=%s error=%q", event.Account, event.MessageID, err)
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultHTTPTimeout)
|
||||
defer cancel()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package inbound
|
||||
|
||||
import (
|
||||
"cmpp-platform/gateway/internal/protocollog"
|
||||
"context"
|
||||
cmpp "github.com/bigwhite/gocmpp"
|
||||
"io"
|
||||
"log"
|
||||
@@ -22,6 +24,9 @@ type Server struct {
|
||||
RecoveryStore RecoveryStore
|
||||
GatewayInstanceID string
|
||||
MaxSubmitConcurrency int
|
||||
ProtocolLogPublisher interface {
|
||||
Publish(context.Context, protocollog.Event) error
|
||||
}
|
||||
}
|
||||
|
||||
func (s Server) ListenAndServe() error {
|
||||
|
||||
@@ -930,6 +930,42 @@ func TestFlushOnlineAccountsFetchesPendingDeliveries(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlushPendingCoalescesConcurrentRequestsPerAccount(t *testing.T) {
|
||||
var calls atomic.Int32
|
||||
release := make(chan struct{})
|
||||
api := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/api/gateway/events/downstream/pending" {
|
||||
t.Fatalf("unexpected api path: %s", r.URL.Path)
|
||||
}
|
||||
calls.Add(1)
|
||||
<-release
|
||||
_ = json.NewEncoder(w).Encode([]pendingDelivery{})
|
||||
}))
|
||||
defer api.Close()
|
||||
|
||||
server := Server{APIBaseURL: api.URL + "/api", GatewayInstanceID: "gateway-a"}
|
||||
results := make(chan error, 8)
|
||||
for range 8 {
|
||||
go func() {
|
||||
_, err := server.flushPending("100001", log.Default())
|
||||
results <- err
|
||||
}()
|
||||
}
|
||||
deadline := time.Now().Add(time.Second)
|
||||
for calls.Load() == 0 && time.Now().Before(deadline) {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
close(release)
|
||||
for range 8 {
|
||||
if err := <-results; err != nil {
|
||||
t.Fatalf("flush failed: %v", err)
|
||||
}
|
||||
}
|
||||
if got := calls.Load(); got != 1 {
|
||||
t.Fatalf("pending fetch calls = %d, want 1", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecoverPendingCandidatesFetchesPresenceAccounts(t *testing.T) {
|
||||
resetDownstreamRegistry()
|
||||
defer resetDownstreamRegistry()
|
||||
@@ -1085,7 +1121,7 @@ func TestDownstreamDeliveryRequiresAcknowledgement(t *testing.T) {
|
||||
messageID: "MSG-LONG-1", phoneNumber: "18821203795",
|
||||
protocolLog: func(event protocolLogEvent) { protocolEvents <- event },
|
||||
}
|
||||
registerDownstreamAck(session, "delivery-1", 37, 9016479179509871733, time.Now().Add(time.Second))
|
||||
registerDownstreamAck(session, "delivery-1", "", 37, 9016479179509871733, time.Now().Add(time.Second))
|
||||
handleDownstreamAcknowledgement(conn, 37, 9016479179509871733, 0, log.Default())
|
||||
|
||||
select {
|
||||
@@ -1165,6 +1201,7 @@ func TestSendDownstreamRejectsZeroMessageID(t *testing.T) {
|
||||
&downstreamSession{mu: &sync.Mutex{}},
|
||||
&cmpp.Cmpp2DeliverReqPkt{MsgId: 0},
|
||||
"delivery-zero",
|
||||
"",
|
||||
)
|
||||
if err == nil || !strings.Contains(err.Error(), "Msg_Id=0") {
|
||||
t.Fatalf("expected zero Msg_Id rejection, got %v", err)
|
||||
@@ -1180,7 +1217,7 @@ func TestDownstreamDeliveryReportsAckTimeout(t *testing.T) {
|
||||
conn: &cmpp.Conn{}, connectionID: "conn-1",
|
||||
deliveryReport: func(event downstreamDeliveryLifecycleEvent) { events <- event },
|
||||
}
|
||||
registerDownstreamAck(session, "delivery-timeout", 38, 9017467844344255865, time.Now().Add(20*time.Millisecond))
|
||||
registerDownstreamAck(session, "delivery-timeout", "", 38, 9017467844344255865, time.Now().Add(20*time.Millisecond))
|
||||
|
||||
select {
|
||||
case event := <-events:
|
||||
|
||||
@@ -212,11 +212,7 @@ func (s Server) handleSubmit(response *cmpp.Response, packet *cmpp.Packet, logge
|
||||
if sendErr != nil {
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
if _, err := s.flushPending(account, logger); err != nil {
|
||||
logger.Printf("cmpp inbound event=post_submit_pending_flush_failed account=%s message_id=%s error=%q", account, result.MessageID, err.Error())
|
||||
}
|
||||
}()
|
||||
s.schedulePendingFlush(account, logger)
|
||||
})
|
||||
logger.Printf(
|
||||
"cmpp inbound event=submit_accepted protocol=%s packet_type=%s account=%s remote=%s seq=%d phone=%s dest_count=%d accepted_count=%d result=0 message_id=%s gateway_message_id=%d duration_ms=%d content_chars=%d content_hash=%s",
|
||||
|
||||
Reference in New Issue
Block a user