aboutsummaryrefslogtreecommitdiffstats
path: root/dashboard/app/cache.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2021-03-25 19:01:14 +0100
committerDmitry Vyukov <dvyukov@google.com>2021-03-26 10:07:20 +0100
commit5f50b260efb9a858ad1a6c5041a8de08fac0f911 (patch)
tree7990f3658b5a3279de4e7f20f64674cdf60c839c /dashboard/app/cache.go
parent1e99e36f41fbce4e003dfb8e80810fe0b7da7981 (diff)
dashboard/app: update memcache with cron
Building the memcache object with bug stats takes significant time and periodically slows down user requests. Update it with cron ahead of time.
Diffstat (limited to 'dashboard/app/cache.go')
-rw-r--r--dashboard/app/cache.go54
1 files changed, 38 insertions, 16 deletions
diff --git a/dashboard/app/cache.go b/dashboard/app/cache.go
index 574324518..7040f65e8 100644
--- a/dashboard/app/cache.go
+++ b/dashboard/app/cache.go
@@ -9,6 +9,8 @@ import (
"time"
"golang.org/x/net/context"
+ "google.golang.org/appengine"
+ "google.golang.org/appengine/log"
"google.golang.org/appengine/memcache"
)
@@ -20,35 +22,43 @@ type Cached struct {
func CacheGet(c context.Context, r *http.Request, ns string) (*Cached, error) {
accessLevel := accessLevel(c, r)
- key := fmt.Sprintf("%v-%v", ns, accessLevel)
v := new(Cached)
- _, err := memcache.Gob.Get(c, key, v)
+ _, err := memcache.Gob.Get(c, cacheKey(ns, accessLevel), v)
if err != nil && err != memcache.ErrCacheMiss {
return nil, err
}
if err == nil {
return v, nil
}
- if v, err = buildCached(c, ns, accessLevel); err != nil {
+ bugs, _, err := loadNamespaceBugs(c, ns)
+ if err != nil {
return nil, err
}
- item := &memcache.Item{
- Key: key,
- Object: v,
- Expiration: time.Hour,
- }
- if err := memcache.Gob.Set(c, item); err != nil {
- return nil, err
+ return buildAndStoreCached(c, bugs, ns, accessLevel)
+}
+
+// cacheUpdate updates memcache every hour (called by cron.yaml).
+// Cache update is slow and we don't want to slow down user requests.
+func cacheUpdate(w http.ResponseWriter, r *http.Request) {
+ c := appengine.NewContext(r)
+ for ns := range config.Namespaces {
+ bugs, _, err := loadNamespaceBugs(c, ns)
+ if err != nil {
+ log.Errorf(c, "failed load ns=%v bugs: %v", ns, err)
+ continue
+ }
+ for _, accessLevel := range []AccessLevel{AccessPublic, AccessUser, AccessAdmin} {
+ _, err := buildAndStoreCached(c, bugs, ns, accessLevel)
+ if err != nil {
+ log.Errorf(c, "failed to build cached for ns=%v access=%v: %v", ns, accessLevel, err)
+ continue
+ }
+ }
}
- return v, nil
}
-func buildCached(c context.Context, ns string, accessLevel AccessLevel) (*Cached, error) {
+func buildAndStoreCached(c context.Context, bugs []*Bug, ns string, accessLevel AccessLevel) (*Cached, error) {
v := &Cached{}
- bugs, _, err := loadNamespaceBugs(c, ns)
- if err != nil {
- return nil, err
- }
for _, bug := range bugs {
switch bug.Status {
case BugStatusOpen:
@@ -66,5 +76,17 @@ func buildCached(c context.Context, ns string, accessLevel AccessLevel) (*Cached
v.Invalid++
}
}
+ item := &memcache.Item{
+ Key: cacheKey(ns, accessLevel),
+ Object: v,
+ Expiration: 4 * time.Hour, // supposed to be updated by cron every hour
+ }
+ if err := memcache.Gob.Set(c, item); err != nil {
+ return nil, err
+ }
return v, nil
}
+
+func cacheKey(ns string, accessLevel AccessLevel) string {
+ return fmt.Sprintf("%v-%v", ns, accessLevel)
+}