internal/worker: display DB info on home page

Add DB process and lock information to the worker home page.

For golang/go#48010

Change-Id: Idab82180a33ce2d00350df0bbfeeb58b2a628ae8
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/349309
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/internal/postgres/postgres.go b/internal/postgres/postgres.go
index 8b48f1d..4c58c3e 100644
--- a/internal/postgres/postgres.go
+++ b/internal/postgres/postgres.go
@@ -140,7 +140,7 @@
 
 // GetUserInfo returns information about a database user.
 func (db *DB) GetUserInfo(ctx context.Context, user string) (_ *UserInfo, err error) {
-	derrors.Wrap(&err, "GetLockInfo(%q)", user)
+	derrors.Wrap(&err, "GetUserInfo(%q)", user)
 
 	ui := UserInfo{User: user}
 	// Count the total number of processes running as user.
diff --git a/internal/worker/pages.go b/internal/worker/pages.go
index 7a62644..3349453 100644
--- a/internal/worker/pages.go
+++ b/internal/worker/pages.go
@@ -83,6 +83,7 @@
 		logsURL = `https://cloud.google.com/console/logs/viewer?resource=gae_app%2Fmodule_id%2F` + s.cfg.ServiceID + `&project=` +
 			s.cfg.ProjectID
 	}
+
 	page := struct {
 		Config          *config.Config
 		Env             string
@@ -100,6 +101,7 @@
 		CgroupStats     map[string]uint64
 		Fetches         []*FetchInfo
 		LogsURL         string
+		DBInfo          *postgres.UserInfo
 	}{
 		Config:         s.cfg,
 		Env:            env(s.cfg),
@@ -116,6 +118,7 @@
 		CgroupStats:    getCgroupMemStats(),
 		Fetches:        FetchInfos(),
 		LogsURL:        logsURL,
+		DBInfo:         s.workerDBInfo(),
 	}
 	return renderPage(ctx, w, page, s.templates[indexTemplate])
 }
diff --git a/internal/worker/server.go b/internal/worker/server.go
index 3113827..14ba178 100644
--- a/internal/worker/server.go
+++ b/internal/worker/server.go
@@ -31,6 +31,7 @@
 	"golang.org/x/pkgsite/internal/index"
 	"golang.org/x/pkgsite/internal/log"
 	"golang.org/x/pkgsite/internal/middleware"
+	"golang.org/x/pkgsite/internal/poller"
 	"golang.org/x/pkgsite/internal/postgres"
 	"golang.org/x/pkgsite/internal/proxy"
 	"golang.org/x/pkgsite/internal/queue"
@@ -52,6 +53,7 @@
 	templates       map[string]*template.Template
 	staticPath      template.TrustedSource
 	getExperiments  func() []*internal.Experiment
+	workerDBInfo    func() *postgres.UserInfo
 }
 
 // ServerConfig contains everything needed by a Server.
@@ -92,6 +94,13 @@
 	if scfg.RedisCacheClient != nil {
 		c = cache.New(scfg.RedisCacheClient)
 	}
+
+	// Update information about DB locks, etc. every few seconds.
+	p := poller.New(nil, func(ctx context.Context) (interface{}, error) {
+		return scfg.DB.GetUserInfo(ctx, "worker")
+	}, func(err error) { log.Error(context.Background(), err) })
+	p.Start(context.Background(), 10*time.Second)
+
 	return &Server{
 		cfg:             cfg,
 		db:              scfg.DB,
@@ -104,6 +113,7 @@
 		templates:       templates,
 		staticPath:      scfg.StaticPath,
 		getExperiments:  scfg.GetExperiments,
+		workerDBInfo:    func() *postgres.UserInfo { return p.Current().(*postgres.UserInfo) },
 	}, nil
 }
 
diff --git a/static/worker/index.tmpl b/static/worker/index.tmpl
index bec41ca..d2e99fb 100644
--- a/static/worker/index.tmpl
+++ b/static/worker/index.tmpl
@@ -141,6 +141,12 @@
           {{.LoadShedStats.MaxSizeInFlight | bytesToMi}} Mi
           ({{pct .LoadShedStats.SizeInFlight .LoadShedStats.MaxSizeInFlight}}%) </td>
       </tr>
+      {{with .DBInfo}}
+        <tr>
+          <td>DB Processes (waiting/total)</td>
+          <td>{{.NumWaiting}} / {{.NumTotal}}</td>
+        </tr>
+      {{end}}
       <tr>
         <td>Shedded Requests</td>
         <td>{{.LoadShedStats.RequestsShed}} / {{.LoadShedStats.RequestsTotal}}