github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/utilities/event/subscription.go (about) 1 package event 2 3 import ( 4 "context" 5 "sync" 6 "time" 7 8 "github.com/neatlab/neatio/utilities/common/mclock" 9 ) 10 11 type Subscription interface { 12 Err() <-chan error 13 Unsubscribe() 14 } 15 16 func NewSubscription(producer func(<-chan struct{}) error) Subscription { 17 s := &funcSub{unsub: make(chan struct{}), err: make(chan error, 1)} 18 go func() { 19 defer close(s.err) 20 err := producer(s.unsub) 21 s.mu.Lock() 22 defer s.mu.Unlock() 23 if !s.unsubscribed { 24 if err != nil { 25 s.err <- err 26 } 27 s.unsubscribed = true 28 } 29 }() 30 return s 31 } 32 33 type funcSub struct { 34 unsub chan struct{} 35 err chan error 36 mu sync.Mutex 37 unsubscribed bool 38 } 39 40 func (s *funcSub) Unsubscribe() { 41 s.mu.Lock() 42 if s.unsubscribed { 43 s.mu.Unlock() 44 return 45 } 46 s.unsubscribed = true 47 close(s.unsub) 48 s.mu.Unlock() 49 50 <-s.err 51 } 52 53 func (s *funcSub) Err() <-chan error { 54 return s.err 55 } 56 57 func Resubscribe(backoffMax time.Duration, fn ResubscribeFunc) Subscription { 58 s := &resubscribeSub{ 59 waitTime: backoffMax / 10, 60 backoffMax: backoffMax, 61 fn: fn, 62 err: make(chan error), 63 unsub: make(chan struct{}), 64 } 65 go s.loop() 66 return s 67 } 68 69 type ResubscribeFunc func(context.Context) (Subscription, error) 70 71 type resubscribeSub struct { 72 fn ResubscribeFunc 73 err chan error 74 unsub chan struct{} 75 unsubOnce sync.Once 76 lastTry mclock.AbsTime 77 waitTime, backoffMax time.Duration 78 } 79 80 func (s *resubscribeSub) Unsubscribe() { 81 s.unsubOnce.Do(func() { 82 s.unsub <- struct{}{} 83 <-s.err 84 }) 85 } 86 87 func (s *resubscribeSub) Err() <-chan error { 88 return s.err 89 } 90 91 func (s *resubscribeSub) loop() { 92 defer close(s.err) 93 var done bool 94 for !done { 95 sub := s.subscribe() 96 if sub == nil { 97 break 98 } 99 done = s.waitForError(sub) 100 sub.Unsubscribe() 101 } 102 } 103 104 func (s *resubscribeSub) subscribe() Subscription { 105 subscribed := make(chan error) 106 var sub Subscription 107 retry: 108 for { 109 s.lastTry = mclock.Now() 110 ctx, cancel := context.WithCancel(context.Background()) 111 go func() { 112 rsub, err := s.fn(ctx) 113 sub = rsub 114 subscribed <- err 115 }() 116 select { 117 case err := <-subscribed: 118 cancel() 119 if err != nil { 120 121 if s.backoffWait() { 122 return nil 123 } 124 continue retry 125 } 126 if sub == nil { 127 panic("event: ResubscribeFunc returned nil subscription and no error") 128 } 129 return sub 130 case <-s.unsub: 131 cancel() 132 return nil 133 } 134 } 135 } 136 137 func (s *resubscribeSub) waitForError(sub Subscription) bool { 138 defer sub.Unsubscribe() 139 select { 140 case err := <-sub.Err(): 141 return err == nil 142 case <-s.unsub: 143 return true 144 } 145 } 146 147 func (s *resubscribeSub) backoffWait() bool { 148 if time.Duration(mclock.Now()-s.lastTry) > s.backoffMax { 149 s.waitTime = s.backoffMax / 10 150 } else { 151 s.waitTime *= 2 152 if s.waitTime > s.backoffMax { 153 s.waitTime = s.backoffMax 154 } 155 } 156 157 t := time.NewTimer(s.waitTime) 158 defer t.Stop() 159 select { 160 case <-t.C: 161 return false 162 case <-s.unsub: 163 return true 164 } 165 } 166 167 type SubscriptionScope struct { 168 mu sync.Mutex 169 subs map[*scopeSub]struct{} 170 closed bool 171 } 172 173 type scopeSub struct { 174 sc *SubscriptionScope 175 s Subscription 176 } 177 178 func (sc *SubscriptionScope) Track(s Subscription) Subscription { 179 sc.mu.Lock() 180 defer sc.mu.Unlock() 181 if sc.closed { 182 return nil 183 } 184 if sc.subs == nil { 185 sc.subs = make(map[*scopeSub]struct{}) 186 } 187 ss := &scopeSub{sc, s} 188 sc.subs[ss] = struct{}{} 189 return ss 190 } 191 192 func (sc *SubscriptionScope) Close() { 193 sc.mu.Lock() 194 defer sc.mu.Unlock() 195 if sc.closed { 196 return 197 } 198 sc.closed = true 199 for s := range sc.subs { 200 s.s.Unsubscribe() 201 } 202 sc.subs = nil 203 } 204 205 func (sc *SubscriptionScope) Count() int { 206 sc.mu.Lock() 207 defer sc.mu.Unlock() 208 return len(sc.subs) 209 } 210 211 func (s *scopeSub) Unsubscribe() { 212 s.s.Unsubscribe() 213 s.sc.mu.Lock() 214 defer s.sc.mu.Unlock() 215 delete(s.sc.subs, s) 216 } 217 218 func (s *scopeSub) Err() <-chan error { 219 return s.s.Err() 220 }