From 3be3441feb33c4cce72a855f14d0abdd1aa8bbe0 Mon Sep 17 00:00:00 2001 From: Nikita Velat Date: Thu, 29 Jun 2023 16:18:24 +0100 Subject: [PATCH] add a caching implementation for InstallationsService (#268) * add caching installation service * add license header * typo in sprintf * switch to time based cache --- githubapp/installations_caching.go | 78 ++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 + 3 files changed, 81 insertions(+) create mode 100644 githubapp/installations_caching.go diff --git a/githubapp/installations_caching.go b/githubapp/installations_caching.go new file mode 100644 index 000000000..d32d4d328 --- /dev/null +++ b/githubapp/installations_caching.go @@ -0,0 +1,78 @@ +// Copyright 2023 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package githubapp + +import ( + "context" + "fmt" + "time" + + ttlcache "github.com/patrickmn/go-cache" +) + +// NewCachingInstallationsService returns an InstallationsService that always queries GitHub. It should be created with +// a client that authenticates as the target. +// It uses a time based cache of the provided expiry/cleanup time to store app installation info for repositories +// or owners and returns the cached installation info when a cache hit exists. +func NewCachingInstallationsService(delegate InstallationsService, expiry, cleanup time.Duration) InstallationsService { + return &cachingInstallationsService{ + cache: ttlcache.New(expiry, cleanup), + delegate: delegate, + } +} + +type cachingInstallationsService struct { + cache *ttlcache.Cache + delegate InstallationsService +} + +func (c *cachingInstallationsService) ListAll(ctx context.Context) ([]Installation, error) { + // ListAll is not cached due to a lack of keys to retrieve from the cache. Returning all values in the cache is not + // always desirable + return c.delegate.ListAll(ctx) +} + +func (c *cachingInstallationsService) GetByOwner(ctx context.Context, owner string) (Installation, error) { + // if installation is in cache, return it + val, ok := c.cache.Get(owner) + if ok { + return val.(Installation), nil + } + + // otherwise, get installation info, save to cache, and return + install, err := c.delegate.GetByOwner(ctx, owner) + if err != nil { + return Installation{}, err + } + c.cache.Set(owner, install, ttlcache.DefaultExpiration) + return install, nil +} + +func (c *cachingInstallationsService) GetByRepository(ctx context.Context, owner, name string) (Installation, error) { + // if installation is in cache, return it + key := fmt.Sprintf("%s/%s", owner, name) + val, ok := c.cache.Get(key) + if ok { + return val.(Installation), nil + } + + // otherwise, get installation info, save to cache, and return + install, err := c.delegate.GetByRepository(ctx, owner, name) + if err != nil { + return Installation{}, err + } + c.cache.Set(key, install, ttlcache.DefaultExpiration) + return install, nil +} diff --git a/go.mod b/go.mod index fc7fc463c..1db079e62 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/google/go-github/v53 v53.2.0 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 github.com/hashicorp/golang-lru v0.6.0 + github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 github.com/rs/zerolog v1.29.1 diff --git a/go.sum b/go.sum index 5bca6f311..6d9f744fe 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,8 @@ github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZb github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=