mirror of
https://gitea.com/gitea/runner.git
synced 2026-08-19 10:27:45 +00:00
be90c01468
The cache server retired entries 30 days after creation regardless of use, so a job that ran often enough to keep its cache warm still lost it on a fixed schedule. Nothing bounded the disk either. Retention now counts from last access alone, and a repository over its limit sheds least recently accessed entries until it fits, enforced on commit as well as on the periodic sweep. ```yaml cache: retention: 168h # remove entries not accessed for seven days repo_size_limit: 10GB # cap each repository size_limit: 0 # cap the whole cache, off by default sweep_interval: 1h # minimum time between sweeps ``` Sizes accept `10GB`, `512mb`, `1TiB` or a plain byte count, binary either way. Leave a key out for its default; `0` turns a limit off, and `0s` does the same for `retention`. Whatever these allow, the cache also sheds entries to keep free space above `health_check.min_free_disk_space_mb` when health checks are enabled, so it cannot grow past the point where the runner stops accepting work. Supporting fixes: serving an entry stamps its access time, so a find cannot hand a job a download URL for an entry the next eviction is about to remove; an entry larger than the limit is dropped on its own account rather than emptying its repository to make room; and a blob that cannot be unlinked keeps its row, so the next sweep retries instead of orphaning bytes no limit can account for. Closes https://gitea.com/gitea/runner/issues/1168 --------- Co-authored-by: silverwind <me@silverwind.io> Reviewed-on: https://gitea.com/gitea/runner/pulls/1170 Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com>
57 lines
2.0 KiB
Go
57 lines
2.0 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package artifactcache
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// The artifact half is forwarded under the Host Gitea knows itself by, so the URLs it hands back
|
|
// still point at Gitea, and nothing else is proxied.
|
|
func TestFrontResultsService(t *testing.T) {
|
|
var gotHost, gotPath, gotProto string
|
|
gitea := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotHost, gotPath, gotProto = r.Host, r.URL.Path, r.Header.Get("X-Forwarded-Proto")
|
|
_, _ = io.WriteString(w, `{"ok":true}`)
|
|
}))
|
|
defer gitea.Close()
|
|
|
|
handler, err := StartHandler(Options{Dir: t.TempDir(), OutboundIP: "127.0.0.1"})
|
|
require.NoError(t, err)
|
|
defer handler.Close()
|
|
const token = "forward-token"
|
|
|
|
client := &http.Client{Transport: &bearerTransport{token: token}}
|
|
post := func(path string) int {
|
|
req, err := http.NewRequestWithContext(t.Context(), http.MethodPost, handler.ExternalURL()+path, nil)
|
|
require.NoError(t, err)
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
resp.Body.Close()
|
|
return resp.StatusCode
|
|
}
|
|
|
|
assert.Equal(t, http.StatusNotFound, post(artifactServicePath+"CreateArtifact"),
|
|
"an unregistered token is forwarded nowhere")
|
|
|
|
defer handler.RegisterJob(token, JobCredential{Repo: "owner/repo", Results: gitea.URL})()
|
|
|
|
assert.Equal(t, http.StatusOK, post(artifactServicePath+"CreateArtifact"))
|
|
assert.Equal(t, strings.TrimPrefix(gitea.URL, "http://"), gotHost, "Gitea must see the host it mints its URLs from")
|
|
assert.Empty(t, gotProto, "a forwarded scheme would make an https Gitea mint http URLs")
|
|
assert.Equal(t, artifactServicePath+"CreateArtifact", gotPath)
|
|
|
|
gotPath = ""
|
|
assert.Equal(t, http.StatusNotFound, post("/twirp/github.actions.results.api.v1.OtherService/Do"))
|
|
assert.Equal(t, http.StatusNotFound, post("/api/v1/repos/owner/repo"))
|
|
assert.Empty(t, gotPath, "only the artifact service is forwarded")
|
|
}
|