Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(985)

Unified Diff: appengine/gaeconfig/default.go

Issue 2575383002: Add server/cache support to gaeconfig. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/gaeconfig/default.go
diff --git a/appengine/gaeconfig/default.go b/appengine/gaeconfig/default.go
index 18cd7db2fd97559735b62e9b06c743cae9f10e8a..869b558c5c23b682103e7bf8797f1b67dbfe69f3 100644
--- a/appengine/gaeconfig/default.go
+++ b/appengine/gaeconfig/default.go
@@ -7,23 +7,23 @@ package gaeconfig
import (
"errors"
"fmt"
- "net/http"
"os"
"path/filepath"
- "sync"
"time"
- "golang.org/x/net/context"
+ "github.com/luci/luci-go/common/config/impl/filesystem"
+ "github.com/luci/luci-go/server/config"
+ "github.com/luci/luci-go/server/config/caching"
+ "github.com/luci/luci-go/server/config/erroring"
+ "github.com/luci/luci-go/server/config/testconfig"
+ "github.com/luci/luci-go/server/config/textproto"
"github.com/luci/gae/service/info"
- "github.com/luci/luci-go/common/config"
- "github.com/luci/luci-go/common/config/impl/erroring"
- "github.com/luci/luci-go/common/config/impl/filesystem"
- "github.com/luci/luci-go/common/config/impl/remote"
- "github.com/luci/luci-go/server/auth"
+
+ "golang.org/x/net/context"
)
-// ErrNotConfigured is returned by methods of config.Interface object returned
+// ErrNotConfigured is returned by methods of config.Backend object returned
// by New if config service URL is not set. Usually happens for new apps.
var ErrNotConfigured = errors.New("config service URL is not set in settings")
@@ -31,21 +31,7 @@ var ErrNotConfigured = errors.New("config service URL is not set in settings")
// local dev appserver model. See New for details.
const devCfgDir = "devcfg"
-// implCache is used to avoid reallocating config.Interface implementation
-// during each request.
-//
-// config.Interface instances don't actually depend on the context and thus we
-// can share them between requests.
-//
-// Cache key is the current value of Settings struct. We don't bother to clean
-// up old entries, since in most cases there'll be none (the settings are mostly
-// static).
-var implCache struct {
- lock sync.RWMutex
- cache map[Settings]config.Interface
-}
-
-// New constructs default luci-config client.
+// Use installs the default luci-config client.
//
// The client is configured to use luci-config URL specified in the settings,
// using GAE app service account for authentication.
@@ -64,58 +50,61 @@ var implCache struct {
//
// Panics if it can't load the settings (should not happen since they are in
// the local memory cache usually).
-func New(c context.Context) config.Interface {
- settings, err := FetchCachedSettings(c)
- if err != nil {
- panic(err)
- }
+func Use(c context.Context) context.Context { return useImpl(c, nil) }
iannucci 2017/01/07 21:05:26 if you do the package renaming, this should move o
dnj 2017/01/10 03:30:07 I'll move to luci_config/appengine/gaeconfig.
- if settings.ConfigServiceURL == "" {
- if info.IsDevAppServer(c) {
- return devServerConfig()
- }
- return erroring.New(ErrNotConfigured)
- }
-
- return configImplForSettings(settings)
+func useImpl(c context.Context, backend config.Backend) context.Context {
+ return installConfigBackend(c, mustFetchCachedSettings(c), backend)
}
-// configImplForSettings returns config.Interface based on given settings.
-//
-// Split out from New to enforce that returned config.Interface doesn't depend
-// on the context (since this function doesn't accept a context).
-func configImplForSettings(settings Settings) config.Interface {
- implCache.lock.RLock()
- impl, ok := implCache.cache[settings]
- implCache.lock.RUnlock()
- if ok {
- return impl
+func installConfigBackend(c context.Context, s *Settings, backend config.Backend) context.Context {
+ if backend == nil {
+ // Non-testing, build a Backend.
+ backend = getPrimaryBackend(c, s)
}
- implCache.lock.Lock()
- defer implCache.lock.Unlock()
+ // Install a FormatRegistry. Register common config service protobufs with it.
+ c = withFormatRegistry(c, defaultFormatterRegistry())
- if impl, ok := implCache.cache[settings]; ok {
- return impl
+ backend = &config.FormatBackend{
+ Backend: backend,
+ GetRegistry: GetFormatterRegistry,
}
- impl = remote.New(settings.ConfigServiceURL+"/_ah/api/config/v1/", authenticatedClient)
- if settings.CacheExpirationSec != 0 {
- impl = WrapWithCache(impl, time.Duration(settings.CacheExpirationSec)*time.Second)
+ // Apply caching configuration.
+ exp := time.Duration(s.CacheExpirationSec) * time.Second
+ if exp > 0 {
+ // Add a ProcCache, backed by memcache.
+ backend = caching.ProcCache(backend, exp)
+ backend = memcacheBackend(backend, exp)
}
- if implCache.cache == nil {
- implCache.cache = make(map[Settings]config.Interface, 1)
+ c = config.WithBackend(c, backend)
+ return c
+}
+
+func getPrimaryBackend(c context.Context, settings *Settings) (backend config.Backend) {
+ // Identify our config service Backend (in testing, it will be supplied).
+ if settings.ConfigServiceURL == "" {
+ if info.IsDevAppServer(c) {
+ return devServerBackend()
+ }
+ return erroring.New(ErrNotConfigured)
}
- implCache.cache[settings] = impl
+ return &config.ClientBackend{&config.RemoteClientProvider{
+ BaseURL: settings.ConfigServiceURL,
+ }}
+}
- return impl
+func defaultFormatterRegistry() *config.FormatterRegistry {
+ var fr config.FormatterRegistry
+ textproto.RegisterFormatter(&fr)
+ return &fr
}
// devServerConfig returns config.Interface to use on a devserver.
//
// See New for details.
-func devServerConfig() config.Interface {
+func devServerBackend() config.Backend {
pwd := os.Getenv("PWD") // os.Getwd works funny with symlinks, use PWD
candidates := []string{
filepath.Join(pwd, devCfgDir),
@@ -127,20 +116,22 @@ func devServerConfig() config.Interface {
if err != nil {
return erroring.New(err)
}
- return fs
+ return &config.ClientBackend{&testconfig.LocalClientProvider{
+ Base: fs,
+ }}
}
}
return erroring.New(fmt.Errorf("luci-config: could not find local configs in any of %s", candidates))
}
-// authenticatedClient returns http.Client to use for making authenticated
-// request to the config service.
-//
-// The returned client uses GAE app's service account for authentication.
-func authenticatedClient(ctx context.Context) (*http.Client, error) {
- t, err := auth.GetRPCTransport(ctx, auth.AsSelf)
- if err != nil {
- return nil, err
- }
- return &http.Client{Transport: t}, nil
+var formatRegistryKey = "github.com/luci/luci-go/appengine/gaeconfig:formatRegistry"
+
+func withFormatRegistry(c context.Context, fr *config.FormatterRegistry) context.Context {
+ return context.WithValue(c, &formatRegistryKey, fr)
+}
+
+// GetFormatterRegistry is used to retrieve the config service format registry
+// from the supplied Context.
+func GetFormatterRegistry(c context.Context) *config.FormatterRegistry {
+ return c.Value(&formatRegistryKey).(*config.FormatterRegistry)
}

Powered by Google App Engine
This is Rietveld 408576698