返回 DeepSeek-Reasonix
message_dedup.go
根目录 / internal / extension / message_dedup.go
1 package extension
2
3 import (
4 "strings"
5 "sync"
6 )
7
8 // MessageSendGuard prevents duplicate irreversible message-send receipts for
9 // the same (generation, messageID) pair within a process.
10 type MessageSendGuard struct {
11 mu sync.Mutex
12 seen map[string]struct{}
13 }
14
15 // DefaultMessageSendGuard belongs to the compatibility runtime owner.
16 var DefaultMessageSendGuard = DefaultRuntimeOwner.Messages
17
18 // NewMessageSendGuard returns an empty guard.
19 func NewMessageSendGuard() *MessageSendGuard {
20 return &MessageSendGuard{seen: make(map[string]struct{})}
21 }
22
23 // TryRecord returns true when this is the first observation of messageID for
24 // gen and records it. Second calls return false (duplicate send protection).
25 func (g *MessageSendGuard) TryRecord(gen uint64, messageID string) bool {
26 if g == nil || messageID == "" {
27 return true
28 }
29 key := itoaU64(gen) + ":" + messageID
30 g.mu.Lock()
31 defer g.mu.Unlock()
32 if _, ok := g.seen[key]; ok {
33 return false
34 }
35 g.seen[key] = struct{}{}
36 return true
37 }
38
39 // Forget removes a message key when its matching receipt leaves retention.
40 func (g *MessageSendGuard) Forget(gen uint64, messageID string) {
41 if g == nil || messageID == "" {
42 return
43 }
44 g.mu.Lock()
45 delete(g.seen, itoaU64(gen)+":"+messageID)
46 g.mu.Unlock()
47 }
48
49 // ForgetReceipt keeps dedup retention aligned with ReceiptStore eviction.
50 func (g *MessageSendGuard) ForgetReceipt(r EffectReceipt) {
51 const prefix = "message-sent:"
52 if g == nil || !strings.HasPrefix(r.ID, prefix) {
53 return
54 }
55 messageID := r.Component
56 if messageID == "" {
57 messageID = strings.TrimPrefix(r.ID, prefix)
58 messageID = strings.TrimSuffix(messageID, "#gen-"+itoaU64(r.Generation))
59 }
60 g.Forget(r.Generation, messageID)
61 }
62
63 // RecordMessageSentOnce records an irreversible message-send receipt only on
64 // the first observation of (generation, messageID).
65 func RecordMessageSentOnce(generation uint64, messageID, owner string) bool {
66 return RuntimeOwnerOrDefault(nil).RecordMessageSentOnce(generation, messageID, owner)
67 }
68
68 lines GO