[pkgsite] internal/api: set cache-control headers

4 views
Skip to first unread message

Jonathan Amsterdam (Gerrit)

unread,
Apr 7, 2026, 7:15:07 PM (2 days ago) Apr 7
to Hyang-Ah Hana Kim, Ethan Lee, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
Attention needed from Ethan Lee and Hyang-Ah Hana Kim

Jonathan Amsterdam has uploaded the change for review

Jonathan Amsterdam would like Hyang-Ah Hana Kim and Ethan Lee to review this change.

Commit message

internal/api: set cache-control headers

Set an HTTP Cache-Control header for all API responses.

Since requests that reference a specific, numbered version apparently
always produce the same response, it is tempting to use the "immutable"
Cache-Control directive so these pages can be cached indefinitely. But
occasionally we must exclude a module. It would be unfortunate if the
module's data lived in caches forever. Instead, we cache such pages for
one day.

Pages that are subject to more rapid change, like those with versions
"latest", "master" and so on, or those that depend on data other than
a module (imported-by, search, etc.) are cached for an hour.
That is an arbitrary value that seems like a good compromise, since
the likelihood of a particular page's value changing in an hour is low.
Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9

Change diff

diff --git a/internal/api/api.go b/internal/api/api.go
index 831b1af..d5d812b 100644
--- a/internal/api/api.go
+++ b/internal/api/api.go
@@ -12,6 +12,7 @@
"net/http"
"strconv"
"strings"
+ "time"

"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/derrors"
@@ -69,7 +70,8 @@
return err
}

- return serveJSON(w, http.StatusOK, resp)
+ //
+ return serveJSON(w, http.StatusOK, resp, immutableVersion(params.Version))
}

// ServeModule handles requests for the v1 module metadata endpoint.
@@ -90,6 +92,8 @@
if requestedVersion == "" {
requestedVersion = version.Latest
}
+ // The served response is immutable if and only if the version is.
+ immutable := immutableVersion(requestedVersion)

// For modules, we can use GetUnitMeta on the module path.
um, err := ds.GetUnitMeta(r.Context(), modulePath, modulePath, requestedVersion)
@@ -111,7 +115,7 @@
}

if !params.Readme && !params.Licenses {
- return serveJSON(w, http.StatusOK, resp)
+ return serveJSON(w, http.StatusOK, resp, immutable)
}

fs := internal.MinimalFields
@@ -123,7 +127,7 @@
}
unit, err := ds.GetUnit(r.Context(), um, fs, internal.BuildContext{})
if err != nil {
- return serveJSON(w, http.StatusOK, resp)
+ return serveJSON(w, http.StatusOK, resp, immutable)
}

if params.Readme && unit.Readme != nil {
@@ -142,7 +146,7 @@
}
}

- return serveJSON(w, http.StatusOK, resp)
+ return serveJSON(w, http.StatusOK, resp, immutable)
}

// ServeModuleVersions handles requests for the v1 module versions endpoint.
@@ -179,7 +183,8 @@
return err
}

- return serveJSON(w, http.StatusOK, resp)
+ // The response is never immutable, because a new version can arrive at any time.
+ return serveJSON(w, http.StatusOK, resp, false)
}

// ServeModulePackages handles requests for the v1 module packages endpoint.
@@ -225,7 +230,7 @@
return err
}

- return serveJSON(w, http.StatusOK, resp)
+ return serveJSON(w, http.StatusOK, resp, immutableVersion(requestedVersion))
}

// ServeSearch handles requests for the v1 search endpoint.
@@ -270,7 +275,11 @@
return fmt.Errorf("%w: %s", derrors.InvalidArgument, err.Error())
}

- return serveJSON(w, http.StatusOK, resp)
+ // Search results are never immutable, because new modules are always being added.
+ // NOTE: the default cache freshness is set to 1 hour (see serverJSON). This seems
+ // like a reasonable time to cache a search, but be aware of complaints
+ // about stale search results.
+ return serveJSON(w, http.StatusOK, resp, false)
}

// ServePackageSymbols handles requests for the v1 package symbols endpoint.
@@ -318,7 +327,7 @@
return err
}

- return serveJSON(w, http.StatusOK, resp)
+ return serveJSON(w, http.StatusOK, resp, immutableVersion(params.Version))
}

// ServePackageImportedBy handles requests for the v1 package imported-by endpoint.
@@ -381,7 +390,8 @@
},
}

- return serveJSON(w, http.StatusOK, resp)
+ // The imported-by list is not immutable, because new modules are always being added.
+ return serveJSON(w, http.StatusOK, resp, false)
}

// ServeVulnerabilities handles requests for the v1 module vulnerabilities endpoint.
@@ -428,7 +438,7 @@
return err
}

- return serveJSON(w, http.StatusOK, resp)
+ return serveJSON(w, http.StatusOK, resp, immutableVersion(requestedVersion))
}
}

@@ -483,12 +493,32 @@
return um, nil
}

-func serveJSON(w http.ResponseWriter, status int, data any) error {
+// Values for the Cache-Control header.
+// Compare with the TTLs for pkgsite's own cache, in internal/frontend/server.go
+// (look for symbols ending in "TTL").
+// Those values are shorter to manage our cache's memory, but the job of
+// Cache-Control is to reduce network traffic; downstream caches can manage
+// their own memory.
+const (
+ // Immutable pages can theoretically, be cached indefinitely,
+ // but have them time out so that excluded modules don't
+ // live in caches forever.
+ longFreshness = 24 * time.Hour
+ // The information on some pages can change relatively quickly.
+ shortFreshness = 1 * time.Hour
+)
+
+func serveJSON(w http.ResponseWriter, status int, data any, immutable bool) error {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(data); err != nil {
return err
}
w.Header().Set("Content-Type", "application/json")
+ freshness := longFreshness
+ if !immutable {
+ freshness = shortFreshness
+ }
+ w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%.0f", freshness.Seconds()))
w.WriteHeader(status)
_, err := w.Write(buf.Bytes())
return err
@@ -503,7 +533,7 @@
Message: err.Error(),
}
}
- return serveJSON(w, aerr.Code, aerr)
+ return serveJSON(w, aerr.Code, aerr, false)
}

// paginate returns a paginated response for the given list of items and pagination parameters.
@@ -629,3 +659,8 @@
}
return sb.String(), nil
}
+
+// immutableVersion reports whether a module version is immutable.
+func immutableVersion(v string) bool {
+ return !(v == "" || v == version.Latest || internal.DefaultBranches[v] || stdlib.SupportedBranches[v])
+}
diff --git a/internal/api/api_test.go b/internal/api/api_test.go
index 36066f4..05441b4 100644
--- a/internal/api/api_test.go
+++ b/internal/api/api_test.go
@@ -965,3 +965,58 @@
}
return nil, errors.Join(err1, err2)
}
+
+func TestCacheControl(t *testing.T) {
+ ctx := context.Background()
+ ds := fakedatasource.New()
+ const modulePath = "example.com"
+ for _, v := range []string{"v1.0.0", "master"} {
+ ds.MustInsertModule(ctx, &internal.Module{
+ ModuleInfo: internal.ModuleInfo{
+ ModulePath: modulePath,
+ Version: v,
+ },
+ Units: []*internal.Unit{{
+ UnitMeta: internal.UnitMeta{
+ Path: modulePath,
+ ModuleInfo: internal.ModuleInfo{
+ ModulePath: modulePath,
+ Version: v,
+ },
+ },
+ }},
+ })
+ }
+
+ for _, test := range []struct {
+ version string
+ want string
+ }{
+ {"v1.0.0", "public, max-age=86400"},
+ {"latest", "public, max-age=3600"},
+ {"master", "public, max-age=3600"},
+ {"", "public, max-age=3600"},
+ } {
+ t.Run(test.version, func(t *testing.T) {
+ url := "/v1/module/" + modulePath
+ if test.version != "" {
+ url += "?version=" + test.version
+ }
+ r := httptest.NewRequest("GET", url, nil)
+ w := httptest.NewRecorder()
+
+ if err := ServeModule(w, r, ds); err != nil {
+ t.Fatal(err)
+ }
+
+ if w.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d", w.Code, http.StatusOK)
+ }
+
+ got := w.Header().Get("Cache-Control")
+ if got != test.want {
+ t.Errorf("Cache-Control = %q, want %q", got, test.want)
+ }
+ })
+ }
+}

Change information

Files:
  • M internal/api/api.go
  • M internal/api/api_test.go
Change size: M
Delta: 2 files changed, 102 insertions(+), 12 deletions(-)
Open in Gerrit

Related details

Attention is currently required from:
  • Ethan Lee
  • Hyang-Ah Hana Kim
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
  • requirement is not satisfiedkokoro-CI-Passes
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: pkgsite
Gerrit-Branch: master
Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
Gerrit-Change-Number: 763782
Gerrit-PatchSet: 1
Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
Gerrit-Reviewer: Ethan Lee <etha...@google.com>
Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
Gerrit-Attention: Hyang-Ah Hana Kim <hya...@gmail.com>
Gerrit-Attention: Ethan Lee <etha...@google.com>
unsatisfied_requirement
satisfied_requirement
open
diffy

kokoro (Gerrit)

unread,
Apr 7, 2026, 7:43:02 PM (2 days ago) Apr 7
to Jonathan Amsterdam, goph...@pubsubhelper.golang.org, Ethan Lee, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
Attention needed from Ethan Lee, Hyang-Ah Hana Kim and Jonathan Amsterdam

kokoro voted kokoro-CI+1

Kokoro presubmit build finished with status: SUCCESS
Logs at: https://source.cloud.google.com/results/invocations/de7d8eb2-92f3-4e93-8355-588a07b25a87

kokoro-CI+1
Open in Gerrit

Related details

Attention is currently required from:
  • Ethan Lee
  • Hyang-Ah Hana Kim
  • Jonathan Amsterdam
Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    • requirement satisfiedkokoro-CI-Passes
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: pkgsite
    Gerrit-Branch: master
    Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
    Gerrit-Change-Number: 763782
    Gerrit-PatchSet: 1
    Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
    Gerrit-Reviewer: Ethan Lee <etha...@google.com>
    Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
    Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
    Gerrit-Reviewer: kokoro <noreply...@google.com>
    Gerrit-CC: kokoro <noreply...@google.com>
    Gerrit-Attention: Hyang-Ah Hana Kim <hya...@gmail.com>
    Gerrit-Attention: Jonathan Amsterdam <j...@google.com>
    Gerrit-Attention: Ethan Lee <etha...@google.com>
    Gerrit-Comment-Date: Tue, 07 Apr 2026 23:42:57 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: Yes
    unsatisfied_requirement
    satisfied_requirement
    open
    diffy

    Ethan Lee (Gerrit)

    unread,
    Apr 8, 2026, 11:01:46 AM (15 hours ago) Apr 8
    to Jonathan Amsterdam, goph...@pubsubhelper.golang.org, Go LUCI, kokoro, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
    Attention needed from Hyang-Ah Hana Kim and Jonathan Amsterdam

    Ethan Lee added 4 comments

    File internal/api/api.go
    Line 73, Patchset 1 (Latest): //
    Ethan Lee . unresolved

    nit: remove comment

    Line 279, Patchset 1 (Latest): // NOTE: the default cache freshness is set to 1 hour (see serverJSON). This seems
    Ethan Lee . unresolved

    nit: serveJson

    Line 521, Patchset 1 (Latest): w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%.0f", freshness.Seconds()))
    Ethan Lee . unresolved

    nit: Can we cast seconds to an integer and use `%d`.

    Line 527, Patchset 1 (Latest):func ServeError(w http.ResponseWriter, err error) error {
    Ethan Lee . unresolved

    Currently, `ServeError` defaults to a 1 hour "short" freshness. There is a risk that transient server errors will be cached by downstream proxies even when the serve recovers. We should use `no-store` or a very short TTL (1 minute) for error responses.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Hyang-Ah Hana Kim
    • Jonathan Amsterdam
    Submit Requirements:
      • requirement is not satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement is not satisfiedReview-Enforcement
      • requirement satisfiedTryBots-Pass
      • requirement satisfiedkokoro-CI-Passes
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: pkgsite
      Gerrit-Branch: master
      Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
      Gerrit-Change-Number: 763782
      Gerrit-PatchSet: 1
      Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
      Gerrit-Reviewer: Ethan Lee <etha...@google.com>
      Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
      Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
      Gerrit-Reviewer: kokoro <noreply...@google.com>
      Gerrit-CC: kokoro <noreply...@google.com>
      Gerrit-Attention: Hyang-Ah Hana Kim <hya...@gmail.com>
      Gerrit-Attention: Jonathan Amsterdam <j...@google.com>
      Gerrit-Comment-Date: Wed, 08 Apr 2026 15:01:39 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      unsatisfied_requirement
      satisfied_requirement
      open
      diffy

      Jonathan Amsterdam (Gerrit)

      unread,
      Apr 8, 2026, 11:41:20 AM (14 hours ago) Apr 8
      to goph...@pubsubhelper.golang.org, Go LUCI, kokoro, Ethan Lee, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
      Attention needed from Ethan Lee and Hyang-Ah Hana Kim

      Jonathan Amsterdam added 4 comments

      File internal/api/api.go
      Line 73, Patchset 1: //
      Ethan Lee . resolved

      nit: remove comment

      Jonathan Amsterdam

      Done

      Line 279, Patchset 1: // NOTE: the default cache freshness is set to 1 hour (see serverJSON). This seems
      Ethan Lee . resolved

      nit: serveJson

      Jonathan Amsterdam

      Done

      Line 521, Patchset 1: w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%.0f", freshness.Seconds()))
      Ethan Lee . resolved

      nit: Can we cast seconds to an integer and use `%d`.

      Jonathan Amsterdam

      Done

      Line 527, Patchset 1:func ServeError(w http.ResponseWriter, err error) error {
      Ethan Lee . resolved

      Currently, `ServeError` defaults to a 1 hour "short" freshness. There is a risk that transient server errors will be cached by downstream proxies even when the serve recovers. We should use `no-store` or a very short TTL (1 minute) for error responses.

      Jonathan Amsterdam

      Done

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Ethan Lee
      • Hyang-Ah Hana Kim
      Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
        Gerrit-Change-Number: 763782
        Gerrit-PatchSet: 2
        Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
        Gerrit-Reviewer: Ethan Lee <etha...@google.com>
        Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
        Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Hyang-Ah Hana Kim <hya...@gmail.com>
        Gerrit-Attention: Ethan Lee <etha...@google.com>
        Gerrit-Comment-Date: Wed, 08 Apr 2026 15:41:16 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: No
        Comment-In-Reply-To: Ethan Lee <etha...@google.com>
        unsatisfied_requirement
        satisfied_requirement
        open
        diffy

        Jonathan Amsterdam (Gerrit)

        unread,
        Apr 8, 2026, 11:41:21 AM (14 hours ago) Apr 8
        to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
        Attention needed from Ethan Lee and Hyang-Ah Hana Kim

        Jonathan Amsterdam uploaded new patchset

        Jonathan Amsterdam uploaded patch set #2 to this change.
        Following approvals got outdated and were removed:
        • TryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI
        • kokoro-CI-Passes: kokoro-CI+1 by kokoro
        Open in Gerrit

        Related details

        Attention is currently required from:
        • Ethan Lee
        • Hyang-Ah Hana Kim
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: newpatchset
        unsatisfied_requirement
        satisfied_requirement
        open
        diffy

        kokoro (Gerrit)

        unread,
        Apr 8, 2026, 12:07:44 PM (14 hours ago) Apr 8
        to Jonathan Amsterdam, goph...@pubsubhelper.golang.org, Go LUCI, Ethan Lee, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
        Attention needed from Ethan Lee, Hyang-Ah Hana Kim and Jonathan Amsterdam

        kokoro voted kokoro-CI+1

        Kokoro presubmit build finished with status: SUCCESS

        Attention is currently required from:
        • Ethan Lee
        • Hyang-Ah Hana Kim
        • Jonathan Amsterdam
        Submit Requirements:
          • requirement is not satisfiedCode-Review
          • requirement satisfiedNo-Unresolved-Comments
          • requirement is not satisfiedReview-Enforcement
          • requirement satisfiedTryBots-Pass
          • requirement satisfiedkokoro-CI-Passes
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: pkgsite
          Gerrit-Branch: master
          Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
          Gerrit-Change-Number: 763782
          Gerrit-PatchSet: 2
          Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
          Gerrit-Reviewer: Ethan Lee <etha...@google.com>
          Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
          Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
          Gerrit-Reviewer: kokoro <noreply...@google.com>
          Gerrit-CC: kokoro <noreply...@google.com>
          Gerrit-Attention: Hyang-Ah Hana Kim <hya...@gmail.com>
          Gerrit-Attention: Jonathan Amsterdam <j...@google.com>
          Gerrit-Attention: Ethan Lee <etha...@google.com>
          Gerrit-Comment-Date: Wed, 08 Apr 2026 16:07:39 +0000
          Gerrit-HasComments: No
          Gerrit-Has-Labels: Yes
          unsatisfied_requirement
          satisfied_requirement
          open
          diffy

          Jonathan Amsterdam (Gerrit)

          unread,
          Apr 8, 2026, 12:34:33 PM (14 hours ago) Apr 8
          to goph...@pubsubhelper.golang.org, kokoro, Go LUCI, Ethan Lee, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
          Attention needed from Ethan Lee and Hyang-Ah Hana Kim

          Jonathan Amsterdam voted Auto-Submit+1

          Auto-Submit+1
          Open in Gerrit

          Related details

          Attention is currently required from:
          • Ethan Lee
          • Hyang-Ah Hana Kim
          Submit Requirements:
          • requirement is not satisfiedCode-Review
          • requirement satisfiedNo-Unresolved-Comments
          • requirement is not satisfiedReview-Enforcement
          • requirement satisfiedTryBots-Pass
          • requirement satisfiedkokoro-CI-Passes
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: pkgsite
          Gerrit-Branch: master
          Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
          Gerrit-Change-Number: 763782
          Gerrit-PatchSet: 2
          Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
          Gerrit-Reviewer: Ethan Lee <etha...@google.com>
          Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
          Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
          Gerrit-Reviewer: kokoro <noreply...@google.com>
          Gerrit-CC: kokoro <noreply...@google.com>
          Gerrit-Attention: Hyang-Ah Hana Kim <hya...@gmail.com>
          Gerrit-Attention: Ethan Lee <etha...@google.com>
          Gerrit-Comment-Date: Wed, 08 Apr 2026 16:34:30 +0000
          Gerrit-HasComments: No
          Gerrit-Has-Labels: Yes
          unsatisfied_requirement
          satisfied_requirement
          open
          diffy

          Ethan Lee (Gerrit)

          unread,
          Apr 8, 2026, 12:47:32 PM (13 hours ago) Apr 8
          to Jonathan Amsterdam, goph...@pubsubhelper.golang.org, kokoro, Go LUCI, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
          Attention needed from Hyang-Ah Hana Kim and Jonathan Amsterdam

          Ethan Lee voted and added 2 comments

          Votes added by Ethan Lee

          Code-Review+2

          2 comments

          File internal/api/api.go
          Line 539, Patchset 2 (Latest): // Do not cache errors.
          Ethan Lee . unresolved

          nit: I think the variable name is enough here, we can remove this comment.

          Line 676, Patchset 2 (Latest):// immutableVersion reports whether a module version is immutable.
          func immutableVersion(v string) bool {

          return !(v == "" || v == version.Latest || internal.DefaultBranches[v] || stdlib.SupportedBranches[v])
          }
          Ethan Lee . unresolved

          nit: can we please inline this since it's only used here.

          Open in Gerrit

          Related details

          Attention is currently required from:
          • Hyang-Ah Hana Kim
          • Jonathan Amsterdam
          Submit Requirements:
          • requirement satisfiedCode-Review
          • requirement is not satisfiedNo-Unresolved-Comments
          • requirement satisfiedReview-Enforcement
          • requirement satisfiedTryBots-Pass
          • requirement satisfiedkokoro-CI-Passes
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: pkgsite
          Gerrit-Branch: master
          Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
          Gerrit-Change-Number: 763782
          Gerrit-PatchSet: 2
          Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
          Gerrit-Reviewer: Ethan Lee <etha...@google.com>
          Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
          Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
          Gerrit-Reviewer: kokoro <noreply...@google.com>
          Gerrit-CC: kokoro <noreply...@google.com>
          Gerrit-Attention: Hyang-Ah Hana Kim <hya...@gmail.com>
          Gerrit-Attention: Jonathan Amsterdam <j...@google.com>
          Gerrit-Comment-Date: Wed, 08 Apr 2026 16:47:29 +0000
          Gerrit-HasComments: Yes
          Gerrit-Has-Labels: Yes
          satisfied_requirement
          unsatisfied_requirement
          open
          diffy

          Jonathan Amsterdam (Gerrit)

          unread,
          Apr 8, 2026, 2:32:05 PM (12 hours ago) Apr 8
          to goph...@pubsubhelper.golang.org, Ethan Lee, kokoro, Go LUCI, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
          Attention needed from Hyang-Ah Hana Kim and Jonathan Amsterdam

          Jonathan Amsterdam added 2 comments

          File internal/api/api.go
          Line 539, Patchset 2: // Do not cache errors.
          Ethan Lee . resolved

          nit: I think the variable name is enough here, we can remove this comment.

          Jonathan Amsterdam

          Done

          Line 676, Patchset 2:// immutableVersion reports whether a module version is immutable.

          func immutableVersion(v string) bool {
          return !(v == "" || v == version.Latest || internal.DefaultBranches[v] || stdlib.SupportedBranches[v])
          }
          Ethan Lee . resolved

          nit: can we please inline this since it's only used here.

          Jonathan Amsterdam

          Done

          Open in Gerrit

          Related details

          Attention is currently required from:
          • Hyang-Ah Hana Kim
          • Jonathan Amsterdam
          Submit Requirements:
          • requirement satisfiedCode-Review
          • requirement satisfiedNo-Unresolved-Comments
          • requirement satisfiedReview-Enforcement
          • requirement is not satisfiedTryBots-Pass
          • requirement is not satisfiedkokoro-CI-Passes
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: pkgsite
          Gerrit-Branch: master
          Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
          Gerrit-Change-Number: 763782
          Gerrit-PatchSet: 3
          Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
          Gerrit-Reviewer: Ethan Lee <etha...@google.com>
          Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
          Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
          Gerrit-Reviewer: kokoro <noreply...@google.com>
          Gerrit-CC: kokoro <noreply...@google.com>
          Gerrit-Attention: Hyang-Ah Hana Kim <hya...@gmail.com>
          Gerrit-Attention: Jonathan Amsterdam <j...@google.com>
          Gerrit-Comment-Date: Wed, 08 Apr 2026 18:32:01 +0000
          satisfied_requirement
          unsatisfied_requirement
          open
          diffy

          Jonathan Amsterdam (Gerrit)

          unread,
          Apr 8, 2026, 2:32:28 PM (12 hours ago) Apr 8
          to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
          Attention needed from Hyang-Ah Hana Kim and Jonathan Amsterdam

          Jonathan Amsterdam uploaded new patchset

          Jonathan Amsterdam uploaded patch set #3 to this change.
          Following approvals got outdated and were removed:
          • TryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI
          • kokoro-CI-Passes: kokoro-CI+1 by kokoro
          Open in Gerrit

          Related details

          Attention is currently required from:
          • Hyang-Ah Hana Kim
          • Jonathan Amsterdam
          Submit Requirements:
          • requirement satisfiedCode-Review
          • requirement satisfiedNo-Unresolved-Comments
          • requirement satisfiedReview-Enforcement
          • requirement is not satisfiedTryBots-Pass
          • requirement is not satisfiedkokoro-CI-Passes
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: newpatchset
          satisfied_requirement
          unsatisfied_requirement
          open
          diffy

          kokoro (Gerrit)

          unread,
          Apr 8, 2026, 3:00:42 PM (11 hours ago) Apr 8
          to Jonathan Amsterdam, goph...@pubsubhelper.golang.org, Go LUCI, Ethan Lee, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
          Attention needed from Hyang-Ah Hana Kim and Jonathan Amsterdam

          kokoro voted kokoro-CI+1

          Kokoro presubmit build finished with status: SUCCESS

          Related details

          Attention is currently required from:
          • Hyang-Ah Hana Kim
          • Jonathan Amsterdam
          Submit Requirements:
            • requirement satisfiedCode-Review
            • requirement satisfiedNo-Unresolved-Comments
            • requirement satisfiedReview-Enforcement
            • requirement satisfiedTryBots-Pass
            • requirement satisfiedkokoro-CI-Passes
            Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
            Gerrit-MessageType: comment
            Gerrit-Project: pkgsite
            Gerrit-Branch: master
            Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
            Gerrit-Change-Number: 763782
            Gerrit-PatchSet: 3
            Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
            Gerrit-Reviewer: Ethan Lee <etha...@google.com>
            Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
            Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
            Gerrit-Reviewer: kokoro <noreply...@google.com>
            Gerrit-CC: kokoro <noreply...@google.com>
            Gerrit-Attention: Hyang-Ah Hana Kim <hya...@gmail.com>
            Gerrit-Attention: Jonathan Amsterdam <j...@google.com>
            Gerrit-Comment-Date: Wed, 08 Apr 2026 19:00:37 +0000
            Gerrit-HasComments: No
            Gerrit-Has-Labels: Yes
            satisfied_requirement
            open
            diffy

            Hyang-Ah Hana Kim (Gerrit)

            unread,
            Apr 8, 2026, 3:03:01 PM (11 hours ago) Apr 8
            to Jonathan Amsterdam, goph...@pubsubhelper.golang.org, Hyang-Ah Hana Kim, kokoro, Go LUCI, Ethan Lee, golang-co...@googlegroups.com
            Attention needed from Jonathan Amsterdam

            Hyang-Ah Hana Kim voted and added 1 comment

            Votes added by Hyang-Ah Hana Kim

            Code-Review+2

            1 comment

            File internal/api/api.go
            Line 505, Patchset 3 (Latest): longCacheDur = 24 * time.Hour
            Hyang-Ah Hana Kim . unresolved

            In module proxy, max cache ttl is 3hr. (in case we need to push bug fix or remove bad modules, etc)
            short cache ttl is 1~30min depending on cases (e.g. error is 1min). I don't know about shortCacheDur, but I think we can consider a shorter period for longCacheDur. (3hr?)


            Still we see significant cache hit rate. Not sure what the pkgsite api traffic pattern will be though.

            Open in Gerrit

            Related details

            Attention is currently required from:
            • Jonathan Amsterdam
            Submit Requirements:
            • requirement satisfiedCode-Review
            • requirement is not satisfiedNo-Unresolved-Comments
            • requirement satisfiedReview-Enforcement
            • requirement satisfiedTryBots-Pass
            • requirement satisfiedkokoro-CI-Passes
            Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
            Gerrit-MessageType: comment
            Gerrit-Project: pkgsite
            Gerrit-Branch: master
            Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
            Gerrit-Change-Number: 763782
            Gerrit-PatchSet: 3
            Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
            Gerrit-Reviewer: Ethan Lee <etha...@google.com>
            Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
            Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
            Gerrit-Reviewer: kokoro <noreply...@google.com>
            Gerrit-CC: kokoro <noreply...@google.com>
            Gerrit-Attention: Jonathan Amsterdam <j...@google.com>
            Gerrit-Comment-Date: Wed, 08 Apr 2026 19:02:57 +0000
            Gerrit-HasComments: Yes
            Gerrit-Has-Labels: Yes
            satisfied_requirement
            unsatisfied_requirement
            open
            diffy

            Jonathan Amsterdam (Gerrit)

            unread,
            Apr 8, 2026, 3:07:37 PM (11 hours ago) Apr 8
            to goph...@pubsubhelper.golang.org, Hyang-Ah Hana Kim, kokoro, Go LUCI, Ethan Lee, golang-co...@googlegroups.com

            Jonathan Amsterdam added 1 comment

            File internal/api/api.go
            Line 505, Patchset 3: longCacheDur = 24 * time.Hour
            Hyang-Ah Hana Kim . resolved

            In module proxy, max cache ttl is 3hr. (in case we need to push bug fix or remove bad modules, etc)
            short cache ttl is 1~30min depending on cases (e.g. error is 1min). I don't know about shortCacheDur, but I think we can consider a shorter period for longCacheDur. (3hr?)


            Still we see significant cache hit rate. Not sure what the pkgsite api traffic pattern will be though.

            Jonathan Amsterdam

            Done

            Open in Gerrit

            Related details

            Attention set is empty
            Submit Requirements:
            • requirement satisfiedCode-Review
            • requirement satisfiedNo-Unresolved-Comments
            • requirement satisfiedReview-Enforcement
            • requirement is not satisfiedTryBots-Pass
            • requirement is not satisfiedkokoro-CI-Passes
            Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
            Gerrit-MessageType: comment
            Gerrit-Project: pkgsite
            Gerrit-Branch: master
            Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
            Gerrit-Change-Number: 763782
            Gerrit-PatchSet: 4
            Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
            Gerrit-Reviewer: Ethan Lee <etha...@google.com>
            Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
            Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
            Gerrit-Reviewer: kokoro <noreply...@google.com>
            Gerrit-CC: kokoro <noreply...@google.com>
            Gerrit-Comment-Date: Wed, 08 Apr 2026 19:07:33 +0000
            Gerrit-HasComments: Yes
            Gerrit-Has-Labels: No
            Comment-In-Reply-To: Hyang-Ah Hana Kim <hya...@gmail.com>
            satisfied_requirement
            unsatisfied_requirement
            open
            diffy

            Jonathan Amsterdam (Gerrit)

            unread,
            Apr 8, 2026, 3:07:38 PM (11 hours ago) Apr 8
            to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

            Jonathan Amsterdam uploaded new patchset

            Jonathan Amsterdam uploaded patch set #4 to this change.
            Following approvals got outdated and were removed:
            • TryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI
            • kokoro-CI-Passes: kokoro-CI+1 by kokoro
            Open in Gerrit

            Related details

            Attention set is empty
            Submit Requirements:
            • requirement satisfiedCode-Review
            • requirement satisfiedNo-Unresolved-Comments
            • requirement satisfiedReview-Enforcement
            • requirement is not satisfiedTryBots-Pass
            • requirement is not satisfiedkokoro-CI-Passes
            Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
            Gerrit-MessageType: newpatchset
            satisfied_requirement
            unsatisfied_requirement
            open
            diffy

            kokoro (Gerrit)

            unread,
            Apr 8, 2026, 3:31:14 PM (11 hours ago) Apr 8
            to Jonathan Amsterdam, goph...@pubsubhelper.golang.org, Go LUCI, Hyang-Ah Hana Kim, Ethan Lee, golang-co...@googlegroups.com
            Attention needed from Jonathan Amsterdam

            kokoro voted kokoro-CI-1

            Kokoro presubmit build finished with status: FAILURE
            Logs at: https://source.cloud.google.com/results/invocations/f4ccdff1-c7bb-49df-90bd-9c685036d973

            kokoro-CI-1
            Open in Gerrit

            Related details

            Attention is currently required from:
            • Jonathan Amsterdam
            Submit Requirements:
              • requirement satisfiedCode-Review
              • requirement satisfiedNo-Unresolved-Comments
              • requirement satisfiedReview-Enforcement
              • requirement satisfiedTryBots-Pass
              • requirement is not satisfiedkokoro-CI-Passes
              Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
              Gerrit-MessageType: comment
              Gerrit-Project: pkgsite
              Gerrit-Branch: master
              Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
              Gerrit-Change-Number: 763782
              Gerrit-PatchSet: 4
              Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
              Gerrit-Reviewer: Ethan Lee <etha...@google.com>
              Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
              Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
              Gerrit-Reviewer: kokoro <noreply...@google.com>
              Gerrit-CC: kokoro <noreply...@google.com>
              Gerrit-Attention: Jonathan Amsterdam <j...@google.com>
              Gerrit-Comment-Date: Wed, 08 Apr 2026 19:31:10 +0000
              Gerrit-HasComments: No
              Gerrit-Has-Labels: Yes
              satisfied_requirement
              unsatisfied_requirement
              open
              diffy

              Jonathan Amsterdam (Gerrit)

              unread,
              Apr 8, 2026, 4:17:11 PM (10 hours ago) Apr 8
              to goph...@pubsubhelper.golang.org, kokoro, Go LUCI, Hyang-Ah Hana Kim, Ethan Lee, golang-co...@googlegroups.com

              Jonathan Amsterdam added 1 comment

              Patchset-level comments
              File-level comment, Patchset 4 (Latest):
              Jonathan Amsterdam . resolved

              kokoro rerun

              Open in Gerrit

              Related details

              Attention set is empty
              Submit Requirements:
              • requirement satisfiedCode-Review
              • requirement satisfiedNo-Unresolved-Comments
              • requirement satisfiedReview-Enforcement
              • requirement satisfiedTryBots-Pass
              • requirement is not satisfiedkokoro-CI-Passes
              Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
              Gerrit-MessageType: comment
              Gerrit-Project: pkgsite
              Gerrit-Branch: master
              Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
              Gerrit-Change-Number: 763782
              Gerrit-PatchSet: 4
              Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
              Gerrit-Reviewer: Ethan Lee <etha...@google.com>
              Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
              Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
              Gerrit-Reviewer: kokoro <noreply...@google.com>
              Gerrit-CC: kokoro <noreply...@google.com>
              Gerrit-Comment-Date: Wed, 08 Apr 2026 20:17:09 +0000
              Gerrit-HasComments: Yes
              Gerrit-Has-Labels: No
              satisfied_requirement
              unsatisfied_requirement
              open
              diffy

              Jonathan Amsterdam (Gerrit)

              unread,
              Apr 8, 2026, 4:35:33 PM (10 hours ago) Apr 8
              to goph...@pubsubhelper.golang.org, kokoro, Go LUCI, Hyang-Ah Hana Kim, Ethan Lee, golang-co...@googlegroups.com

              Jonathan Amsterdam voted TryBot-Bypass+1

              TryBot-Bypass+1
              Open in Gerrit

              Related details

              Attention set is empty
              Submit Requirements:
                • requirement satisfiedCode-Review
                • requirement satisfiedNo-Unresolved-Comments
                • requirement satisfiedReview-Enforcement
                • requirement satisfiedTryBots-Pass
                • requirement satisfiedkokoro-CI-Passes
                Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
                Gerrit-MessageType: comment
                Gerrit-Project: pkgsite
                Gerrit-Branch: master
                Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
                Gerrit-Change-Number: 763782
                Gerrit-PatchSet: 4
                Gerrit-Owner: Jonathan Amsterdam <j...@google.com>
                Gerrit-Reviewer: Ethan Lee <etha...@google.com>
                Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
                Gerrit-Reviewer: Jonathan Amsterdam <j...@google.com>
                Gerrit-Reviewer: kokoro <noreply...@google.com>
                Gerrit-CC: kokoro <noreply...@google.com>
                Gerrit-Comment-Date: Wed, 08 Apr 2026 20:35:30 +0000
                Gerrit-HasComments: No
                Gerrit-Has-Labels: Yes
                satisfied_requirement
                open
                diffy

                Jonathan Amsterdam (Gerrit)

                unread,
                Apr 8, 2026, 4:35:37 PM (10 hours ago) Apr 8
                to goph...@pubsubhelper.golang.org, golang-...@googlegroups.com, kokoro, Go LUCI, Hyang-Ah Hana Kim, Ethan Lee, golang-co...@googlegroups.com

                Jonathan Amsterdam submitted the change with unreviewed changes

                Unreviewed changes

                3 is the latest approved patch-set.
                The change was submitted with unreviewed changes in the following files:

                ```
                The name of the file: internal/api/api.go
                Insertions: 1, Deletions: 1.

                @@ -502,7 +502,7 @@

                // Immutable pages can theoretically, be cached indefinitely,
                 	// but have them time out so that excluded modules don't
                 	// live in caches forever.
                -	longCacheDur = 24 * time.Hour
                + longCacheDur = 3 * time.Hour

                // The information on some pages can change relatively quickly.
                 	shortCacheDur = 1 * time.Hour
                // Errors should not be cached.
                ```
                ```
                The name of the file: internal/api/api_test.go
                Insertions: 1, Deletions: 1.

                @@ -992,7 +992,7 @@
                version string
                want string
                }{
                - {"v1.0.0", "public, max-age=86400"},
                + {"v1.0.0", "public, max-age=10800"},

                {"latest", "public, max-age=3600"},
                 		{"master", "public, max-age=3600"},
                 		{"", "public, max-age=3600"},
                ```

                Change information

                Commit message:
                internal/api: set cache-control headers

                Set an HTTP Cache-Control header for all API responses.

                Since requests that reference a specific, numbered version apparently
                always produce the same response, it is tempting to use the "immutable"
                Cache-Control directive so these pages can be cached indefinitely. But
                occasionally we must exclude a module. It would be unfortunate if the
                module's data lived in caches forever. Instead, we cache such pages for
                one day.

                Pages that are subject to more rapid change, like those with versions
                "latest", "master" and so on, or those that depend on data other than
                a module (imported-by, search, etc.) are cached for an hour.
                That is an arbitrary value that seems like a good compromise, since
                the likelihood of a particular page's value changing in an hour is low.
                Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
                Reviewed-by: Ethan Lee <etha...@google.com>
                Reviewed-by: Hyang-Ah Hana Kim <hya...@gmail.com>
                TryBot-Bypass: Jonathan Amsterdam <j...@google.com>
                Files:
                • M internal/api/api.go
                • M internal/api/api_test.go
                Change size: M
                Delta: 2 files changed, 110 insertions(+), 12 deletions(-)
                Branch: refs/heads/master
                Submit Requirements:
                • requirement satisfiedCode-Review: +2 by Hyang-Ah Hana Kim, +2 by Ethan Lee
                • requirement satisfiedTryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI, TryBot-Bypass+1 by Jonathan Amsterdam
                • requirement satisfiedkokoro-CI-Passes: kokoro-CI-1 by kokoro, TryBot-Bypass+1 by Jonathan Amsterdam
                Open in Gerrit
                Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
                Gerrit-MessageType: merged
                Gerrit-Project: pkgsite
                Gerrit-Branch: master
                Gerrit-Change-Id: I21414c22c724220c993c1dd7e7a0b49074efd8b9
                Gerrit-Change-Number: 763782
                Gerrit-PatchSet: 5
                open
                diffy
                satisfied_requirement
                Reply all
                Reply to author
                Forward
                0 new messages