DEV: Cache slack users list for 10 minutes (#113)

This should help to avoid Slack API rate limiting in very large slack communities
This commit is contained in:
David Taylor 2022-03-15 13:32:28 +00:00 committed by GitHub
parent 55f9b7873b
commit 20f0b1c6ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 7 deletions

View File

@ -2,6 +2,8 @@
module DiscourseChatIntegration::Provider::SlackProvider module DiscourseChatIntegration::Provider::SlackProvider
class SlackTranscript class SlackTranscript
class UserFetchError < RuntimeError; end
attr_reader :users, :channel_id, :messages attr_reader :users, :channel_id, :messages
def initialize(channel_name:, channel_id:, requested_thread_ts: nil) def initialize(channel_name:, channel_id:, requested_thread_ts: nil)
@ -250,19 +252,29 @@ module DiscourseChatIntegration::Provider::SlackProvider
end end
def load_user_data def load_user_data
key = "slack_user_info_#{Digest::SHA1.hexdigest(SiteSetting.chat_integration_slack_access_token)}"
@users = Discourse.cache.fetch(key, expires_in: 10.minutes) do
fetch_user_data
end
true
rescue UserFetchError
false
end
def fetch_user_data
http = ::DiscourseChatIntegration::Provider::SlackProvider.slack_api_http http = ::DiscourseChatIntegration::Provider::SlackProvider.slack_api_http
cursor = nil cursor = nil
req = Net::HTTP::Post.new(URI('https://slack.com/api/users.list')) req = Net::HTTP::Post.new(URI('https://slack.com/api/users.list'))
@users = {} users = {}
loop do loop do
break if cursor == "" break if cursor == ""
req.set_form_data(token: SiteSetting.chat_integration_slack_access_token, limit: 200, cursor: cursor) req.set_form_data(token: SiteSetting.chat_integration_slack_access_token, limit: 200, cursor: cursor)
response = http.request(req) response = http.request(req)
return false unless response.kind_of? Net::HTTPSuccess raise UserFetchError.new unless response.kind_of? Net::HTTPSuccess
json = JSON.parse(response.body) json = JSON.parse(response.body)
return false unless json['ok'] raise UserFetchError.new unless json['ok']
cursor = json['response_metadata']['next_cursor'] cursor = json['response_metadata']['next_cursor']
json['members'].each do |user| json['members'].each do |user|
# Slack uses display_name and falls back to real_name if it is not set # Slack uses display_name and falls back to real_name if it is not set
@ -272,10 +284,10 @@ module DiscourseChatIntegration::Provider::SlackProvider
user['_transcript_username'] = user['profile']['display_name'] user['_transcript_username'] = user['profile']['display_name']
end end
user['_transcript_username'] = user['_transcript_username'].gsub(' ', '_') user['_transcript_username'] = user['_transcript_username'].gsub(' ', '_')
@users[user['id']] = user users[user['id']] = user
end end
end end
true users
end end
def load_chat_history(count: 500) def load_chat_history(count: 500)

View File

@ -3,6 +3,9 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe DiscourseChatIntegration::Provider::SlackProvider::SlackTranscript do RSpec.describe DiscourseChatIntegration::Provider::SlackProvider::SlackTranscript do
before do
Discourse.cache.clear
end
let(:messages_fixture) { let(:messages_fixture) {
[ [
@ -132,14 +135,14 @@ RSpec.describe DiscourseChatIntegration::Provider::SlackProvider::SlackTranscrip
stub_request(:post, "https://slack.com/api/users.list") stub_request(:post, "https://slack.com/api/users.list")
.to_return(status: 500, body: '') .to_return(status: 500, body: '')
expect(transcript.load_user_data).to be_falsey expect(transcript.load_user_data).to eq(false)
end end
it 'handles slack failure' do it 'handles slack failure' do
stub_request(:post, "https://slack.com/api/users.list") stub_request(:post, "https://slack.com/api/users.list")
.to_return(status: 200, body: { ok: false }.to_json) .to_return(status: 200, body: { ok: false }.to_json)
expect(transcript.load_user_data).to be_falsey expect(transcript.load_user_data).to eq(false)
end end
end end