@@ -18,27 +18,36 @@ type listenerEntry struct {
1818// listenerRegistry manages all active flag change listener registrations for a single
1919// SDK client entity. It is safe to use from multiple goroutines.
2020type listenerRegistry struct {
21- mu sync.Mutex
22- entries map [string ]* listenerEntry // keyed by listenerId
23- tracker interfaces.FlagTracker
21+ mu sync.Mutex
22+ listeners map [string ]* listenerEntry // keyed by listenerId
23+ tracker interfaces.FlagTracker
2424}
2525
2626func newListenerRegistry (tracker interfaces.FlagTracker ) * listenerRegistry {
2727 return & listenerRegistry {
28- entries : make (map [string ]* listenerEntry ),
29- tracker : tracker ,
28+ listeners : make (map [string ]* listenerEntry ),
29+ tracker : tracker ,
3030 }
3131}
3232
33- // registerFlagChangeListener subscribes to general flag configuration changes. If flagKey
34- // is non-empty, only events for that specific flag are forwarded to the callback URI.
35- func (r * listenerRegistry ) registerFlagChangeListener (listenerID , flagKey , callbackURI string ) {
36- ch := r .tracker .AddFlagChangeListener ()
33+ // storeListener registers a new listener entry under listenerID, cancelling any
34+ // previously registered listener with the same ID. Returns the new entry's context.
35+ func (r * listenerRegistry ) storeListener (listenerID string ) context.Context {
3736 ctx , cancel := context .WithCancel (context .Background ())
38-
3937 r .mu .Lock ()
40- r .entries [listenerID ] = & listenerEntry {cancel : cancel }
38+ if old , exists := r .listeners [listenerID ]; exists {
39+ old .cancel ()
40+ }
41+ r .listeners [listenerID ] = & listenerEntry {cancel : cancel }
4142 r .mu .Unlock ()
43+ return ctx
44+ }
45+
46+ // registerFlagChangeListener subscribes to general flag configuration changes.
47+ // All flag change events are forwarded to the callback URI.
48+ func (r * listenerRegistry ) registerFlagChangeListener (listenerID , callbackURI string ) {
49+ ch := r .tracker .AddFlagChangeListener ()
50+ ctx := r .storeListener (listenerID )
4251
4352 svc := callbackService {baseURL : callbackURI }
4453 go func () {
@@ -51,9 +60,6 @@ func (r *listenerRegistry) registerFlagChangeListener(listenerID, flagKey, callb
5160 if ! ok {
5261 return
5362 }
54- if flagKey != "" && event .Key != flagKey {
55- continue
56- }
5763 _ = svc .post ("" , servicedef.ListenerNotification {
5864 ListenerID : listenerID ,
5965 FlagKey : event .Key ,
@@ -73,11 +79,7 @@ func (r *listenerRegistry) registerFlagValueChangeListener(
7379 callbackURI string ,
7480) {
7581 ch := r .tracker .AddFlagValueChangeListener (flagKey , evalCtx , defaultValue )
76- ctx , cancel := context .WithCancel (context .Background ())
77-
78- r .mu .Lock ()
79- r .entries [listenerID ] = & listenerEntry {cancel : cancel }
80- r .mu .Unlock ()
82+ ctx := r .storeListener (listenerID )
8183
8284 svc := callbackService {baseURL : callbackURI }
8385 go func () {
@@ -107,9 +109,9 @@ func (r *listenerRegistry) registerFlagValueChangeListener(
107109// registry. Returns false if no listener with that ID was found.
108110func (r * listenerRegistry ) unregister (listenerID string ) bool {
109111 r .mu .Lock ()
110- entry , ok := r .entries [listenerID ]
112+ entry , ok := r .listeners [listenerID ]
111113 if ok {
112- delete (r .entries , listenerID )
114+ delete (r .listeners , listenerID )
113115 }
114116 r .mu .Unlock ()
115117
@@ -122,11 +124,11 @@ func (r *listenerRegistry) unregister(listenerID string) bool {
122124// closeAll stops all active listener goroutines. Called when the SDK client entity closes.
123125func (r * listenerRegistry ) closeAll () {
124126 r .mu .Lock ()
125- entries := r .entries
126- r .entries = make (map [string ]* listenerEntry )
127+ listeners := r .listeners
128+ r .listeners = make (map [string ]* listenerEntry )
127129 r .mu .Unlock ()
128130
129- for _ , entry := range entries {
131+ for _ , entry := range listeners {
130132 entry .cancel ()
131133 }
132134}
0 commit comments