Skip to content

Commit 5ac1439

Browse files
authored
Merge pull request #24 from rusq/cache-and-context
LRU cache and Context
2 parents 956bc0f + a255365 commit 5ac1439

File tree

18 files changed

+367
-332
lines changed

18 files changed

+367
-332
lines changed

.github/workflows/go.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Set up Go
2020
uses: actions/setup-go@v5
2121
with:
22-
go-version: 1.24
22+
go-version: 1.25
2323

2424
- name: Build
2525
run: go build -v ./...

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.24-alpine AS builder
1+
FROM golang:1.25-alpine AS builder
22
LABEL maintainer="github:@rusq"
33

44
WORKDIR /build

addr.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package aklapi
22

33
import (
4+
"context"
45
"encoding/json"
56
"errors"
6-
"log"
7+
"log/slog"
78
"net/http"
89
"strconv"
910
"time"
@@ -36,19 +37,19 @@ func (s Address) String() string {
3637
}
3738

3839
// AddressLookup is a convenience function to get addresses.
39-
func AddressLookup(addr string) (*AddrResponse, error) {
40-
return MatchingPropertyAddresses(&AddrRequest{SearchText: addr, PageSize: 10})
40+
func AddressLookup(ctx context.Context, addr string) (*AddrResponse, error) {
41+
return MatchingPropertyAddresses(ctx, &AddrRequest{SearchText: addr, PageSize: 10})
4142
}
4243

4344
// MatchingPropertyAddresses wrapper around the AKL Council API.
44-
func MatchingPropertyAddresses(addrReq *AddrRequest) (*AddrResponse, error) {
45+
func MatchingPropertyAddresses(ctx context.Context, addrReq *AddrRequest) (*AddrResponse, error) {
4546
cachedAr, ok := addrCache.Lookup(addrReq.SearchText)
4647
if ok {
47-
log.Printf("cached address result: %q", cachedAr)
48+
slog.DebugContext(ctx, "found cached address result", "addr", cachedAr)
4849
return cachedAr, nil
4950
}
5051

51-
req, err := http.NewRequest("GET", addrURI, nil)
52+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, addrURI, nil)
5253
if err != nil {
5354
return nil, err
5455
}
@@ -66,7 +67,7 @@ func MatchingPropertyAddresses(addrReq *AddrRequest) (*AddrResponse, error) {
6667
return nil, err
6768
}
6869
defer resp.Body.Close()
69-
log.Printf("address call complete in %s", time.Since(start))
70+
slog.DebugContext(ctx, "address call complete", "duration", time.Since(start))
7071

7172
if resp.StatusCode != http.StatusOK {
7273
return nil, errors.New("address API returned status code: " + strconv.Itoa(resp.StatusCode))
@@ -82,8 +83,8 @@ func MatchingPropertyAddresses(addrReq *AddrRequest) (*AddrResponse, error) {
8283
return &apiResp, nil
8384
}
8485

85-
func oneAddress(addr string) (*Address, error) {
86-
resp, err := AddressLookup(addr)
86+
func oneAddress(ctx context.Context, addr string) (*Address, error) {
87+
resp, err := AddressLookup(ctx, addr)
8788
if err != nil {
8889
return nil, err
8990
}

addr_cache.go

Lines changed: 0 additions & 17 deletions
This file was deleted.

addr_cache_test.go

Lines changed: 0 additions & 92 deletions
This file was deleted.

addr_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func TestMatchingPropertyAddresses(t *testing.T) {
6868
oldURI := addrURI
6969
defer func() { addrURI = oldURI }()
7070
addrURI = tt.testSrv.URL
71-
got, err := MatchingPropertyAddresses(tt.args.addrReq)
71+
got, err := MatchingPropertyAddresses(t.Context(), tt.args.addrReq)
7272
if (err != nil) != tt.wantErr {
7373
t.Errorf("MatchingPropertyAddresses() error = %v, wantErr %v", err, tt.wantErr)
7474
return
@@ -106,7 +106,7 @@ func TestAddress(t *testing.T) {
106106
oldURI := addrURI
107107
defer func() { addrURI = oldURI }()
108108
addrURI = tt.testSrv.URL
109-
got, err := AddressLookup(tt.args.addr)
109+
got, err := AddressLookup(t.Context(), tt.args.addr)
110110
if (err != nil) != tt.wantErr {
111111
t.Errorf("Address() error = %v, wantErr %v", err, tt.wantErr)
112112
return
@@ -160,7 +160,7 @@ func Test_oneAddress(t *testing.T) {
160160
oldURI := addrURI
161161
defer func() { addrURI = oldURI }()
162162
addrURI = tt.testSrv.URL
163-
got, err := oneAddress(tt.args.addr)
163+
got, err := oneAddress(t.Context(), tt.args.addr)
164164
if (err != nil) != tt.wantErr {
165165
t.Errorf("oneAddress() error = %v, wantErr %v", err, tt.wantErr)
166166
return

aklapi.go

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

33
import (
4-
"regexp"
54
"time"
65
)
76

87
var (
98
defaultLoc, _ = time.LoadLocation("Pacific/Auckland") // Auckland is in NZ.
10-
dow = regexp.MustCompile("Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday")
119
)

caches.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package aklapi
2+
3+
import (
4+
"github.com/phuslu/lru"
5+
)
6+
7+
const defCacheSz = 100 // seems reasonable.
8+
var (
9+
addrCache = newLRUCache[string, *AddrResponse](defCacheSz)
10+
rubbishCache = rubbishResultCache{lc: newLRUCache[string, *CollectionDayDetailResult](defCacheSz)}
11+
)
12+
13+
type lruCache[K comparable, V any] struct {
14+
cache *lru.LRUCache[K, V]
15+
}
16+
17+
func newLRUCache[K comparable, V any](size int) *lruCache[K, V] {
18+
return &lruCache[K, V]{
19+
cache: lru.NewLRUCache[K, V](size),
20+
}
21+
}
22+
23+
func (c *lruCache[K, V]) Lookup(key K) (resp V, ok bool) {
24+
var nothing V
25+
if NoCache {
26+
return nothing, false
27+
}
28+
return c.cache.Get(key)
29+
}
30+
31+
func (c *lruCache[K, V]) Add(key K, value V) {
32+
c.cache.Set(key, value)
33+
}
34+
35+
func (c *lruCache[K, V]) Delete(key K) {
36+
c.cache.Delete(key)
37+
}
38+
39+
type rubbishResultCache struct {
40+
lc *lruCache[string, *CollectionDayDetailResult]
41+
}
42+
43+
func (c *rubbishResultCache) Lookup(searchText string) (result *CollectionDayDetailResult, ok bool) {
44+
result, ok = c.lc.Lookup(searchText)
45+
if !ok {
46+
return nil, false
47+
}
48+
49+
today := now()
50+
for _, res := range result.Collections {
51+
if today.After(res.Date) || res.Date.IsZero() {
52+
// invalidate from cache.
53+
c.lc.Delete(searchText)
54+
return nil, false
55+
}
56+
}
57+
return
58+
}
59+
60+
func (c *rubbishResultCache) Add(searchText string, result *CollectionDayDetailResult) {
61+
c.lc.Add(searchText, result)
62+
}

0 commit comments

Comments
 (0)