fix(feishu): add message cache for fetchMessageByID to avoid repeated downloads

- Add messageCache (sync.Map) to FeishuChannel struct
- Cache fetched messages with 30s TTL to avoid re-downloading attachments
  when multiple users reply to the same parent message in a thread
- Cleanup expired entries on read access (no background goroutine needed)
This commit is contained in:
ywj 2026-03-31 12:57:12 +08:00
parent a149761022
commit 9627846e5b
2 changed files with 21 additions and 2 deletions

View file

@ -19,6 +19,7 @@ import (
"strings"
"sync"
"sync/atomic"
"time"
"github.com/sipeed/picoclaw/pkg/bus"
"github.com/sipeed/picoclaw/pkg/channels"
@ -42,11 +43,17 @@ type FeishuChannel struct {
tokenCache *tokenCache // custom cache that supports invalidation
botOpenID atomic.Value // stores string; populated lazily for @mention detection
messageCache sync.Map // caches fetched messages (messageID -> *larkim.Message)
mu sync.Mutex
cancel context.CancelFunc
}
type cachedMessage struct {
msg *larkim.Message
expiry time.Time
}
func NewFeishuChannel(cfg config.FeishuConfig, bus *bus.MessageBus) (*FeishuChannel, error) {
base := channels.NewBaseChannel("feishu", cfg, bus, cfg.AllowFrom,
channels.WithGroupTrigger(cfg.GroupTrigger),

View file

@ -14,6 +14,8 @@ import (
"github.com/sipeed/picoclaw/pkg/utils"
)
const messageCacheTTL = 30 * time.Second
const (
maxReplyContextLen = 600
)
@ -122,6 +124,14 @@ func (c *FeishuChannel) resolveReplyTargetMessageID(ctx context.Context, message
}
func (c *FeishuChannel) fetchMessageByID(ctx context.Context, messageID string) (*larkim.Message, error) {
if cached, ok := c.messageCache.Load(messageID); ok {
cm := cached.(*cachedMessage)
if time.Now().Before(cm.expiry) {
return cm.msg, nil
}
c.messageCache.Delete(messageID)
}
req := larkim.NewGetMessageReqBuilder().
MessageId(messageID).
Build()
@ -138,7 +148,9 @@ func (c *FeishuChannel) fetchMessageByID(ctx context.Context, messageID string)
return nil, fmt.Errorf("feishu get message: empty response")
}
return resp.Data.Items[0], nil
msg := resp.Data.Items[0]
c.messageCache.Store(messageID, &cachedMessage{msg: msg, expiry: time.Now().Add(messageCacheTTL)})
return msg, nil
}
func replyTargetID(message *larkim.EventMessage) string {