From 20f0b1c6cec85a4361816c75fa05cda054b10929 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 15 Mar 2022 13:32:28 +0000 Subject: [PATCH] DEV: Cache slack users list for 10 minutes (#113) This should help to avoid Slack API rate limiting in very large slack communities --- .../provider/slack/slack_transcript.rb | 22 ++++++++++++++----- .../provider/slack/slack_transcript_spec.rb | 7 ++++-- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/discourse_chat_integration/provider/slack/slack_transcript.rb b/lib/discourse_chat_integration/provider/slack/slack_transcript.rb index cdbd135..0e168a2 100644 --- a/lib/discourse_chat_integration/provider/slack/slack_transcript.rb +++ b/lib/discourse_chat_integration/provider/slack/slack_transcript.rb @@ -2,6 +2,8 @@ module DiscourseChatIntegration::Provider::SlackProvider class SlackTranscript + class UserFetchError < RuntimeError; end + attr_reader :users, :channel_id, :messages def initialize(channel_name:, channel_id:, requested_thread_ts: nil) @@ -250,19 +252,29 @@ module DiscourseChatIntegration::Provider::SlackProvider end 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 cursor = nil req = Net::HTTP::Post.new(URI('https://slack.com/api/users.list')) - @users = {} + users = {} loop do break if cursor == "" req.set_form_data(token: SiteSetting.chat_integration_slack_access_token, limit: 200, cursor: cursor) 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) - return false unless json['ok'] + raise UserFetchError.new unless json['ok'] cursor = json['response_metadata']['next_cursor'] json['members'].each do |user| # 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'] end user['_transcript_username'] = user['_transcript_username'].gsub(' ', '_') - @users[user['id']] = user + users[user['id']] = user end end - true + users end def load_chat_history(count: 500) diff --git a/spec/lib/discourse_chat_integration/provider/slack/slack_transcript_spec.rb b/spec/lib/discourse_chat_integration/provider/slack/slack_transcript_spec.rb index b90f376..fe20f87 100644 --- a/spec/lib/discourse_chat_integration/provider/slack/slack_transcript_spec.rb +++ b/spec/lib/discourse_chat_integration/provider/slack/slack_transcript_spec.rb @@ -3,6 +3,9 @@ require 'rails_helper' RSpec.describe DiscourseChatIntegration::Provider::SlackProvider::SlackTranscript do + before do + Discourse.cache.clear + end let(:messages_fixture) { [ @@ -132,14 +135,14 @@ RSpec.describe DiscourseChatIntegration::Provider::SlackProvider::SlackTranscrip stub_request(:post, "https://slack.com/api/users.list") .to_return(status: 500, body: '') - expect(transcript.load_user_data).to be_falsey + expect(transcript.load_user_data).to eq(false) end it 'handles slack failure' do stub_request(:post, "https://slack.com/api/users.list") .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