diff --git a/network/nsq_client.go b/network/nsq_client.go index e400cca..a06c0ea 100644 --- a/network/nsq_client.go +++ b/network/nsq_client.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "strconv" @@ -59,6 +59,19 @@ func (data *NSQStatsData) GetChannel(topicName, channelName string) *nsqd.Channe return nil } +func (data *NSQStatsData) ClientIsRunning(hostname string) bool { + for _, topic := range data.Topics { + for _, channel := range topic.Channels { + for _, client := range channel.Clients { + if client.Hostname == hostname { + return true + } + } + } + } + return false +} + // NewNSQClient returns a new NSQ client that will connect to the NSQ // server and the specified url. The URL is typically available through // Config.NsqdHttpAddress, and usually ends with :4151. This is @@ -98,7 +111,7 @@ func (client *NSQClient) EnqueueString(topic string, data string) error { // nsqd sends a simple OK. We have to read the response body, // or the connection will hang open forever. - body, _ := ioutil.ReadAll(resp.Body) + body, _ := io.ReadAll(resp.Body) resp.Body.Close() // NSQ response body is short. "OK" on success, @@ -123,7 +136,7 @@ func (client *NSQClient) get(_url string) ([]byte, error) { if err != nil { return nil, fmt.Errorf("error connecting to nsq at %s: %v", client.URL, err) } - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) resp.Body.Close() if err != nil { return nil, fmt.Errorf("error reading nsq response body: %v", err) diff --git a/views/work_items/show.html b/views/work_items/show.html index ec7105a..b09a55d 100644 --- a/views/work_items/show.html +++ b/views/work_items/show.html @@ -69,7 +69,7 @@

{{ .item.Name }}

User
{{ .item.User }}
Node
-
{{ defaultString .item.Node "N/A" }}
+
{{ defaultString .item.Node "N/A" }} {{ escapeHTML .clientStatusIcon }}
PID
{{ .item.PID }}
APTrust Approver
diff --git a/web/webui/work_items_controller.go b/web/webui/work_items_controller.go index aecff12..728fe9e 100644 --- a/web/webui/work_items_controller.go +++ b/web/webui/work_items_controller.go @@ -35,6 +35,9 @@ func WorkItemShow(c *gin.Context) { } req.TemplateData["item"] = item + // This has to be initialized to a string value, or the HTML template won't render. + req.TemplateData["clientStatusIcon"] = "" + // Show requeue options to Admin, if item has not completed. // Only sys admin should have this permission. userCanRequeue := req.CurrentUser.HasPermission(constants.WorkItemRequeue, item.InstitutionID) @@ -48,6 +51,22 @@ func WorkItemShow(c *gin.Context) { return } req.TemplateData["form"] = form + + // Create an icon to display next to the node name indicating + // whether that node is currently running. Options are "?" for + // unknown, check for running, "!" for not running. + if item.Node != "" { + icon := `` + nsqStats, err := common.Context().NSQClient.GetStats() + if err == nil && nsqStats != nil { + if nsqStats.ClientIsRunning(item.Node) { + icon = `` + } else { + icon = `` + } + } + req.TemplateData["clientStatusIcon"] = icon + } } // Let user fix missing object id, if necessary