summaryrefslogtreecommitdiff
path: root/plugins/status
diff options
context:
space:
mode:
authorValery Piashchynski <[email protected]>2021-04-04 18:39:52 +0300
committerValery Piashchynski <[email protected]>2021-04-04 18:39:52 +0300
commitcc56299b877f3fbbae1e3368d98804d06564a424 (patch)
tree6b2bcd13eb32e31cef556f57869b9dcdeea4472a /plugins/status
parentc1664e0815727e599dcb7f7a0a7a95a5be974197 (diff)
- 🔥 Support Readiness checks (via `/ready`) status plugin endpoint.
Signed-off-by: Valery Piashchynski <[email protected]>
Diffstat (limited to 'plugins/status')
-rw-r--r--plugins/status/interface.go7
-rw-r--r--plugins/status/plugin.go92
-rw-r--r--plugins/status/rpc.go20
3 files changed, 93 insertions, 26 deletions
diff --git a/plugins/status/interface.go b/plugins/status/interface.go
index 0a92bc52..9d5a13af 100644
--- a/plugins/status/interface.go
+++ b/plugins/status/interface.go
@@ -9,3 +9,10 @@ type Status struct {
type Checker interface {
Status() Status
}
+
+// Readiness interface used to get readiness status from the plugin
+// that means, that worker poll inside the plugin has 1+ plugins which are ready to work
+// at the particular moment
+type Readiness interface {
+ Ready() Status
+}
diff --git a/plugins/status/plugin.go b/plugins/status/plugin.go
index 6fbe67cf..693440bf 100644
--- a/plugins/status/plugin.go
+++ b/plugins/status/plugin.go
@@ -18,10 +18,13 @@ const (
)
type Plugin struct {
- registry map[string]Checker
- server *fiber.App
- log logger.Logger
- cfg *Config
+ // plugins which needs to be checked just as Status
+ statusRegistry map[string]Checker
+ // plugins which needs to send Readiness status
+ readyRegistry map[string]Readiness
+ server *fiber.App
+ log logger.Logger
+ cfg *Config
}
func (c *Plugin) Init(log logger.Logger, cfg config.Configurer) error {
@@ -34,7 +37,9 @@ func (c *Plugin) Init(log logger.Logger, cfg config.Configurer) error {
return errors.E(op, errors.Disabled, err)
}
- c.registry = make(map[string]Checker)
+ c.readyRegistry = make(map[string]Readiness)
+ c.statusRegistry = make(map[string]Checker)
+
c.log = log
return nil
}
@@ -49,6 +54,7 @@ func (c *Plugin) Serve() chan error {
})
c.server.Use("/health", c.healthHandler)
+ c.server.Use("/ready", c.readinessHandler)
go func() {
err := c.server.Listen(c.cfg.Address)
@@ -69,10 +75,11 @@ func (c *Plugin) Stop() error {
return nil
}
-// Reset named service.
-func (c *Plugin) Status(name string) (Status, error) {
+// status returns a Checker interface implementation
+// Reset named service. This is not an Status interface implementation
+func (c *Plugin) status(name string) (Status, error) {
const op = errors.Op("checker_plugin_status")
- svc, ok := c.registry[name]
+ svc, ok := c.statusRegistry[name]
if !ok {
return Status{}, errors.E(op, errors.Errorf("no such service: %s", name))
}
@@ -80,16 +87,34 @@ func (c *Plugin) Status(name string) (Status, error) {
return svc.Status(), nil
}
-// CollectTarget collecting services which can provide Status.
-func (c *Plugin) CollectTarget(name endure.Named, r Checker) error {
- c.registry[name.Name()] = r
+// ready used to provide a readiness check for the plugin
+func (c *Plugin) ready(name string) (Status, error) {
+ const op = errors.Op("checker_plugin_ready")
+ svc, ok := c.readyRegistry[name]
+ if !ok {
+ return Status{}, errors.E(op, errors.Errorf("no such service: %s", name))
+ }
+
+ return svc.Ready(), nil
+}
+
+// CollectCheckerImpls collects services which can provide Status.
+func (c *Plugin) CollectCheckerImpls(name endure.Named, r Checker) error {
+ c.statusRegistry[name.Name()] = r
+ return nil
+}
+
+// CollectReadinessImpls collects services which can provide Readiness check.
+func (c *Plugin) CollectReadinessImpls(name endure.Named, r Readiness) error {
+ c.readyRegistry[name.Name()] = r
return nil
}
// Collects declares services to be collected.
func (c *Plugin) Collects() []interface{} {
return []interface{}{
- c.CollectTarget,
+ c.CollectReadinessImpls,
+ c.CollectCheckerImpls,
}
}
@@ -109,6 +134,35 @@ type Plugins struct {
const template string = "Service: %s: Status: %d\n"
+func (c *Plugin) readinessHandler(ctx *fiber.Ctx) error {
+ const op = errors.Op("checker_plugin_readiness_handler")
+ plugins := &Plugins{}
+ err := ctx.QueryParser(plugins)
+ if err != nil {
+ return errors.E(op, err)
+ }
+
+ if len(plugins.Plugins) == 0 {
+ ctx.Status(http.StatusOK)
+ _, _ = ctx.WriteString("No plugins provided in query. Query should be in form of: ready?plugin=plugin1&plugin=plugin2 \n")
+ return nil
+ }
+
+ // iterate over all provided plugins
+ for i := 0; i < len(plugins.Plugins); i++ {
+ // check if the plugin exists
+ if plugin, ok := c.readyRegistry[plugins.Plugins[i]]; ok {
+ st := plugin.Ready()
+ _, _ = ctx.WriteString(fmt.Sprintf(template, plugins.Plugins[i], st.Code))
+ } else {
+ _, _ = ctx.WriteString(fmt.Sprintf("Service: %s not found", plugins.Plugins[i]))
+ }
+ }
+
+ ctx.Status(http.StatusOK)
+ return nil
+}
+
func (c *Plugin) healthHandler(ctx *fiber.Ctx) error {
const op = errors.Op("checker_plugin_health_handler")
plugins := &Plugins{}
@@ -123,26 +177,16 @@ func (c *Plugin) healthHandler(ctx *fiber.Ctx) error {
return nil
}
- failed := false
// iterate over all provided plugins
for i := 0; i < len(plugins.Plugins); i++ {
// check if the plugin exists
- if plugin, ok := c.registry[plugins.Plugins[i]]; ok {
+ if plugin, ok := c.statusRegistry[plugins.Plugins[i]]; ok {
st := plugin.Status()
- if st.Code >= 500 {
- failed = true
- continue
- } else if st.Code >= 100 && st.Code <= 400 {
- _, _ = ctx.WriteString(fmt.Sprintf(template, plugins.Plugins[i], st.Code))
- }
+ _, _ = ctx.WriteString(fmt.Sprintf(template, plugins.Plugins[i], st.Code))
} else {
_, _ = ctx.WriteString(fmt.Sprintf("Service: %s not found", plugins.Plugins[i]))
}
}
- if failed {
- ctx.Status(http.StatusInternalServerError)
- return nil
- }
ctx.Status(http.StatusOK)
return nil
diff --git a/plugins/status/rpc.go b/plugins/status/rpc.go
index 396ff451..755a06fa 100644
--- a/plugins/status/rpc.go
+++ b/plugins/status/rpc.go
@@ -14,7 +14,7 @@ type rpc struct {
func (rpc *rpc) Status(service string, status *Status) error {
const op = errors.Op("checker_rpc_status")
rpc.log.Debug("started Status method", "service", service)
- st, err := rpc.srv.Status(service)
+ st, err := rpc.srv.status(service)
if err != nil {
return errors.E(op, err)
}
@@ -22,6 +22,22 @@ func (rpc *rpc) Status(service string, status *Status) error {
*status = st
rpc.log.Debug("status code", "code", st.Code)
- rpc.log.Debug("successfully finished Status method")
+ rpc.log.Debug("successfully finished the Status method")
+ return nil
+}
+
+// Status return current status of the provided plugin
+func (rpc *rpc) Ready(service string, status *Status) error {
+ const op = errors.Op("checker_rpc_ready")
+ rpc.log.Debug("started Ready method", "service", service)
+ st, err := rpc.srv.ready(service)
+ if err != nil {
+ return errors.E(op, err)
+ }
+
+ *status = st
+
+ rpc.log.Debug("status code", "code", st.Code)
+ rpc.log.Debug("successfully finished the Ready method")
return nil
}