internal/worker: route to list jobs
Provide the "/jobs/list" route, which will write a simple
list of existing jobs.
Change-Id: Ibc16ed65b6209a84d6b95b32ddd6f6b837014a7c
Reviewed-on: https://go-review.googlesource.com/c/pkgsite-metrics/+/496187
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
diff --git a/internal/worker/jobs.go b/internal/worker/jobs.go
index e9bbf94..79076dc 100644
--- a/internal/worker/jobs.go
+++ b/internal/worker/jobs.go
@@ -15,12 +15,14 @@
package worker
import (
+ "bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
+ "time"
"golang.org/x/pkgsite-metrics/internal/derrors"
"golang.org/x/pkgsite-metrics/internal/jobs"
@@ -43,6 +45,7 @@
DeleteJob(ctx context.Context, id string) error
GetJob(ctx context.Context, id string) (*jobs.Job, error)
UpdateJob(ctx context.Context, id string, f func(*jobs.Job) error) error
+ ListJobs(context.Context, func(*jobs.Job, time.Time) error) error
}
func processJobRequest(ctx context.Context, w io.Writer, path, jobID string, db jobDB) error {
@@ -69,6 +72,21 @@
return nil
})
+ case "/list":
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "%-20s\tEnq\tCompl\tCanceled\n", "ID")
+ err := db.ListJobs(ctx, func(j *jobs.Job, _ time.Time) error {
+ _, err := fmt.Fprintf(&buf, "%-20s\t%3d\t%3d\t%t\n",
+ j.ID(), j.NumEnqueued, j.NumFailed+j.NumErrored+j.NumSucceeded,
+ j.Canceled)
+ return err
+ })
+ if err != nil {
+ return err
+ }
+ buf.WriteTo(w)
+ return nil
+
default:
return fmt.Errorf("unknown path %q: %w", path, derrors.InvalidArgument)
}
diff --git a/internal/worker/jobs_test.go b/internal/worker/jobs_test.go
index 806a30e..c682d71 100644
--- a/internal/worker/jobs_test.go
+++ b/internal/worker/jobs_test.go
@@ -9,10 +9,13 @@
"context"
"encoding/json"
"fmt"
+ "strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
+ "golang.org/x/exp/maps"
+ "golang.org/x/exp/slices"
"golang.org/x/pkgsite-metrics/internal/derrors"
"golang.org/x/pkgsite-metrics/internal/jobs"
)
@@ -49,6 +52,17 @@
if !got2.Canceled {
t.Error("got canceled false, want true")
}
+
+ buf.Reset()
+ if err := processJobRequest(ctx, &buf, "/list", "", db); err != nil {
+ t.Fatal(err)
+ }
+ // Don't check for specific output, just make sure there's something
+ // that mentions the job ID.
+ got3 := buf.String()
+ if !strings.Contains(got3, job.ID()) {
+ t.Errorf("got\n%q\nwhich does not contain the job ID %q", got3, job.ID())
+ }
}
type testJobDB struct {
@@ -90,3 +104,17 @@
d.jobs[id] = j
return nil
}
+
+func (d *testJobDB) ListJobs(ctx context.Context, f func(*jobs.Job, time.Time) error) error {
+ jobslice := maps.Values(d.jobs)
+ // Sort by StartedAt descending.
+ slices.SortFunc(jobslice, func(j1, j2 *jobs.Job) bool {
+ return j1.StartedAt.After(j2.StartedAt)
+ })
+ for _, j := range jobslice {
+ if err := f(j, time.Time{}); err != nil {
+ return err
+ }
+ }
+ return nil
+}