Skip to content

Commit 5b6f1b6

Browse files
Add rendezvous helper (#21)
1 parent 4ebce50 commit 5b6f1b6

4 files changed

Lines changed: 47 additions & 11 deletions

File tree

api/dbv1/full_users.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package dbv1
33
import (
44
"context"
55
"fmt"
6-
"math/rand"
76
"strings"
87

98
"bridgerton.audius.co/rendezvous"
@@ -47,9 +46,7 @@ func (q *Queries) FullUsersKeyed(ctx context.Context, arg GetUsersParams) (map[i
4746

4847
if cid != "" {
4948
// rendezvous for cid
50-
ranked := rendezvous.GlobalHasher.Rank(cid)
51-
randIdx := rand.Intn(3)
52-
first, rest := ranked[randIdx], append(ranked[:randIdx], ranked[randIdx+1:]...)[:2]
49+
first, rest := rendezvous.GlobalHasher.ReplicaSet3(cid)
5350

5451
coverPhoto = &RectangleImage{
5552
X640: fmt.Sprintf("%s/content/%s/640x.jpg", first, cid),
@@ -111,9 +108,7 @@ func squareImageStruct(maybeCids ...pgtype.Text) *SquareImage {
111108
}
112109

113110
// rendezvous for cid
114-
ranked := rendezvous.GlobalHasher.Rank(cid)
115-
randIdx := rand.Intn(3)
116-
first, rest := ranked[randIdx], append(ranked[:randIdx], ranked[randIdx+1:]...)[:2]
111+
first, rest := rendezvous.GlobalHasher.ReplicaSet3(cid)
117112

118113
return &SquareImage{
119114
X150x150: fmt.Sprintf("%s/content/%s/150x150.jpg", first, cid),

api/dbv1/media_link.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bytes"
55
"encoding/json"
66
"fmt"
7-
"math/rand"
87
"net/url"
98
"strings"
109
"time"
@@ -21,9 +20,7 @@ type MediaLink struct {
2120
}
2221

2322
func mediaLink(cid string, trackId int32, userId int32) *MediaLink {
24-
ranked := rendezvous.GlobalHasher.Rank(cid)
25-
randIdx := rand.Intn(3)
26-
first, rest := ranked[randIdx], append(ranked[:randIdx], ranked[randIdx+1:]...)[:2]
23+
first, rest := rendezvous.GlobalHasher.ReplicaSet3(cid)
2724

2825
timestamp := time.Now().Unix() * 1000
2926
data := map[string]interface{}{

rendezvous/rendezvous.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"bytes"
77
"crypto/sha256"
88
"io"
9+
"math/rand"
910
"net/url"
1011
"os"
1112
"slices"
@@ -174,3 +175,19 @@ func (rh *RendezvousHasher) Rank(key string) []string {
174175
}
175176
return result
176177
}
178+
179+
// Get a replica set of 3 nodes with random order
180+
func (rh *RendezvousHasher) ReplicaSet3(key string) (string, []string) {
181+
ranked := rh.Rank(key)
182+
n := min(len(ranked), 3)
183+
if n == 0 {
184+
return "", []string{}
185+
}
186+
187+
candidates := append([]string(nil), ranked[:n]...)
188+
rand.Shuffle(n, func(i, j int) {
189+
candidates[i], candidates[j] = candidates[j], candidates[i]
190+
})
191+
192+
return candidates[0], candidates[1:]
193+
}

rendezvous/rendezvous_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package rendezvous
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestReplicaSet3(t *testing.T) {
10+
hosts := []string{
11+
"https://host1.com",
12+
"https://host2.com",
13+
"https://host3.com",
14+
"https://host4.com",
15+
"https://host5.com",
16+
}
17+
18+
hasher := NewRendezvousHasher(hosts)
19+
first, rest := hasher.ReplicaSet3("test-key")
20+
ranked := hasher.Rank("test-key")
21+
22+
assert.Equal(t, 2, len(rest))
23+
assert.Contains(t, ranked, first)
24+
for i := 0; i < 2; i++ {
25+
assert.Contains(t, ranked, rest[i])
26+
}
27+
}

0 commit comments

Comments
 (0)