Skip to content

Commit afad84d

Browse files
authored
feat: plugin unregister clean cache immediatly (#636)
1 parent a82c02f commit afad84d

3 files changed

Lines changed: 59 additions & 4 deletions

File tree

internal/cluster/node.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,23 @@ func (c *Cluster) FetchPluginAvailableNodesByHashedId(hashedPluginId string) ([]
122122
}
123123

124124
nodes := make([]string, 0)
125-
for key := range states {
125+
for key, state := range states {
126+
// Check if the plugin state is still valid (not expired)
127+
if !c.isPluginStateValid(&state) {
128+
// State is expired, clean it up
129+
nodeId, _, err := c.splitNodePluginJoin(key)
130+
if err == nil {
131+
log.Warn("found expired plugin state, cleaning up",
132+
"key", key,
133+
"node_id", nodeId,
134+
"scheduled_at", state.ScheduledAt,
135+
)
136+
// Clean up expired state immediately
137+
c.forceGCPluginByNodePluginJoin(key)
138+
}
139+
continue
140+
}
141+
126142
nodeId, _, err := c.splitNodePluginJoin(key)
127143
if err != nil {
128144
continue

internal/cluster/plugin.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,31 @@ func (c *Cluster) UnregisterPlugin(lifetime plugin_entities.PluginLifetime) erro
8181
log.Info("unregistering plugin", "identity", identity.String())
8282
}
8383

84-
// remove plugin from cluster
85-
err = c.removePluginState(c.id, plugin_entities.HashedIdentity(identity.String()))
84+
hashedIdentity := plugin_entities.HashedIdentity(identity.String())
85+
const UNREGISTER_PLUGIN_RETRY_BASE_DELAY = 10 * time.Millisecond
86+
87+
// remove plugin from cluster with retry logic
88+
maxRetries := 3
89+
for i := 0; i < maxRetries; i++ {
90+
err = c.removePluginState(c.id, hashedIdentity)
91+
if err == nil {
92+
break
93+
}
94+
95+
// Log retry attempt
96+
if i < maxRetries-1 {
97+
log.Warn("failed to remove plugin state, retrying",
98+
"identity", identity.String(),
99+
"attempt", i+1,
100+
"max_retries", maxRetries,
101+
"error", err,
102+
)
103+
time.Sleep(time.Duration(i+1) * UNREGISTER_PLUGIN_RETRY_BASE_DELAY)
104+
}
105+
}
106+
86107
if err != nil {
87-
return errors.Join(err, errors.New("failed to remove plugin state"))
108+
return errors.Join(err, errors.New("failed to remove plugin state after retries"))
88109
}
89110

90111
c.plugins.Delete(identity.String())
@@ -262,6 +283,23 @@ func (c *Cluster) isPluginActive(state *pluginState) bool {
262283
return true
263284
}
264285

286+
// isPluginStateValid checks if a plugin runtime state is still valid
287+
// A state is considered valid if it has been scheduled within the deactivated timeout
288+
func (c *Cluster) isPluginStateValid(state *plugin_entities.PluginRuntimeState) bool {
289+
if state == nil {
290+
return false
291+
}
292+
if state.ScheduledAt == nil {
293+
return false
294+
}
295+
// Consider state invalid if it hasn't been updated in more than half the deactivated timeout
296+
// This allows us to clean up stale states faster
297+
if time.Since(*state.ScheduledAt) > c.pluginDeactivatedTimeout/2 {
298+
return false
299+
}
300+
return true
301+
}
302+
265303
func (c *Cluster) splitNodePluginJoin(node_plugin_join string) (nodeId string, plugin_hashed_id string, err error) {
266304
split := strings.Split(node_plugin_join, ":")
267305
if len(split) != 2 {

internal/cluster/plugin_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,4 @@ func TestPluginRegisterIdempotent(t *testing.T) {
240240
return
241241
}
242242
}
243+

0 commit comments

Comments
 (0)