@@ -187,25 +187,45 @@ func (pm *PluginManager) killPluginLocked(pID plugins.PluginID) {
187
187
// Dispense returns a PluginInstance for use by safely obtaining the
188
188
// PluginInstance from storage if we have it.
189
189
func (pm * PluginManager ) Dispense (name , pluginType string ) (PluginInstance , error ) {
190
-
191
190
// Measure the time taken to dispense a plugin. This helps identify
192
191
// contention and pressure obtaining plugin client handles.
193
192
labels := []metrics.Label {{Name : "plugin_name" , Value : name }, {Name : "plugin_type" , Value : pluginType }}
194
193
defer metrics .MeasureSinceWithLabels ([]string {"plugin" , "manager" , "access_ms" }, time .Now (), labels )
195
194
196
- pm .pluginInstancesLock .RLock ()
197
- defer pm .pluginInstancesLock .RUnlock ()
195
+ pID := plugins.PluginID {Name : name , PluginType : pluginType }
198
196
199
197
// Attempt to pull our plugin instance from the store and pass this to the
200
- // caller.
201
- //
202
- // TODO(jrasell) if we do not find the instance, we should probably try and
203
- // dispense the plugin. We should also check the plugin instance has not
204
- // exited.
205
- inst , ok := pm .pluginInstances [plugins.PluginID {Name : name , PluginType : pluginType }]
198
+ // caller. If the plugin isn't in the store, try to instantiate it; if it
199
+ // is, do a health check and attempt to re-instantiate if it fails.
200
+ pm .pluginInstancesLock .Lock ()
201
+ inst , exists := pm .pluginInstances [pID ]
202
+
203
+ if exists {
204
+ if _ , err := pm .pluginInfo (pID , inst ); err == nil {
205
+ // Plugin is fine, return it
206
+ pm .pluginInstancesLock .Unlock ()
207
+ return inst , nil
208
+ }
209
+
210
+ // The plugin exists, but is broken. Remove it.
211
+ pm .logger .Warn ("plugin failed healthcheck" , "plugin_name" , pID .Name )
212
+ pm .killPluginLocked (pID )
213
+ } else {
214
+ pm .logger .Warn ("plugin not in store" , "plugin_name" , pID .Name )
215
+ }
216
+ pm .pluginInstancesLock .Unlock ()
217
+
218
+ if err := pm .dispensePlugins (); err != nil {
219
+ return nil , fmt .Errorf ("failed to dispense plugin: %q of type %q: %w" , name , pluginType , err )
220
+ }
221
+
222
+ pm .pluginInstancesLock .RLock ()
223
+ inst , ok := pm .pluginInstances [pID ]
224
+ pm .pluginInstancesLock .RUnlock ()
206
225
if ! ok {
207
226
return nil , fmt .Errorf ("failed to dispense plugin: %q of type %q is not stored" , name , pluginType )
208
227
}
228
+
209
229
return inst , nil
210
230
}
211
231
@@ -322,7 +342,23 @@ func (pm *PluginManager) launchExternalPlugin(id plugins.PluginID, info *pluginI
322
342
}
323
343
324
344
func (pm * PluginManager ) pluginLaunchCheck (id plugins.PluginID , info * pluginInfo , raw interface {}) (* base.PluginInfo , error ) {
345
+ pluginInfo , err := pm .pluginInfo (id , raw )
346
+ if err != nil {
347
+ return nil , err
348
+ }
349
+
350
+ // If the plugin name, or plugin do not match it means the executed plugin
351
+ // has returned its metadata that is different to the configured. This is a
352
+ // problem, particularly in the PluginType sense as it means it will be
353
+ // unable to fulfill its role.
354
+ if pluginInfo .Name != info .driver || pluginInfo .PluginType != id .PluginType {
355
+ return nil , fmt .Errorf ("plugin %s remote info doesn't match local config: %v" , id .Name , err )
356
+ }
357
+
358
+ return pluginInfo , nil
359
+ }
325
360
361
+ func (pm * PluginManager ) pluginInfo (id plugins.PluginID , raw interface {}) (* base.PluginInfo , error ) {
326
362
// Check that the plugin implements the base plugin interface. As these are
327
363
// external plugins we need to check this safely, otherwise an incorrect
328
364
// plugin can cause the core application to panic.
@@ -336,14 +372,6 @@ func (pm *PluginManager) pluginLaunchCheck(id plugins.PluginID, info *pluginInfo
336
372
return nil , fmt .Errorf ("failed to call PluginInfo on %s: %v" , id .Name , err )
337
373
}
338
374
339
- // If the plugin name, or plugin do not match it means the executed plugin
340
- // has returned its metadata that is different to the configured. This is a
341
- // problem, particularly in the PluginType sense as it means it will be
342
- // unable to fulfill its role.
343
- if pluginInfo .Name != info .driver || pluginInfo .PluginType != id .PluginType {
344
- return nil , fmt .Errorf ("plugin %s remote info doesn't match local config: %v" , id .Name , err )
345
- }
346
-
347
375
return pluginInfo , nil
348
376
}
349
377
0 commit comments