Skip to content

Commit 3ede94a

Browse files
authored
Merge pull request #71 from elementsinteractive/cache-slack
2 parents 4f30405 + f0f6996 commit 3ede94a

2 files changed

Lines changed: 72 additions & 0 deletions

File tree

internal/slack/slack.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package slack
33
import (
44
"errors"
55
"fmt"
6+
"sync"
67
"time"
78

89
"github.com/elliotchance/pie/v2"
@@ -18,6 +19,8 @@ type service struct {
1819
client iclient
1920
maxAttempts int
2021
initialBackoff time.Duration
22+
channelCache map[string]*slack.Channel
23+
cacheMutex sync.RWMutex
2124
}
2225

2326
type conversationsResult struct {
@@ -36,6 +39,7 @@ func New(token string, debug bool) (IService, error) {
3639
client: &client{client: slackClient},
3740
maxAttempts: 5,
3841
initialBackoff: 2 * time.Second,
42+
channelCache: make(map[string]*slack.Channel),
3943
}
4044

4145
return &s, nil
@@ -68,6 +72,12 @@ func (s *service) findSlackChannel(channelName string) (channel *slack.Channel,
6872
var channels []slack.Channel
6973
var channelTypes = []string{"private_channel", "public_channel"}
7074

75+
cachedChannel := s.getCachedChannel(channelName)
76+
if cachedChannel != nil {
77+
log.Debug().Str("channel", channelName).Msg("Found slack channel in cache")
78+
return cachedChannel, nil
79+
}
80+
7181
for {
7282
result, opErr := runWithRetries(func() (conversationsResult, error) {
7383
convChannels, convCursor, convErr := s.client.GetConversations(&slack.GetConversationsParameters{
@@ -92,6 +102,7 @@ func (s *service) findSlackChannel(channelName string) (channel *slack.Channel,
92102
if idx > -1 {
93103
log.Info().Str("channel", channelName).Msg("Found slack channel")
94104
channel = &channels[idx]
105+
s.saveChannelToCache(channelName, channel)
95106
return
96107
} else if nextCursor == "" {
97108
return nil, fmt.Errorf("channel %v not found", channelName)
@@ -101,6 +112,24 @@ func (s *service) findSlackChannel(channelName string) (channel *slack.Channel,
101112
}
102113
}
103114

115+
// getCachedChannel retrieves a channel from the cache if it exists
116+
func (s *service) getCachedChannel(channelName string) (channel *slack.Channel) {
117+
s.cacheMutex.RLock()
118+
defer s.cacheMutex.RUnlock()
119+
ch := s.channelCache[channelName]
120+
return ch
121+
}
122+
123+
// saveChannelToCache saves a channel to the cache
124+
func (s *service) saveChannelToCache(channelName string, channel *slack.Channel) {
125+
s.cacheMutex.Lock()
126+
defer s.cacheMutex.Unlock()
127+
if s.channelCache == nil {
128+
s.channelCache = make(map[string]*slack.Channel)
129+
}
130+
s.channelCache[channelName] = channel
131+
}
132+
104133
func runWithRetries[T any](operation func() (T, error), maxAttempts int, backoff time.Duration) (result T, err error) {
105134
if maxAttempts <= 0 {
106135
maxAttempts = 1

internal/slack/slack_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,46 @@ func TestPostMessageWithDynamicRateLimitRetry(t *testing.T) {
185185
elapsed := time.Since(start)
186186
assert.GreaterOrEqual(t, elapsed, expectedWait, "should have used Slack's dynamic RetryAfter backoff")
187187
}
188+
189+
func TestChannelIsCached(t *testing.T) {
190+
channelID := "1234"
191+
channelName := "random channel"
192+
193+
mockClient := mockClient{}
194+
mockClient.On("GetConversations", &slack.GetConversationsParameters{
195+
ExcludeArchived: true,
196+
Cursor: "",
197+
Types: []string{"private_channel", "public_channel"},
198+
Limit: 1000,
199+
}).Return(
200+
[]slack.Channel{
201+
{
202+
GroupConversation: slack.GroupConversation{
203+
Conversation: slack.Conversation{ID: channelID},
204+
Name: channelName,
205+
},
206+
},
207+
},
208+
"",
209+
nil,
210+
).Once() // Expect only one call to GetConversations
211+
212+
svc := service{
213+
client: &mockClient,
214+
maxAttempts: 3,
215+
initialBackoff: 2 * time.Second,
216+
}
217+
218+
channel, err := svc.findSlackChannel(channelName)
219+
assert.Nil(t, err)
220+
assert.NotNil(t, channel)
221+
assert.Equal(t, channelID, channel.ID)
222+
223+
// Call again to verify it uses the cache
224+
cachedChannel, err := svc.findSlackChannel(channelName)
225+
assert.Nil(t, err)
226+
assert.NotNil(t, cachedChannel)
227+
assert.Equal(t, channelID, cachedChannel.ID)
228+
229+
mockClient.AssertExpectations(t)
230+
}

0 commit comments

Comments
 (0)