Skip to content

Commit 38a4041

Browse files
Implement LRU in-memory caching for listAllNodes endpoint (#164)
Co-authored-by: James Kwon <96548424+hongil0316@users.noreply.github.com>
1 parent 0370df0 commit 38a4041

File tree

7 files changed

+234
-54
lines changed

7 files changed

+234
-54
lines changed

drip/api.gen.go

Lines changed: 61 additions & 50 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/Masterminds/semver/v3 v3.2.1
1414
github.com/algolia/algoliasearch-client-go/v3 v3.31.1
1515
github.com/deepmap/oapi-codegen/v2 v2.1.0
16+
github.com/dgraph-io/ristretto/v2 v2.1.0
1617
github.com/getkin/kin-openapi v0.123.0
1718
github.com/golang-jwt/jwt/v5 v5.2.1
1819
github.com/google/uuid v1.6.0
@@ -23,7 +24,7 @@ require (
2324
github.com/newrelic/go-agent/v3/integrations/nrecho-v4 v1.1.3
2425
github.com/oapi-codegen/runtime v1.1.1
2526
github.com/rs/zerolog v1.32.0
26-
github.com/stretchr/testify v1.9.0
27+
github.com/stretchr/testify v1.10.0
2728
github.com/testcontainers/testcontainers-go v0.28.0
2829
github.com/testcontainers/testcontainers-go/modules/postgres v0.28.0
2930
google.golang.org/api v0.165.0
@@ -49,6 +50,7 @@ require (
4950
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
5051
github.com/bmatcuk/doublestar v1.3.4 // indirect
5152
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
53+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
5254
github.com/containerd/containerd v1.7.12 // indirect
5355
github.com/containerd/log v0.1.0 // indirect
5456
github.com/cpuguy83/dockercfg v0.3.1 // indirect
@@ -57,6 +59,7 @@ require (
5759
github.com/docker/docker v25.0.2+incompatible // indirect
5860
github.com/docker/go-connections v0.5.0 // indirect
5961
github.com/docker/go-units v0.5.0 // indirect
62+
github.com/dustin/go-humanize v1.0.1 // indirect
6063
github.com/felixge/httpsnoop v1.0.4 // indirect
6164
github.com/go-logr/logr v1.4.1 // indirect
6265
github.com/go-logr/stdr v1.2.2 // indirect

go.sum

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9
5353
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
5454
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
5555
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
56+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
57+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
5658
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
5759
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
5860
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
@@ -71,6 +73,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
7173
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7274
github.com/deepmap/oapi-codegen/v2 v2.1.0 h1:I/NMVhJCtuvL9x+S2QzZKpSjGi33oDZwPRdemvOZWyQ=
7375
github.com/deepmap/oapi-codegen/v2 v2.1.0/go.mod h1:R1wL226vc5VmCNJUvMyYr3hJMm5reyv25j952zAVXZ8=
76+
github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I=
77+
github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4=
78+
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
79+
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
7480
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
7581
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
7682
github.com/docker/docker v25.0.2+incompatible h1:/OaKeauroa10K4Nqavw4zlhcDq/WBcPMc5DbjOGgozY=
@@ -79,6 +85,8 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj
7985
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
8086
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
8187
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
88+
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
89+
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
8290
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
8391
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
8492
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -265,8 +273,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
265273
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
266274
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
267275
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
268-
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
269-
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
276+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
277+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
270278
github.com/testcontainers/testcontainers-go v0.28.0 h1:1HLm9qm+J5VikzFDYhOd+Zw12NtOl+8drH2E8nTY1r8=
271279
github.com/testcontainers/testcontainers-go v0.28.0/go.mod h1:COlDpUXbwW3owtpMkEB1zo9gwb1CoKVKlyrVPejF4AU=
272280
github.com/testcontainers/testcontainers-go/modules/postgres v0.28.0 h1:ff0s4JdYIdNAVSi/SrpN2Pdt1f+IjIw3AKjbHau8Un4=

integration-tests/node_version_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,77 @@ func TestRegistryNodeVersion(t *testing.T) {
324324
nodeStatus := drip.NodeStatusActive
325325
assert.Equal(t, *node.Status, nodeStatus)
326326
}
327+
328+
t.Run("Cache", func(t *testing.T) {
329+
// create new node version as latest node version
330+
nodeVersion3 := randomNodeVersion(2)
331+
res, err := withMiddleware(authz, impl.PublishNodeVersion)(ctx, drip.PublishNodeVersionRequestObject{
332+
PublisherId: publisherId,
333+
NodeId: *node.Id,
334+
Body: &drip.PublishNodeVersionJSONRequestBody{
335+
PersonalAccessToken: *pat,
336+
Node: *node,
337+
NodeVersion: *nodeVersion3,
338+
},
339+
})
340+
require.IsType(t, drip.PublishNodeVersion201JSONResponse{}, res)
341+
require.NoError(t, err, "should return created node version")
342+
343+
// Retrieve and verify the list of nodes
344+
resNodesCached, err := withMiddleware(authz, impl.ListAllNodes)(ctx, drip.ListAllNodesRequestObject{})
345+
require.NoError(t, err)
346+
assert.Equal(t, resNodes, resNodesCached)
347+
})
348+
349+
t.Run("ForceNoCache", func(t *testing.T) {
350+
// create new node version as latest node version
351+
nodeVersion4 := randomNodeVersion(3)
352+
res, err := withMiddleware(authz, impl.PublishNodeVersion)(ctx, drip.PublishNodeVersionRequestObject{
353+
PublisherId: publisherId,
354+
NodeId: *node.Id,
355+
Body: &drip.PublishNodeVersionJSONRequestBody{
356+
PersonalAccessToken: *pat,
357+
Node: *node,
358+
NodeVersion: *nodeVersion4,
359+
},
360+
})
361+
require.IsType(t, drip.PublishNodeVersion201JSONResponse{}, res)
362+
nodeVersionResp := res.(drip.PublishNodeVersion201JSONResponse)
363+
require.NoError(t, err, "should return created node version")
364+
365+
// Retrieve and verify the list of nodes
366+
resNodes, err := withMiddleware(authz, impl.ListAllNodes)(ctx, drip.ListAllNodesRequestObject{
367+
Params: drip.ListAllNodesParams{
368+
Latest: proto.Bool(true),
369+
},
370+
})
371+
require.NoError(t, err)
372+
require.IsType(t, drip.ListAllNodes200JSONResponse{}, resNodes)
373+
resNodes200 := resNodes.(drip.ListAllNodes200JSONResponse)
374+
375+
// Iterate over each node and assert individual fields
376+
for _, node := range *resNodes200.Nodes {
377+
// Assertions for basic node attributes
378+
assert.Equal(t, *node.Id, *node.Id)
379+
assert.Equal(t, *node.Name, *node.Name)
380+
assert.Equal(t, *node.Repository, *node.Repository)
381+
assert.Equal(t, *node.Description, *node.Description)
382+
assert.Equal(t, *node.Author, *node.Author)
383+
assert.Equal(t, *node.License, *node.License)
384+
assert.Equal(t, *node.Tags, *node.Tags)
385+
386+
// Assert the latest version
387+
assert.Equal(t, *node.LatestVersion.Version, *nodeVersionResp.NodeVersion.Version)
388+
assert.Equal(t, *node.LatestVersion.Changelog, *nodeVersionResp.NodeVersion.Changelog)
389+
assert.Equal(t, *node.LatestVersion.Dependencies, *nodeVersionResp.NodeVersion.Dependencies)
390+
assert.Equal(t, *node.LatestVersion.DownloadUrl, *nodeVersionResp.NodeVersion.DownloadUrl)
391+
assert.Equal(t, *node.LatestVersion.Status, *nodeVersionResp.NodeVersion.Status)
392+
393+
// Status checks
394+
nodeStatus := drip.NodeStatusActive
395+
assert.Equal(t, *node.Status, nodeStatus)
396+
}
397+
})
327398
})
328399

329400
t.Run("Index Nodes", func(t *testing.T) {

openapi.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,6 +1338,12 @@ paths:
13381338
schema:
13391339
type: string
13401340
format: date-time
1341+
- in: query
1342+
name: latest
1343+
description: Whether to fetch fresh result from database or use cached one if false
1344+
required: false
1345+
schema:
1346+
type: boolean
13411347
responses:
13421348
'200':
13431349
description: A paginated list of nodes

server/implementation/registry.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,11 @@ func (s *DripStrictServerImplementation) ListAllNodes(
280280
}
281281

282282
// List nodes from the registry service
283-
nodeResults, err := s.RegistryService.ListNodes(ctx, s.Client, page, limit, filter)
283+
latest := false
284+
if request.Params.Latest != nil {
285+
latest = *request.Params.Latest
286+
}
287+
nodeResults, err := s.RegistryService.ListNodesWithCache(ctx, s.Client, page, limit, filter, latest)
284288
if err != nil {
285289
log.Ctx(ctx).Error().Msgf("Failed to list nodes w/ err: %v", err)
286290
return drip.ListAllNodes500JSONResponse{Message: "Failed to list nodes", Error: err.Error()}, err

0 commit comments

Comments
 (0)