@@ -27,6 +27,7 @@ import (
2727
2828 "istio.io/istio/mixer/adapter/svcctrl/config"
2929 "istio.io/istio/mixer/pkg/adapter"
30+ "istio.io/istio/mixer/pkg/cache"
3031 "istio.io/istio/mixer/pkg/status"
3132 "istio.io/istio/mixer/template/apikey"
3233)
@@ -35,9 +36,19 @@ import (
3536type checkImpl struct {
3637 env adapter.Env
3738 checkResultExpiration time.Duration
38- runtimeConfig * config.RuntimeConfig
39- serviceConfig * config.GcpServiceSetting
40- client serviceControlClient
39+ // A LRU cache, keyed by checkCacheKey struct and value is of type *sc.CheckResponse
40+ responseCache cache.ExpiringCache
41+ runtimeConfig * config.RuntimeConfig
42+ serviceConfig * config.GcpServiceSetting
43+ client serviceControlClient
44+ }
45+
46+ // Cache key used with checkImpl.responseCache. The cache is at handler level, so it stores check responses for multiple
47+ // GCP services.
48+ type checkCacheKey struct {
49+ googleServiceName string
50+ consumerID string
51+ operation string
4152}
4253
4354// ProcessCheck processes check call and converts CheckResponse to adapter.CheckResult.
@@ -48,21 +59,10 @@ func (c *checkImpl) ProcessCheck(ctx context.Context, instance *apikey.Instance)
4859 fmt .Sprintf (
4960 "instance:%s, api key and api operation must not be empty" , instance .Name ))), nil
5061 }
51-
5262 consumerID := generateConsumerIDFromAPIKey (instance .ApiKey )
5363 response , err := c .doCheck (consumerID , instance .ApiOperation , instance .Timestamp )
5464 if err != nil {
55- return c .checkResult (
56- rpc.Status {
57- Code : int32 (rpc .PERMISSION_DENIED ),
58- Message : err .Error (),
59- }), nil
60- }
61-
62- if c .env .Logger ().VerbosityLevel (logDebug ) {
63- if responseDetail , err := toFormattedJSON (response ); err == nil {
64- c .env .Logger ().Infof ("response: %v" , string (responseDetail ))
65- }
65+ return c .checkResult (status .WithPermissionDenied (err .Error ())), nil
6666 }
6767
6868 return c .responseToCheckResult (response )
@@ -85,6 +85,17 @@ func (c *checkImpl) ResolveConsumerProjectID(consumerID, opName string) (string,
8585
8686// doCheck calls Check on Google ServiceControl client.
8787func (c * checkImpl ) doCheck (consumerID , operationName string , timestamp time.Time ) (* sc.CheckResponse , error ) {
88+ cacheKey := checkCacheKey {
89+ googleServiceName : c .serviceConfig .GoogleServiceName ,
90+ consumerID : consumerID ,
91+ operation : operationName ,
92+ }
93+
94+ cachedResponse , found := c .responseCache .Get (cacheKey )
95+ if found {
96+ return cachedResponse .(* sc.CheckResponse ), nil
97+ }
98+
8899 request := & sc.CheckRequest {
89100 Operation : & sc.Operation {
90101 OperationId : uuid .New (),
@@ -93,7 +104,26 @@ func (c *checkImpl) doCheck(consumerID, operationName string, timestamp time.Tim
93104 ConsumerId : consumerID ,
94105 },
95106 }
96- return c .client .Check (c .serviceConfig .GoogleServiceName , request )
107+
108+ if c .env .Logger ().VerbosityLevel (logDebug ) {
109+ if requestDetail , err := toFormattedJSON (request ); err == nil {
110+ c .env .Logger ().Infof ("request: %v" , string (requestDetail ))
111+ }
112+ }
113+
114+ response , err := c .client .Check (c .serviceConfig .GoogleServiceName , request )
115+ if err != nil {
116+ return nil , err
117+ }
118+
119+ if c .env .Logger ().VerbosityLevel (logDebug ) {
120+ if responseDetail , err := toFormattedJSON (response ); err == nil {
121+ c .env .Logger ().Infof ("response: %v" , string (responseDetail ))
122+ }
123+ }
124+
125+ c .responseCache .Set (cacheKey , response )
126+ return response , nil
97127}
98128
99129// responseToCheckResult converts ServiceControl CheckResponse to Mixer CheckerResult
@@ -132,6 +162,7 @@ func newCheckProcessor(meshServiceName string, ctx *handlerContext) (*checkImpl,
132162 return & checkImpl {
133163 ctx .env ,
134164 toDuration (ctx .config .RuntimeConfig .CheckResultExpiration ),
165+ ctx .checkResponseCache ,
135166 ctx .config .RuntimeConfig ,
136167 serviceConfig ,
137168 ctx .client ,
0 commit comments