Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TT-8959/TT-9611] Add timeout to endpoint level cache config #5368

Merged
merged 1 commit into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apidef/api_definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ type CacheMeta struct {
Path string `bson:"path" json:"path"`
CacheKeyRegex string `bson:"cache_key_regex" json:"cache_key_regex"`
CacheOnlyResponseCodes []int `bson:"cache_response_codes" json:"cache_response_codes"`
Timeout int64 `bson:"timeout" json:"timeout"`
}

type RequestInputType string
Expand Down
2 changes: 2 additions & 0 deletions gateway/api_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ type EndPointCacheMeta struct {
Method string
CacheKeyRegex string
CacheOnlyResponseCodes []int
Timeout int64
}

type TransformSpec struct {
Expand Down Expand Up @@ -805,6 +806,7 @@ func (a APIDefinitionLoader) compileCachedPathSpec(oldpaths []string, newpaths [
newSpec.CacheConfig.Method = spec.Method
newSpec.CacheConfig.CacheKeyRegex = spec.CacheKeyRegex
newSpec.CacheConfig.CacheOnlyResponseCodes = spec.CacheOnlyResponseCodes
newSpec.CacheConfig.Timeout = spec.Timeout
// Extend with method actions
urlSpec = append(urlSpec, newSpec)
}
Expand Down
46 changes: 46 additions & 0 deletions gateway/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,52 @@ func TestOldCachePlugin(t *testing.T) {
})
}

func TestAdvanceCacheTimeoutPerEndpoint(t *testing.T) {
ts := StartTest(nil)
defer ts.Close()
cache := storage.RedisCluster{KeyPrefix: "cache-", RedisController: ts.Gw.RedisController}
defer cache.DeleteScanMatch("*")

extendedPaths := apidef.ExtendedPathsSet{
AdvanceCacheConfig: []apidef.CacheMeta{
{
Method: http.MethodGet,
Path: "/my-cached-endpoint",
},
},
}

api := BuildAPI(func(spec *APISpec) {
spec.Proxy.ListenPath = "/"
spec.CacheOptions = apidef.CacheOptions{
CacheTimeout: 0,
EnableCache: true,
}

UpdateAPIVersion(spec, "v1", func(v *apidef.VersionInfo) {
v.ExtendedPaths = extendedPaths
})
})[0]

ts.Gw.LoadAPI(api)

headerCache := map[string]string{"x-tyk-cached-response": "1"}

_, _ = ts.Run(t, []test.TestCase{
{Method: http.MethodGet, Path: "/my-cached-endpoint", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
{Method: http.MethodGet, Path: "/my-cached-endpoint", HeadersNotMatch: headerCache},
}...)

// endpoint level cache timeout should override
extendedPaths.AdvanceCacheConfig[0].Timeout = 120
ts.Gw.LoadAPI(api)

_, _ = ts.Run(t, []test.TestCase{
{Method: http.MethodGet, Path: "/my-cached-endpoint", HeadersNotMatch: headerCache, Delay: 10 * time.Millisecond},
{Method: http.MethodGet, Path: "/my-cached-endpoint", HeadersMatch: headerCache},
}...)
}

func TestWebsocketsSeveralOpenClose(t *testing.T) {
ts := StartTest(nil)
defer ts.Close()
Expand Down
16 changes: 13 additions & 3 deletions gateway/mw_redis_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ func (m *RedisCacheMiddleware) decodePayload(payload string) (string, string, er
type cacheOptions struct {
key string
cacheOnlyResponseCodes []int
timeout int64
}

// ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
Expand Down Expand Up @@ -193,14 +194,23 @@ func (m *RedisCacheMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Req
}

cacheOnlyResponseCodes := m.Spec.CacheOptions.CacheOnlyResponseCodes
// override api main CacheOnlyResponseCodes by endpoint specific if provided
if cacheMeta != nil && len(cacheMeta.CacheOnlyResponseCodes) > 0 {
cacheOnlyResponseCodes = cacheMeta.CacheOnlyResponseCodes
timeout := m.Spec.CacheOptions.CacheTimeout
if cacheMeta != nil {
// override api level CacheOnlyResponseCodes by endpoint level if provided
if len(cacheMeta.CacheOnlyResponseCodes) > 0 {
cacheOnlyResponseCodes = cacheMeta.CacheOnlyResponseCodes
}

// override api level Timout by endpoint level if provided
if cacheMeta.Timeout > 0 {
timeout = cacheMeta.Timeout
}
}

ctxSetCacheOptions(r, &cacheOptions{
key: key,
cacheOnlyResponseCodes: cacheOnlyResponseCodes,
timeout: timeout,
})

retBlob, err = m.store.GetKey(key)
Expand Down
2 changes: 1 addition & 1 deletion gateway/res_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (m *ResponseCacheMiddleware) HandleResponse(w http.ResponseWriter, res *htt
}

cacheThisRequest := true
cacheTTL := m.Spec.CacheOptions.CacheTimeout
cacheTTL := options.timeout

// make sure the status codes match if specified
if len(options.cacheOnlyResponseCodes) > 0 {
Expand Down
Loading