From 74b5e4a6ab6f2d672ccc7a7ccdb252d5b930a2e9 Mon Sep 17 00:00:00 2001 From: Marcel Boehm Date: Thu, 12 Mar 2026 17:52:58 +0100 Subject: [PATCH] Implement readonly mode --- cmd/go-cache-plugin/commands.go | 1 + cmd/go-cache-plugin/setup.go | 3 +++ lib/gobuild/gobuild.go | 7 +++++++ lib/modproxy/modproxy.go | 7 +++++++ lib/revproxy/revproxy.go | 8 +++++++- 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cmd/go-cache-plugin/commands.go b/cmd/go-cache-plugin/commands.go index 0578f82..cc5ca0d 100644 --- a/cmd/go-cache-plugin/commands.go +++ b/cmd/go-cache-plugin/commands.go @@ -32,6 +32,7 @@ var flags struct { MinUploadSize int64 `flag:"min-upload-size,default=$GOCACHE_MIN_SIZE,Minimum object size to upload to S3 (in bytes)"` Concurrency int `flag:"c,default=$GOCACHE_CONCURRENCY,Maximum number of concurrent requests"` S3Concurrency int `flag:"u,default=$GOCACHE_S3_CONCURRENCY,Maximum concurrency for upload to S3"` + ReadOnly bool `flag:"read-only,default=$GOCACHE_READ_ONLY,Disable uploads to S3"` PrintMetrics bool `flag:"metrics,default=$GOCACHE_METRICS,Print summary metrics to stderr at exit"` Expiration time.Duration `flag:"expiry,default=$GOCACHE_EXPIRY,Cache expiration period (optional)"` Verbose bool `flag:"v,default=$GOCACHE_VERBOSE,Enable verbose logging"` diff --git a/cmd/go-cache-plugin/setup.go b/cmd/go-cache-plugin/setup.go index 2cbf559..2f1b529 100644 --- a/cmd/go-cache-plugin/setup.go +++ b/cmd/go-cache-plugin/setup.go @@ -78,6 +78,7 @@ func initCacheServer(env *command.Env) (*gocache.Server, *s3util.Client, error) S3Client: client, KeyPrefix: flags.KeyPrefix, MinUploadSize: flags.MinUploadSize, + ReadOnly: flags.ReadOnly, UploadConcurrency: flags.S3Concurrency, } cache.SetMetrics(env.Context(), expvar.NewMap("gocache_host")) @@ -120,6 +121,7 @@ func initModProxy(env *command.Env, s3c *s3util.Client) (_ http.Handler, cleanup Local: modCachePath, S3Client: s3c, KeyPrefix: path.Join(flags.KeyPrefix, "module"), + ReadOnly: flags.ReadOnly, MaxTasks: flags.S3Concurrency, Logf: vprintf, LogRequests: flags.DebugLog&debugModProxy != 0, @@ -202,6 +204,7 @@ func initRevProxy(env *command.Env, s3c *s3util.Client, g *taskgroup.Group) (htt Local: revCachePath, S3Client: s3c, KeyPrefix: path.Join(flags.KeyPrefix, "revproxy"), + ReadOnly: flags.ReadOnly, Logf: vprintf, LogRequests: flags.DebugLog&debugRevProxy != 0, } diff --git a/lib/gobuild/gobuild.go b/lib/gobuild/gobuild.go index 5592019..e0c0e15 100644 --- a/lib/gobuild/gobuild.go +++ b/lib/gobuild/gobuild.go @@ -67,6 +67,10 @@ type S3Cache struct { // which the cache will not write the object to S3. MinUploadSize int64 + // ReadOnly, if true, prevents the cache from writing any data back to S3. + // Data is still read from S3 and stored locally. + ReadOnly bool + // UploadConcurrency, if positive, defines the maximum number of concurrent // tasks for writing cache entries to S3. If zero or negative, it uses // runtime.NumCPU. @@ -155,6 +159,9 @@ func (s *S3Cache) Put(ctx context.Context, obj gocache.Object) (diskPath string, if err != nil { return "", err // don't bother trying to forward it to the remote } + if s.ReadOnly { + return diskPath, nil // don't write back to S3 + } if obj.Size < s.MinUploadSize { s.putSkipSmall.Add(1) return diskPath, nil // don't bother uploading this, it's too small diff --git a/lib/modproxy/modproxy.go b/lib/modproxy/modproxy.go index 889292c..1d312b0 100644 --- a/lib/modproxy/modproxy.go +++ b/lib/modproxy/modproxy.go @@ -61,6 +61,10 @@ type S3Cacher struct { // intervening slash. KeyPrefix string + // ReadOnly, if true, prevents the cacher from writing any data back to S3. + // Data is still read from S3 and stored locally. + ReadOnly bool + // MaxTasks, if positive, limits the number of concurrent tasks that may be // interacting with S3. If zero or negative, the default is // [runtime.NumCPU]. @@ -212,6 +216,9 @@ func (c *S3Cacher) Put(ctx context.Context, name string, data io.ReadSeeker) (oe c.putLocalHit.Add(1) return nil } + if c.ReadOnly { + return nil + } // Try to push the object to S3 in the background. f, size, err := openFileSize(path) diff --git a/lib/revproxy/revproxy.go b/lib/revproxy/revproxy.go index 8c0dae6..c67f619 100644 --- a/lib/revproxy/revproxy.go +++ b/lib/revproxy/revproxy.go @@ -84,6 +84,10 @@ type Server struct { // intervening slash. KeyPrefix string + // ReadOnly, if true, prevents the server from writing any data back to S3. + // Data is still read from S3 and stored locally. + ReadOnly bool + // Logf, if non-nil, is used to write log messages. If nil, logs are // discarded. Logf func(string, ...any) @@ -274,7 +278,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } else { s.rspSave.Add(1) s.rspSaveBytes.Add(int64(len(body))) - s.start(s.cacheStoreS3(hash, rsp.Header, body)) + if !s.ReadOnly { + s.start(s.cacheStoreS3(hash, rsp.Header, body)) + } } s.vlogf("rp E H:%s fetch RC:yes B:%d (%v elapsed)", hash, len(body), time.Since(start)) }