Skip to content

Commit d9fd220

Browse files
committed
wip - cache invalidation
1 parent c376754 commit d9fd220

File tree

7 files changed

+220
-42
lines changed

7 files changed

+220
-42
lines changed

cache/inmemory_cache.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (c *InMemoryCache) JSON() ([]byte, error) {
4343
}
4444

4545
func (c *InMemoryCache) Debug(identifier string) error {
46-
f := file_utils.NewFile(identifier + ".cache.json")
46+
f := file_utils.NewFile("../" + identifier + ".cache.json")
4747
defer f.Close()
4848
jsonContent, _ := c.JSON()
4949
f.Write(string(jsonContent))

cache_proxy/cache_middleware/cache_middleware.go

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
"github.com/labstack/echo/v4"
1717
)
1818

19-
var gc = graphcache.NewGraphCache()
19+
var Cache = graphcache.NewGraphCache("redis")
2020

2121
func CacheMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
2222
return func(c echo.Context) error {
@@ -46,12 +46,59 @@ func CacheMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
4646

4747
if astQuery.Operations[0].Operation == "mutation" {
4848
// if the operation is a mutation, we don't cache it
49-
c.Request().Body = io.NopCloser(bytes.NewBuffer(requestBytes))
49+
// c.Request().Body = io.NopCloser(bytes.NewBuffer(requestBytes))
50+
// c.Request().ContentLength = -1
51+
transformedBody, err := transformer.TransformBody(request.Query, astQuery)
52+
if err != nil {
53+
fmt.Println("Error transforming body:", err)
54+
return nil
55+
}
56+
57+
fmt.Println("time taken to transform body ", time.Since(start))
58+
59+
transformedRequest := request
60+
transformedRequest.Query = transformedBody
61+
62+
c.Request().Body = io.NopCloser(bytes.NewBuffer(transformedRequest.Bytes()))
5063
c.Request().ContentLength = -1
51-
return next(c)
64+
65+
resBody := new(bytes.Buffer)
66+
mw := io.MultiWriter(c.Response().Writer, resBody)
67+
writer := &bodyDumpResponseWriter{Writer: mw, ResponseWriter: c.Response().Writer}
68+
c.Response().Writer = writer
69+
err = next(c)
70+
if err != nil {
71+
return err
72+
}
73+
fmt.Println("found a mutation, invalidating cache...")
74+
75+
responseMap := make(map[string]interface{})
76+
err = json.Unmarshal(resBody.Bytes(), &responseMap)
77+
if err != nil {
78+
fmt.Println("Error unmarshalling response:", err)
79+
}
80+
81+
// go through the response. Every object that has a __typename field, and an id field cache it in the format of typename:id
82+
// for example, if the response has an object with __typename: "Organisation" and id: "1234", cache it as Organisation:1234
83+
// if the object has a nested object with __typename: "User" and id: "5678", cache
84+
// it as User:5678
85+
86+
Cache.InvalidateCache("data", responseMap, nil)
87+
88+
// newResponse := &graphcache.GraphQLResponse{}
89+
// newResponse.FromBytes(resBody.Bytes())
90+
// res, err := Cache.RemoveTypenameFromResponse(newResponse)
91+
// if err != nil {
92+
// fmt.Println("Error removing __typename:", err)
93+
// return nil
94+
// }
95+
// fmt.Println("response bytes ", string(res.Bytes()))
96+
// c.Response().Write(res.Bytes())
97+
// c.Response().Header().Set("X-Proxy", "GraphQL Cache")
98+
return nil
5299
}
53100

54-
cachedResponse, err := gc.ParseASTBuildResponse(astQuery, request)
101+
cachedResponse, err := Cache.ParseASTBuildResponse(astQuery, request)
55102
if err == nil && cachedResponse != nil {
56103
fmt.Println("serving response from cache...")
57104
br, err := json.Marshal(cachedResponse)
@@ -60,12 +107,7 @@ func CacheMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
60107
}
61108
fmt.Println("time taken to serve response from cache ", time.Since(start))
62109
graphqlresponse := graphcache.GraphQLResponse{Data: json.RawMessage(br)}
63-
res, err := gc.RemoveTypenameFromResponse(&graphqlresponse)
64-
if err != nil {
65-
fmt.Println("Error removing __typename:", err)
66-
return nil
67-
}
68-
return c.JSON(200, res)
110+
return c.JSON(200, graphqlresponse)
69111
}
70112

71113
transformedBody, err := transformer.TransformBody(request.Query, astQuery)
@@ -116,10 +158,10 @@ func CacheMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
116158
// for the operation op we need to traverse the response and the ast together to build a graph of the relations
117159

118160
// build the relation graph
119-
responseKey := gc.GetQueryResponseKey(op, responseMap, variables)
161+
responseKey := Cache.GetQueryResponseKey(op, responseMap, variables)
120162
for key, value := range responseKey {
121163
if value != nil {
122-
gc.SetQueryCache(key, value)
164+
Cache.SetQueryCache(key, value)
123165
}
124166
}
125167
}
@@ -131,7 +173,7 @@ func CacheMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
131173
// if the object has a nested object with __typename: "User" and id: "5678", cache
132174
// it as User:5678
133175

134-
gc.CacheResponse("data", responseMap, nil)
176+
Cache.CacheResponse("data", responseMap, nil)
135177

136178
fmt.Println("time taken to cache response ", time.Since(start))
137179

@@ -149,10 +191,10 @@ func CacheMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
149191
// fmt.Println(string(queryCacheState))
150192

151193
fmt.Println("time taken to finish completely ", time.Since(start))
152-
newResponse := &graphcache.GraphQLResponse{}
153-
newResponse.FromBytes(resBody.Bytes())
154-
gc.RemoveTypenameFromResponse(newResponse)
155-
c.Response().Header().Set("X-Proxy", "GraphQL Cache")
194+
// newResponse := &graphcache.GraphQLResponse{}
195+
// newResponse.FromBytes(resBody.Bytes())
196+
// Cache.RemoveTypenameFromResponse(newResponse)
197+
// c.Response().Header().Set("X-Proxy", "GraphQL Cache")
156198
return nil
157199
}
158200
}

cache_proxy/main.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package main
22

33
import (
4+
"bytes"
5+
"fmt"
46
"graphql_cache/cache_proxy/balancer"
57
"graphql_cache/cache_proxy/cache_middleware"
8+
"graphql_cache/graphcache"
9+
"io"
10+
"net/http"
611
"net/url"
12+
"strconv"
713

814
"github.com/labstack/echo/v4"
915
"github.com/labstack/echo/v4/middleware"
@@ -17,7 +23,7 @@ func main() {
1723
e.Use(middleware.Recover())
1824
e.Use(middleware.Logger())
1925

20-
e.Use(cache_middleware.CacheMiddleware)
26+
// e.Use(cache_middleware.NewCacheMiddleware(gc))
2127
apiSever, err := url.Parse(API_URL)
2228
if err != nil {
2329
e.Logger.Fatal(err)
@@ -26,7 +32,37 @@ func main() {
2632
URL: apiSever,
2733
})
2834

29-
e.Use(middleware.Proxy(balancer))
35+
e.GET("/debug", func(c echo.Context) error {
36+
cache_middleware.Cache.Debug()
37+
return c.JSON(http.StatusOK, map[string]interface{}{"success": true})
38+
})
39+
40+
g := e.Group("")
41+
42+
g.Use(cache_middleware.CacheMiddleware)
43+
44+
g.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{
45+
Balancer: balancer,
46+
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())))
63+
return nil
64+
},
65+
}))
3066

3167
e.Logger.Fatal(e.Start(":9090"))
3268
}

default_api_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func TestCachedTodoAPI(t *testing.T) {
3232
userIDToUpdate := ""
3333
// Create 5 users
3434
createdUsers := []db.User{}
35-
for i := 0; i < 5; i++ {
35+
for i := 0; i < 10; i++ {
3636
user, tt, err := client.CreateRandomUser()
3737
if err != nil {
3838
fmt.Println(err)
@@ -46,15 +46,15 @@ func TestCachedTodoAPI(t *testing.T) {
4646
assert.NotNil(t, userIDToUpdate)
4747

4848
// Paginate users
49-
for i := 0; i < 5; i++ {
49+
for i := 0; i < 10; i++ {
5050
users, tt, err := client.PaginateUsers()
5151
if err != nil {
5252
fmt.Println(err)
5353
return
5454
}
5555
totalTimeTaken += tt
5656

57-
assert.Equal(t, 5, len(users))
57+
assert.Equal(t, 10, len(users))
5858
assert.Equal(t, createdUsers, users)
5959
}
6060

@@ -72,7 +72,7 @@ func TestCachedTodoAPI(t *testing.T) {
7272
}
7373
totalTimeTaken += tt
7474

75-
assert.Equal(t, 6, len(users))
75+
assert.Equal(t, 11, len(users))
7676

7777
_, tt, err = client.GetUserByID(userIDToUpdate)
7878
if err != nil {
@@ -91,7 +91,7 @@ func TestCachedTodoAPI(t *testing.T) {
9191

9292
assert.Equal(t, "Updated Name", user.Name)
9393

94-
for i := 0; i < 5; i++ {
94+
for i := 0; i < 10; i++ {
9595
updatedUser, tt, err := client.GetUserByID(userIDToUpdate)
9696
if err != nil {
9797
fmt.Println(err)
@@ -126,7 +126,7 @@ func TestDefaultTodoAPI(t *testing.T) {
126126

127127
userIDToUpdate := ""
128128
// Create 5 users
129-
for i := 0; i < 5; i++ {
129+
for i := 0; i < 10; i++ {
130130
user, tt, err := client.CreateRandomUser()
131131
if err != nil {
132132
fmt.Println(err)
@@ -139,15 +139,15 @@ func TestDefaultTodoAPI(t *testing.T) {
139139

140140
assert.NotNil(t, userIDToUpdate)
141141

142-
for i := 0; i < 5; i++ {
142+
for i := 0; i < 10; i++ {
143143
users, tt, err := client.PaginateUsers()
144144
if err != nil {
145145
fmt.Println(err)
146146
return
147147
}
148148
totalTimeTaken += tt
149149

150-
assert.Equal(t, 5, len(users))
150+
assert.Equal(t, 10, len(users))
151151
}
152152

153153
_, tt, err = client.CreateRandomUser()
@@ -164,7 +164,7 @@ func TestDefaultTodoAPI(t *testing.T) {
164164
}
165165
totalTimeTaken += tt
166166

167-
assert.Equal(t, 6, len(users))
167+
assert.Equal(t, 11, len(users))
168168

169169
_, tt, err = client.GetUserByID(userIDToUpdate)
170170
if err != nil {
@@ -183,7 +183,7 @@ func TestDefaultTodoAPI(t *testing.T) {
183183

184184
assert.Equal(t, "Updated Name", user.Name)
185185

186-
for i := 0; i < 5; i++ {
186+
for i := 0; i < 10; i++ {
187187
updatedUser, tt, err := client.GetUserByID(userIDToUpdate)
188188
if err != nil {
189189
fmt.Println(err)

0 commit comments

Comments
 (0)