git-pr
created pr with
56.1
added 56.2
1: 0200c93 ! 1: a2710a3 refactor: custom index page
added 56.3
1: a2710a3 < -: ------- refactor: custom index page
-: ------- > 1: 7338b44 feat: allow config `desc` to add a description box to index page
added 56.4
1: 7338b44 < -: ------- feat: allow config `desc` to add a description box to index page
-: ------- > 1: 26daea4 feat(pgs): lru cache for object info and special files
-: ------- > 2: b004b64 chore(pgs): use http cache clear event to rm lru cache for special files
-: ------- > 3: 59f5618 refactor(pgs): store lru cache on web router
changed status to
accepted
cmds
checkout latest patchset:
ssh pr.pico.sh print 56 | git am -3checkout any patchset in a patch request:
ssh pr.pico.sh print 56.[rev] | git am -3add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 56set PR to open (enables RSS notifications):
ssh pr.pico.sh pr open 56set PR to draft (stops RSS notifications):
ssh pr.pico.sh pr draft 56
Patchset
56.4
refactor(pgs): store lru cache on web router
Eric Bower
2025-04-06T19:07:36ZTests were failing because the cache was colliding during tests
Semantic diff summary
0 added,
7 modified,
0 signature changed,
0 removed
across 3 analyzed files
+12
-6
pkg/apps/pgs/web.go
#
| ... | ... | @@ -21,6 +21,8 @@ import ( | |
| 21 | 21 | "github.com/darkweak/souin/plugins/souin/storages" | |
| 22 | 22 | "github.com/darkweak/storages/core" | |
| 23 | 23 | "github.com/gorilla/feeds" | |
| 24 | + | "github.com/hashicorp/golang-lru/v2/expirable" | |
| 25 | + | "github.com/picosh/pico/pkg/cache" | |
| 24 | 26 | "github.com/picosh/pico/pkg/db" | |
| 25 | 27 | sst "github.com/picosh/pico/pkg/pobj/storage" | |
| 26 | 28 | "github.com/picosh/pico/pkg/shared" |
| ... | ... | @@ -93,14 +95,18 @@ func StartApiServer(cfg *PgsConfig) { | |
| 93 | 95 | type HasPerm = func(proj *db.Project) bool | |
| 94 | 96 | ||
| 95 | 97 | type WebRouter struct { | |
| 96 | - | Cfg *PgsConfig | |
| 97 | - | RootRouter *http.ServeMux | |
| 98 | - | UserRouter *http.ServeMux | |
| 98 | + | Cfg *PgsConfig | |
| 99 | + | RootRouter *http.ServeMux | |
| 100 | + | UserRouter *http.ServeMux | |
| 101 | + | RedirectsCache *expirable.LRU[string, []*RedirectRule] | |
| 102 | + | HeadersCache *expirable.LRU[string, []*HeaderRule] | |
| 99 | 103 | } | |
| 100 | 104 | ||
| 101 | 105 | func NewWebRouter(cfg *PgsConfig) *WebRouter { | |
| 102 | 106 | router := &WebRouter{ | |
| 103 | - | Cfg: cfg, | |
| 107 | + | Cfg: cfg, | |
| 108 | + | RedirectsCache: expirable.NewLRU[string, []*RedirectRule](2048, nil, cache.CacheTimeout), | |
| 109 | + | HeadersCache: expirable.NewLRU[string, []*HeaderRule](2048, nil, cache.CacheTimeout), | |
| 104 | 110 | } | |
| 105 | 111 | router.initRouters() | |
| 106 | 112 | return router |
| ... | ... | @@ -513,9 +519,9 @@ func (web *WebRouter) ServeAsset(fname string, opts *storage.ImgProcessOpts, fro | |
| 513 | 519 | go func() { | |
| 514 | 520 | for key := range web.Cfg.CacheClearingQueue { | |
| 515 | 521 | rKey := filepath.Join(key, "_redirects") | |
| 516 | - | redirectsCache.Remove(rKey) | |
| 522 | + | web.RedirectsCache.Remove(rKey) | |
| 517 | 523 | hKey := filepath.Join(key, "_headers") | |
| 518 | - | headersCache.Remove(hKey) | |
| 524 | + | web.HeadersCache.Remove(hKey) | |
| 519 | 525 | } | |
| 520 | 526 | }() | |
| 521 | 527 |
+5
-11
pkg/apps/pgs/web_asset_handler.go
#
| ... | ... | @@ -14,17 +14,10 @@ import ( | |
| 14 | 14 | "net/http/httputil" | |
| 15 | 15 | _ "net/http/pprof" | |
| 16 | 16 | ||
| 17 | - | "github.com/hashicorp/golang-lru/v2/expirable" | |
| 18 | - | "github.com/picosh/pico/pkg/cache" | |
| 19 | 17 | sst "github.com/picosh/pico/pkg/pobj/storage" | |
| 20 | 18 | "github.com/picosh/pico/pkg/shared/storage" | |
| 21 | 19 | ) | |
| 22 | 20 | ||
| 23 | - | var ( | |
| 24 | - | redirectsCache = expirable.NewLRU[string, []*RedirectRule](2048, nil, cache.CacheTimeout) | |
| 25 | - | headersCache = expirable.NewLRU[string, []*HeaderRule](2048, nil, cache.CacheTimeout) | |
| 26 | - | ) | |
| 27 | - | ||
| 28 | 21 | type ApiAssetHandler struct { | |
| 29 | 22 | *WebRouter | |
| 30 | 23 | Logger *slog.Logger |
| ... | ... | @@ -50,7 +43,8 @@ func (h *ApiAssetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
| 50 | 43 | var redirects []*RedirectRule | |
| 51 | 44 | ||
| 52 | 45 | redirectsCacheKey := filepath.Join(getSurrogateKey(h.UserID, h.ProjectDir), "_redirects") | |
| 53 | - | if cachedRedirects, found := redirectsCache.Get(redirectsCacheKey); found { | |
| 46 | + | if cachedRedirects, found := h.RedirectsCache.Get(redirectsCacheKey); found { | |
| 47 | + | fmt.Println(cachedRedirects) | |
| 54 | 48 | redirects = cachedRedirects | |
| 55 | 49 | } else { | |
| 56 | 50 | redirectFp, redirectInfo, err := h.Cfg.Storage.GetObject(h.Bucket, filepath.Join(h.ProjectDir, "_redirects")) |
| ... | ... | @@ -77,7 +71,7 @@ func (h *ApiAssetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
| 77 | 71 | } | |
| 78 | 72 | } | |
| 79 | 73 | ||
| 80 | - | redirectsCache.Add(redirectsCacheKey, redirects) | |
| 74 | + | h.RedirectsCache.Add(redirectsCacheKey, redirects) | |
| 81 | 75 | } | |
| 82 | 76 | ||
| 83 | 77 | routes := calcRoutes(h.ProjectDir, h.Filepath, redirects) |
| ... | ... | @@ -180,7 +174,7 @@ func (h *ApiAssetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
| 180 | 174 | var headers []*HeaderRule | |
| 181 | 175 | ||
| 182 | 176 | headersCacheKey := filepath.Join(getSurrogateKey(h.UserID, h.ProjectDir), "_headers") | |
| 183 | - | if cachedHeaders, found := headersCache.Get(headersCacheKey); found { | |
| 177 | + | if cachedHeaders, found := h.HeadersCache.Get(headersCacheKey); found { | |
| 184 | 178 | headers = cachedHeaders | |
| 185 | 179 | } else { | |
| 186 | 180 | headersFp, headersInfo, err := h.Cfg.Storage.GetObject(h.Bucket, filepath.Join(h.ProjectDir, "_headers")) |
+1
-1
pkg/apps/pgs/web_test.go
#
| ... | ... | @@ -329,7 +329,7 @@ func TestApiBasic(t *testing.T) { | |
| 329 | 329 | ||
| 330 | 330 | ct := responseRecorder.Header().Get("content-type") | |
| 331 | 331 | if ct != tc.contentType { | |
| 332 | - | t.Errorf("Want status '%s', got '%s'", tc.contentType, ct) | |
| 332 | + | t.Errorf("Want content type '%s', got '%s'", tc.contentType, ct) | |
| 333 | 333 | } | |
| 334 | 334 | ||
| 335 | 335 | body := strings.TrimSpace(responseRecorder.Body.String()) |