Skip to content

Commit

Permalink
Cache failed handle resolutions with exponentially increasing TTLs (#300
Browse files Browse the repository at this point in the history
)
  • Loading branch information
whyrusleeping authored Sep 8, 2023
2 parents f934d62 + 761cb81 commit e4f0da2
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 4 deletions.
56 changes: 54 additions & 2 deletions api/extra.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/bluesky-social/indigo/did"
"github.com/bluesky-social/indigo/xrpc"
arc "github.com/hashicorp/golang-lru/arc/v2"
logging "github.com/ipfs/go-log"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
otel "go.opentelemetry.io/otel"
Expand Down Expand Up @@ -75,8 +76,26 @@ type HandleResolver interface {
ResolveHandleToDid(ctx context.Context, handle string) (string, error)
}

type failCacheItem struct {
err error
count int
expiresAt time.Time
}

type ProdHandleResolver struct {
ReqMod func(*http.Request, string) error
ReqMod func(*http.Request, string) error
FailCache *arc.ARCCache[string, *failCacheItem]
}

func NewProdHandleResolver(failureCacheSize int) (*ProdHandleResolver, error) {
failureCache, err := arc.NewARC[string, *failCacheItem](failureCacheSize)
if err != nil {
return nil, err
}

return &ProdHandleResolver{
FailCache: failureCache,
}, nil
}

func (dr *ProdHandleResolver) ResolveHandleToDid(ctx context.Context, handle string) (string, error) {
Expand All @@ -86,6 +105,18 @@ func (dr *ProdHandleResolver) ResolveHandleToDid(ctx context.Context, handle str
ctx, span := otel.Tracer("resolver").Start(ctx, "ResolveHandleToDid")
defer span.End()

var cachedFailureCount int

if dr.FailCache != nil {
if item, ok := dr.FailCache.Get(handle); ok {
cachedFailureCount = item.count
if item.expiresAt.After(time.Now()) {
return "", item.err
}
dr.FailCache.Remove(handle)
}
}

var wkres, dnsres string
var wkerr, dnserr error

Expand Down Expand Up @@ -117,7 +148,28 @@ func (dr *ProdHandleResolver) ResolveHandleToDid(ctx context.Context, handle str
return wkres, nil
}

return "", errors.Join(fmt.Errorf("no did record found for handle %q", handle), dnserr, wkerr)
err := errors.Join(fmt.Errorf("no did record found for handle %q", handle), dnserr, wkerr)

if dr.FailCache != nil {
cachedFailureCount++
expireAt := time.Now().Add(time.Millisecond * 100)
if cachedFailureCount > 1 {
// exponential backoff
expireAt = time.Now().Add(time.Millisecond * 100 * time.Duration(cachedFailureCount*cachedFailureCount))
// Clamp to one hour
if expireAt.After(time.Now().Add(time.Hour)) {
expireAt = time.Now().Add(time.Hour)
}
}

dr.FailCache.Add(handle, &failCacheItem{
err: err,
expiresAt: expireAt,
count: cachedFailureCount,
})
}

return "", err
}

func (dr *ProdHandleResolver) resolveWellKnown(ctx context.Context, handle string) (string, error) {
Expand Down
7 changes: 5 additions & 2 deletions cmd/bigsky/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,10 @@ func Bigsky(cctx *cli.Context) error {
blobstore = &blobs.DiskBlobStore{bsdir}
}

prodHR := api.ProdHandleResolver{}
prodHR, err := api.NewProdHandleResolver(100_000)
if err != nil {
return fmt.Errorf("failed to set up handle resolver: %w", err)
}
if rlskip != "" {
prodHR.ReqMod = func(req *http.Request, host string) error {
if strings.HasSuffix(host, ".bsky.social") {
Expand All @@ -307,7 +310,7 @@ func Bigsky(cctx *cli.Context) error {
}
}

var hr api.HandleResolver = &prodHR
var hr api.HandleResolver = prodHR
if cctx.StringSlice("handle-resolver-hosts") != nil {
hr = &api.TestHandleResolver{
TrialHosts: cctx.StringSlice("handle-resolver-hosts"),
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/gorilla/websocket v1.5.0
github.com/hashicorp/go-retryablehttp v0.7.2
github.com/hashicorp/golang-lru v0.5.4
github.com/hashicorp/golang-lru/arc/v2 v2.0.6
github.com/hashicorp/golang-lru/v2 v2.0.6
github.com/icrowley/fake v0.0.0-20221112152111-d7b7e2276db2
github.com/ipfs/go-block-format v0.1.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/arc/v2 v2.0.6 h1:4NU7uP5vSoK6TbaMj3NtY478TTAWLso/vL1gpNrInHg=
github.com/hashicorp/golang-lru/arc/v2 v2.0.6/go.mod h1:cfdDIX05DWvYV6/shsxDfa/OVcRieOt+q4FnM8x+Xno=
github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM=
github.com/hashicorp/golang-lru/v2 v2.0.6/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
Expand Down

0 comments on commit e4f0da2

Please sign in to comment.