Merge pull request #434 from retentionscience/aw/exp-backoff
On OctoKit::Forbidden error: retry with exponential backoff
This commit is contained in:
commit
9eb8c93019
|
@ -29,4 +29,5 @@ Gem::Specification.new do |spec|
|
||||||
spec.add_runtime_dependency("octokit", ["~> 4.0"])
|
spec.add_runtime_dependency("octokit", ["~> 4.0"])
|
||||||
spec.add_runtime_dependency("faraday-http-cache")
|
spec.add_runtime_dependency("faraday-http-cache")
|
||||||
spec.add_runtime_dependency("activesupport")
|
spec.add_runtime_dependency("activesupport")
|
||||||
|
spec.add_runtime_dependency("retriable", ["~> 2.1"])
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
require "retriable"
|
||||||
module GitHubChangelogGenerator
|
module GitHubChangelogGenerator
|
||||||
# A Fetcher responsible for all requests to GitHub and all basic manipulation with related data
|
# A Fetcher responsible for all requests to GitHub and all basic manipulation with related data
|
||||||
# (such as filtering, validating, e.t.c)
|
# (such as filtering, validating, e.t.c)
|
||||||
|
@ -8,6 +9,7 @@ module GitHubChangelogGenerator
|
||||||
class OctoFetcher
|
class OctoFetcher
|
||||||
PER_PAGE_NUMBER = 100
|
PER_PAGE_NUMBER = 100
|
||||||
MAX_THREAD_NUMBER = 25
|
MAX_THREAD_NUMBER = 25
|
||||||
|
MAX_FORBIDDEN_RETRIES = 100
|
||||||
CHANGELOG_GITHUB_TOKEN = "CHANGELOG_GITHUB_TOKEN"
|
CHANGELOG_GITHUB_TOKEN = "CHANGELOG_GITHUB_TOKEN"
|
||||||
GH_RATE_LIMIT_EXCEEDED_MSG = "Warning: Can't finish operation: GitHub API rate limit exceeded, change log may be " \
|
GH_RATE_LIMIT_EXCEEDED_MSG = "Warning: Can't finish operation: GitHub API rate limit exceeded, change log may be " \
|
||||||
"missing some issues. You can limit the number of issues fetched using the `--max-issues NUM` argument."
|
"missing some issues. You can limit the number of issues fetched using the `--max-issues NUM` argument."
|
||||||
|
@ -280,17 +282,45 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
||||||
#
|
#
|
||||||
# @return [Object] returns exactly the same, what you put in the block, but wrap it with begin-rescue block
|
# @return [Object] returns exactly the same, what you put in the block, but wrap it with begin-rescue block
|
||||||
def check_github_response
|
def check_github_response
|
||||||
begin
|
Retriable.retriable(retry_options) do
|
||||||
value = yield
|
yield
|
||||||
rescue Octokit::Unauthorized => e
|
end
|
||||||
Helper.log.error e.message
|
|
||||||
abort "Error: wrong GitHub token"
|
|
||||||
rescue Octokit::Forbidden => e
|
rescue Octokit::Forbidden => e
|
||||||
Helper.log.warn e.message
|
Helper.log.error("#{e.class}: #{e.message}")
|
||||||
|
sys_abort("Exceeded retry limit")
|
||||||
|
rescue Octokit::Unauthorized => e
|
||||||
|
Helper.log.error("#{e.class}: #{e.message}")
|
||||||
|
sys_abort("Error: wrong GitHub token")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Exponential backoff
|
||||||
|
def retry_options
|
||||||
|
{
|
||||||
|
on: [Octokit::Forbidden],
|
||||||
|
tries: MAX_FORBIDDEN_RETRIES,
|
||||||
|
base_interval: sleep_base_interval,
|
||||||
|
multiplier: 1.0,
|
||||||
|
rand_factor: 0.0,
|
||||||
|
on_retry: retry_callback
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def sleep_base_interval
|
||||||
|
1.0
|
||||||
|
end
|
||||||
|
|
||||||
|
def retry_callback
|
||||||
|
proc do |exception, try, elapsed_time, next_interval|
|
||||||
|
Helper.log.warn("RETRY - #{exception.class}: '#{exception.message}'")
|
||||||
|
Helper.log.warn("#{try} tries in #{elapsed_time} seconds and #{next_interval} seconds until the next try")
|
||||||
Helper.log.warn GH_RATE_LIMIT_EXCEEDED_MSG
|
Helper.log.warn GH_RATE_LIMIT_EXCEEDED_MSG
|
||||||
Helper.log.warn @client.rate_limit
|
Helper.log.warn @client.rate_limit
|
||||||
end
|
end
|
||||||
value
|
end
|
||||||
|
|
||||||
|
def sys_abort(msg)
|
||||||
|
abort(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Print specified line on the same string
|
# Print specified line on the same string
|
||||||
|
|
|
@ -42,7 +42,7 @@ module GitHubChangelogGenerator
|
||||||
|
|
||||||
# setup parsing options
|
# setup parsing options
|
||||||
def self.setup_parser(options)
|
def self.setup_parser(options)
|
||||||
parser = OptionParser.new do |opts|
|
parser = OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
|
||||||
opts.banner = "Usage: github_changelog_generator [options]"
|
opts.banner = "Usage: github_changelog_generator [options]"
|
||||||
opts.on("-u", "--user [USER]", "Username of the owner of target GitHub repo") do |last|
|
opts.on("-u", "--user [USER]", "Username of the owner of target GitHub repo") do |last|
|
||||||
options[:user] = last
|
options[:user] = last
|
||||||
|
|
|
@ -12,6 +12,31 @@ describe GitHubChangelogGenerator::OctoFetcher do
|
||||||
|
|
||||||
let(:fetcher) { GitHubChangelogGenerator::OctoFetcher.new(options) }
|
let(:fetcher) { GitHubChangelogGenerator::OctoFetcher.new(options) }
|
||||||
|
|
||||||
|
describe "#check_github_response" do
|
||||||
|
context "when returns successfully" do
|
||||||
|
it "returns block value" do
|
||||||
|
expect(fetcher.send(:check_github_response) { 1 + 1 }).to eq(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when raises Octokit::Unauthorized" do
|
||||||
|
it "aborts" do
|
||||||
|
expect(fetcher).to receive(:sys_abort).with("Error: wrong GitHub token")
|
||||||
|
fetcher.send(:check_github_response) { raise(Octokit::Unauthorized) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when raises Octokit::Forbidden" do
|
||||||
|
it "sleeps and retries and then aborts" do
|
||||||
|
retry_limit = GitHubChangelogGenerator::OctoFetcher::MAX_FORBIDDEN_RETRIES - 1
|
||||||
|
allow(fetcher).to receive(:sleep_base_interval).exactly(retry_limit).times.and_return(0)
|
||||||
|
|
||||||
|
expect(fetcher).to receive(:sys_abort).with("Exceeded retry limit")
|
||||||
|
fetcher.send(:check_github_response) { raise(Octokit::Forbidden) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#fetch_github_token" do
|
describe "#fetch_github_token" do
|
||||||
token = GitHubChangelogGenerator::OctoFetcher::CHANGELOG_GITHUB_TOKEN
|
token = GitHubChangelogGenerator::OctoFetcher::CHANGELOG_GITHUB_TOKEN
|
||||||
context "when token in ENV exist" do
|
context "when token in ENV exist" do
|
||||||
|
|
Loading…
Reference in New Issue
Block a user