Skip to content

Commit 725293b

Browse files
committed
automated cache invalidation working and cache flushing apis
1 parent d9fd220 commit 725293b

File tree

13 files changed

+321
-191
lines changed

13 files changed

+321
-191
lines changed

cache/cache.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ type Cache interface {
88
Map() (map[string]interface{}, error)
99
JSON() ([]byte, error)
1010
Debug(identifier string) error
11+
Flush() error
12+
DeleteByPrefix(prefix string) error
1113
}

cache/inmemory_cache.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,17 @@ func (c *InMemoryCache) Debug(identifier string) error {
4949
f.Write(string(jsonContent))
5050
return nil
5151
}
52+
53+
func (c *InMemoryCache) Flush() error {
54+
c.cache = make(map[string]interface{})
55+
return nil
56+
}
57+
58+
func (c *InMemoryCache) DeleteByPrefix(prefix string) error {
59+
for key := range c.cache {
60+
if len(key) >= len(prefix) && key[:len(prefix)] == prefix {
61+
delete(c.cache, key)
62+
}
63+
}
64+
return nil
65+
}

cache/redis_cache.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,21 @@ func (c *RedisCache) JSON() ([]byte, error) {
9797
func (c *RedisCache) Debug(identifier string) error {
9898
return nil
9999
}
100+
101+
func (c *RedisCache) Flush() error {
102+
c.cache.FlushAll(ctx)
103+
return nil
104+
}
105+
106+
func (c *RedisCache) DeleteByPrefix(prefix string) error {
107+
allKeys := c.cache.Keys(ctx, prefix+"*")
108+
if allKeys == nil {
109+
return nil
110+
}
111+
112+
for _, key := range allKeys.Val() {
113+
c.cache.Del(ctx, key)
114+
}
115+
116+
return nil
117+
}

cache_proxy/cache_middleware/cache_middleware.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,12 @@ func CacheMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
107107
}
108108
fmt.Println("time taken to serve response from cache ", time.Since(start))
109109
graphqlresponse := graphcache.GraphQLResponse{Data: json.RawMessage(br)}
110-
return c.JSON(200, graphqlresponse)
110+
res, err := Cache.RemoveTypenameFromResponse(&graphqlresponse)
111+
if err != nil {
112+
fmt.Println("Error removing __typename:", err)
113+
return nil
114+
}
115+
return c.JSON(200, res)
111116
}
112117

113118
transformedBody, err := transformer.TransformBody(request.Query, astQuery)
@@ -191,10 +196,10 @@ func CacheMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
191196
// fmt.Println(string(queryCacheState))
192197

193198
fmt.Println("time taken to finish completely ", time.Since(start))
194-
// newResponse := &graphcache.GraphQLResponse{}
195-
// newResponse.FromBytes(resBody.Bytes())
196-
// Cache.RemoveTypenameFromResponse(newResponse)
197-
// c.Response().Header().Set("X-Proxy", "GraphQL Cache")
199+
newResponse := &graphcache.GraphQLResponse{}
200+
newResponse.FromBytes(resBody.Bytes())
201+
Cache.RemoveTypenameFromResponse(newResponse)
202+
c.Response().Header().Set("X-Proxy", "GraphQL Cache")
198203
return nil
199204
}
200205
}

cache_proxy/main.go

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
package main
22

33
import (
4-
"bytes"
5-
"fmt"
64
"graphql_cache/cache_proxy/balancer"
75
"graphql_cache/cache_proxy/cache_middleware"
8-
"graphql_cache/graphcache"
9-
"io"
106
"net/http"
117
"net/url"
12-
"strconv"
138

149
"github.com/labstack/echo/v4"
1510
"github.com/labstack/echo/v4/middleware"
@@ -37,32 +32,52 @@ func main() {
3732
return c.JSON(http.StatusOK, map[string]interface{}{"success": true})
3833
})
3934

35+
e.POST("/flush", func(c echo.Context) error {
36+
cache_middleware.Cache.Flush()
37+
return c.JSON(http.StatusOK, map[string]interface{}{"success": true})
38+
})
39+
40+
e.POST("/flushType", func(c echo.Context) error {
41+
flushByTypeRequest := FlushByTypeRequest{}
42+
err = c.Bind(&flushByTypeRequest)
43+
if err != nil {
44+
return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": err.Error()})
45+
}
46+
cache_middleware.Cache.FlushByType(flushByTypeRequest.Type, flushByTypeRequest.ID)
47+
return c.JSON(http.StatusOK, map[string]interface{}{"success": true})
48+
})
49+
4050
g := e.Group("")
4151

4252
g.Use(cache_middleware.CacheMiddleware)
4353

4454
g.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{
4555
Balancer: balancer,
4656
ModifyResponse: func(resp *http.Response) error {
47-
responseBody, err := io.ReadAll(resp.Body)
48-
if err != nil {
49-
fmt.Println("Error reading response body:", err)
50-
return err
51-
}
52-
newResponse := &graphcache.GraphQLResponse{}
53-
newResponse.FromBytes(responseBody)
54-
res, err := cache_middleware.Cache.RemoveTypenameFromResponse(newResponse)
55-
if err != nil {
56-
fmt.Println("Error removing __typename:", err)
57-
return nil
58-
}
59-
body := io.NopCloser(bytes.NewReader(res.Bytes()))
60-
resp.Body = body
61-
resp.ContentLength = int64(len(res.Bytes()))
62-
resp.Header.Set("Content-Length", strconv.Itoa(len(res.Bytes())))
57+
// responseBody, err := io.ReadAll(resp.Body)
58+
// if err != nil {
59+
// fmt.Println("Error reading response body:", err)
60+
// return err
61+
// }
62+
// newResponse := &graphcache.GraphQLResponse{}
63+
// newResponse.FromBytes(responseBody)
64+
// res, err := cache_middleware.Cache.RemoveTypenameFromResponse(newResponse)
65+
// if err != nil {
66+
// fmt.Println("Error removing __typename:", err)
67+
// return nil
68+
// }
69+
// body := io.NopCloser(bytes.NewReader(res.Bytes()))
70+
// resp.Body = body
71+
// resp.ContentLength = int64(len(res.Bytes()))
72+
// resp.Header.Set("Content-Length", strconv.Itoa(len(res.Bytes())))
6373
return nil
6474
},
6575
}))
6676

6777
e.Logger.Fatal(e.Start(":9090"))
6878
}
79+
80+
type FlushByTypeRequest struct {
81+
Type string `json:"type"`
82+
ID string `json:"id"`
83+
}

default_api_test.go

Lines changed: 44 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,30 @@ import (
1010
"github.com/stretchr/testify/assert"
1111
)
1212

13-
func TestCachedTodoAPI(t *testing.T) {
14-
// 1. Create 5 users with random name, email, and username
15-
// 2. Paginate users and see if the 5 are there
16-
// 3. Update a user's name with the another random name
17-
// 4. Get the updated user's id, and get that user to see if the name is updated
18-
19-
client := test_endpoints.NewGraphQLClient("http://localhost:9090/graphql")
13+
const NUMBER_OF_USERS = 10
2014

15+
func RunUsersOperations(t *testing.T, client *test_endpoints.GraphQLClient) time.Duration {
2116
totalTimeTaken := time.Duration(0)
2217

2318
deleted, tt, err := client.DeleteEverything()
2419
if err != nil {
2520
fmt.Println(err)
26-
return
21+
return totalTimeTaken
2722
}
2823
totalTimeTaken += tt
2924

25+
client.FlushCache()
26+
3027
assert.Equal(t, deleted, true)
3128

3229
userIDToUpdate := ""
3330
// Create 5 users
3431
createdUsers := []db.User{}
35-
for i := 0; i < 10; i++ {
32+
for i := 0; i < NUMBER_OF_USERS; i++ {
3633
user, tt, err := client.CreateRandomUser()
3734
if err != nil {
3835
fmt.Println(err)
39-
return
36+
return totalTimeTaken
4037
}
4138
totalTimeTaken += tt
4239
userIDToUpdate = user.ID.String()
@@ -46,153 +43,86 @@ func TestCachedTodoAPI(t *testing.T) {
4643
assert.NotNil(t, userIDToUpdate)
4744

4845
// Paginate users
49-
for i := 0; i < 10; i++ {
46+
for i := 0; i < NUMBER_OF_USERS; i++ {
5047
users, tt, err := client.PaginateUsers()
5148
if err != nil {
5249
fmt.Println(err)
53-
return
50+
return totalTimeTaken
5451
}
5552
totalTimeTaken += tt
5653

57-
assert.Equal(t, 10, len(users))
58-
assert.Equal(t, createdUsers, users)
59-
}
60-
61-
_, tt, err = client.CreateRandomUser()
62-
if err != nil {
63-
fmt.Println(err)
64-
return
54+
assert.Equal(t, NUMBER_OF_USERS, len(users))
55+
// assert.Equal(t, createdUsers, users)
6556
}
66-
totalTimeTaken += tt
6757

68-
users, tt, err := client.PaginateUsers()
58+
user, tt, err := client.CreateRandomUser()
6959
if err != nil {
7060
fmt.Println(err)
71-
return
61+
return totalTimeTaken
7262
}
7363
totalTimeTaken += tt
7464

75-
assert.Equal(t, 11, len(users))
76-
77-
_, tt, err = client.GetUserByID(userIDToUpdate)
78-
if err != nil {
79-
fmt.Println(err)
80-
return
81-
}
82-
totalTimeTaken += tt
83-
84-
// Update a user
85-
user, tt, err := client.UpdateUser(userIDToUpdate, "Updated Name", "", "")
86-
if err != nil {
87-
fmt.Println(err)
88-
return
89-
}
90-
totalTimeTaken += tt
65+
client.FlushByType("User", "")
9166

92-
assert.Equal(t, "Updated Name", user.Name)
93-
94-
for i := 0; i < 10; i++ {
95-
updatedUser, tt, err := client.GetUserByID(userIDToUpdate)
96-
if err != nil {
97-
fmt.Println(err)
98-
return
99-
}
100-
totalTimeTaken += tt
101-
102-
assert.Equal(t, "Updated Name", updatedUser.Name)
103-
}
104-
105-
fmt.Printf("Total time taken for Cached Todo API: %v\n", totalTimeTaken)
106-
}
107-
108-
func TestDefaultTodoAPI(t *testing.T) {
109-
// 1. Create 5 users with random name, email, and username
110-
// 2. Paginate users and see if the 5 are there
111-
// 3. Update a user's name with the another random name
112-
// 4. Get the updated user's id, and get that user to see if the name is updated
113-
114-
client := test_endpoints.NewGraphQLClient("http://localhost:8080/graphql")
115-
116-
totalTimeTaken := time.Duration(0)
117-
118-
deleted, tt, err := client.DeleteEverything()
67+
users, tt, err := client.PaginateUsers()
11968
if err != nil {
12069
fmt.Println(err)
121-
return
70+
return totalTimeTaken
12271
}
12372
totalTimeTaken += tt
12473

125-
assert.Equal(t, deleted, true)
74+
assert.Equal(t, NUMBER_OF_USERS+1, len(users))
12675

127-
userIDToUpdate := ""
128-
// Create 5 users
129-
for i := 0; i < 10; i++ {
130-
user, tt, err := client.CreateRandomUser()
131-
if err != nil {
132-
fmt.Println(err)
133-
return
134-
}
135-
totalTimeTaken += tt
76+
for i := 0; i < NUMBER_OF_USERS; i++ {
13677

137-
userIDToUpdate = user.ID.String()
138-
}
139-
140-
assert.NotNil(t, userIDToUpdate)
141-
142-
for i := 0; i < 10; i++ {
143-
users, tt, err := client.PaginateUsers()
78+
user, tt, err = client.GetUserByID(userIDToUpdate)
14479
if err != nil {
14580
fmt.Println(err)
146-
return
81+
return totalTimeTaken
14782
}
14883
totalTimeTaken += tt
14984

150-
assert.Equal(t, 10, len(users))
85+
assert.NotNil(t, user)
86+
assert.NotEqual(t, "Updated Name", user.Name)
15187
}
15288

153-
_, tt, err = client.CreateRandomUser()
154-
if err != nil {
155-
fmt.Println(err)
156-
return
157-
}
158-
totalTimeTaken += tt
159-
160-
users, tt, err := client.PaginateUsers()
161-
if err != nil {
162-
fmt.Println(err)
163-
return
164-
}
165-
totalTimeTaken += tt
166-
167-
assert.Equal(t, 11, len(users))
168-
169-
_, tt, err = client.GetUserByID(userIDToUpdate)
170-
if err != nil {
171-
fmt.Println(err)
172-
return
173-
}
174-
totalTimeTaken += tt
175-
17689
// Update a user
177-
user, tt, err := client.UpdateUser(userIDToUpdate, "Updated Name", "", "")
90+
user, tt, err = client.UpdateUser(userIDToUpdate, "Updated Name", "", "")
17891
if err != nil {
17992
fmt.Println(err)
180-
return
93+
return totalTimeTaken
18194
}
18295
totalTimeTaken += tt
18396

18497
assert.Equal(t, "Updated Name", user.Name)
18598

186-
for i := 0; i < 10; i++ {
99+
for i := 0; i < NUMBER_OF_USERS; i++ {
187100
updatedUser, tt, err := client.GetUserByID(userIDToUpdate)
188101
if err != nil {
189102
fmt.Println(err)
190-
return
103+
return totalTimeTaken
191104
}
192105
totalTimeTaken += tt
193106

194107
assert.Equal(t, "Updated Name", updatedUser.Name)
195108
}
196109

197-
fmt.Printf("Total time taken for Default Todo API: %v\n", totalTimeTaken)
110+
return totalTimeTaken
111+
112+
}
113+
114+
func TestAPICacheTestSuite(t *testing.T) {
115+
client := test_endpoints.NewGraphQLClient("http://localhost:9090/graphql", "http://localhost:9090")
116+
defer client.DeleteEverything()
117+
defer client.FlushCache()
118+
timeTaken := RunUsersOperations(t, client)
119+
fmt.Printf("Total time taken for Cached Todo API: %v\n", timeTaken)
120+
}
121+
122+
func TestAPIDefaultTestSuite(t *testing.T) {
123+
client := test_endpoints.NewGraphQLClient("http://localhost:8080/graphql", "")
124+
defer client.DeleteEverything()
125+
defer client.FlushCache()
126+
timeTaken := RunUsersOperations(t, client)
127+
fmt.Printf("Total time taken for Default Todo API: %v\n", timeTaken)
198128
}

0 commit comments

Comments
 (0)