[MM-13507] Plugin framework: auto-restart plugins that crash (#10781)

* introduce plugin health check

* implement plugin health check job

* add support for checking pid of plugin process and RPC ping, to determine a plugin's health

* implement restart policy with back-offs

* support "EnableHealthCheck" boolean from config file.

* add tests for supervisor.PerformHealthCheck() and shouldDeactivatePlugin()

* improve error handling. clean up if blocks to be more concise
Этот коммит содержится в:
Michael Kochell
2019-05-09 16:08:31 -04:00
коммит произвёл Christopher Speller
родитель 818e0470df
Коммит 43e95b0b2b
7 изменённых файлов: 485 добавлений и 12 удалений

Просмотреть файл

@@ -31,11 +31,13 @@ type activePlugin struct {
// It is meant for use by the Mattermost server to manipulate, interact with and report on the set
// of active plugins.
type Environment struct {
activePlugins sync.Map
logger *mlog.Logger
newAPIImpl apiImplCreatorFunc
pluginDir string
webappPluginDir string
activePlugins sync.Map
pluginHealthStatuses sync.Map
pluginHealthCheckJob *PluginHealthCheckJob
logger *mlog.Logger
newAPIImpl apiImplCreatorFunc
pluginDir string
webappPluginDir string
}
func NewEnvironment(newAPIImpl apiImplCreatorFunc, pluginDir string, webappPluginDir string, logger *mlog.Logger) (*Environment, error) {
@@ -227,6 +229,15 @@ func (env *Environment) Activate(id string) (manifest *model.Manifest, activated
ap.supervisor = sup
componentActivated = true
var h *PluginHealthStatus
if health, ok := env.pluginHealthStatuses.Load(id); ok {
h = health.(*PluginHealthStatus)
} else {
h = newPluginHealthStatus()
env.pluginHealthStatuses.Store(id, h)
}
h.Crashed = false
}
if !componentActivated {
@@ -256,6 +267,30 @@ func (env *Environment) Deactivate(id string) bool {
return true
}
// RestartPlugin deactivates, then activates the plugin with the given id.
func (env *Environment) RestartPlugin(id string) error {
env.Deactivate(id)
_, _, err := env.Activate(id)
return err
}
// UpdatePluginHealthStatus accepts a callback to edit the stored health status of the plugin.
func (env *Environment) UpdatePluginHealthStatus(id string, callback func(*PluginHealthStatus)) {
if h, ok := env.pluginHealthStatuses.Load(id); ok {
callback(h.(*PluginHealthStatus))
}
}
// CheckPluginHealthStatus checks if the plugin is in a failed state, based on information gathered from previous health checks.
func (env *Environment) CheckPluginHealthStatus(id string) error {
if h, ok := env.pluginHealthStatuses.Load(id); ok {
if h.(*PluginHealthStatus).Crashed {
return h.(*PluginHealthStatus).lastError
}
}
return nil
}
// Shutdown deactivates all plugins and gracefully shuts down the environment.
func (env *Environment) Shutdown() {
env.activePlugins.Range(func(key, value interface{}) bool {