improve dispatch cancellation and token estimates

This commit is contained in:
lpf
2026-05-11 12:43:41 +08:00
parent 97df340960
commit eb781cef25
6 changed files with 435 additions and 11 deletions

View File

@@ -33,6 +33,21 @@ func (r *recordingChannel) count() int {
return len(r.sent)
}
type canceledChannel struct {
called chan struct{}
}
func (c *canceledChannel) Name() string { return "test" }
func (c *canceledChannel) Start(ctx context.Context) error { return nil }
func (c *canceledChannel) Stop(ctx context.Context) error { return nil }
func (c *canceledChannel) IsRunning() bool { return true }
func (c *canceledChannel) IsAllowed(senderID string) bool { return true }
func (c *canceledChannel) HealthCheck(ctx context.Context) error { return nil }
func (c *canceledChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
close(c.called)
return context.Canceled
}
func TestDispatchOutbound_DeduplicatesRepeatedSend(t *testing.T) {
mb := bus.NewMessageBus()
mgr, err := NewManager(&config.Config{}, mb)
@@ -58,6 +73,28 @@ func TestDispatchOutbound_DeduplicatesRepeatedSend(t *testing.T) {
}
}
func TestDispatchOutbound_TreatsCanceledSendAsLifecycleExit(t *testing.T) {
mb := bus.NewMessageBus()
mgr, err := NewManager(&config.Config{}, mb)
if err != nil {
t.Fatalf("new manager: %v", err)
}
cc := &canceledChannel{called: make(chan struct{})}
mgr.channels["test"] = cc
mgr.refreshSnapshot()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go mgr.dispatchOutbound(ctx)
mb.PublishOutbound(bus.OutboundMessage{Channel: "test", ChatID: "c1", Content: "hello", Action: "send"})
select {
case <-cc.called:
case <-time.After(time.Second):
t.Fatalf("expected canceled send to be dispatched")
}
}
func TestBaseChannel_HandleMessage_ContentHashFallbackDedupe(t *testing.T) {
mb := bus.NewMessageBus()
bc := NewBaseChannel("test", nil, mb, nil)

View File

@@ -9,6 +9,7 @@ package channels
import (
"context"
"encoding/json"
"errors"
"fmt"
"hash/fnv"
"strings"
@@ -339,6 +340,13 @@ func (m *Manager) dispatchOutbound(ctx context.Context) {
go func(c Channel, outbound bus.OutboundMessage) {
defer func() { <-m.dispatchSem }()
if err := c.Send(ctx, outbound); err != nil {
if errors.Is(err, context.Canceled) {
logger.InfoCF("channels", logger.C0042, map[string]interface{}{
logger.FieldChannel: outbound.Channel,
"reason": "context canceled",
})
return
}
logger.ErrorCF("channels", logger.C0042, map[string]interface{}{
logger.FieldChannel: outbound.Channel,
logger.FieldError: err.Error(),