diff --git a/lib/event_service/client.rb b/lib/event_service/client.rb index 37ac7ad4..c73238b5 100644 --- a/lib/event_service/client.rb +++ b/lib/event_service/client.rb @@ -14,7 +14,7 @@ def get(path, params) private def connection_for(endpoint, proxy) - Faraday.new(endpoint, proxy: proxy) do |f| + Faraday.new(endpoint, proxy: proxy, request: { open_timeout: 10, timeout: 60 }) do |f| f.response :logger if self.class.debug # faraday標準のJSONパーサーを使用 diff --git a/lib/event_service/providers/doorkeeper.rb b/lib/event_service/providers/doorkeeper.rb index 8d9409cc..b61fade8 100644 --- a/lib/event_service/providers/doorkeeper.rb +++ b/lib/event_service/providers/doorkeeper.rb @@ -17,35 +17,48 @@ def search(keyword:) end # NOTE: since_at, until_at は DateTime で指定 - def fetch_events(group_id:, since_at: @default_since, until_at: @default_until) - begin - params = { - page: 1, - since: since_at.utc.iso8601, - until: until_at.utc.iso8601 - } - events = [] + def fetch_events(group_id:, since_at: @default_since, until_at: @default_until, retry_count: 0) + params = { + page: 1, + since: since_at.utc.iso8601, + until: until_at.utc.iso8601 + } + events = [] - loop do - part = @client.get("groups/#{group_id}/events", params) + loop do + part = @client.get("groups/#{group_id}/events", params) - break if part.size.zero? + break if part.size.zero? - events.push(*part.map { |e| e[:event] }) + events.push(*part.map { |e| e[:event] }) - break if part.size < 25 # 25 items / 1 request + break if part.size < 25 # 25 items / 1 request - params[:page] += 1 - end - - events - rescue Faraday::ClientError => e - raise e unless e.response[:status] == 429 + params[:page] += 1 + end + events + rescue Faraday::ClientError => e + # 429: Rate Limit + if e.response[:status] == 429 puts 'API rate limit exceeded.' puts "This task will retry in 60 seconds from now(#{Time.zone.now})." sleep 60 retry + else + raise e + end + rescue Faraday::ServerError => e + # 502, 503, 504: Server errors + if [502, 503, 504].include?(e.response[:status]) && retry_count < 3 + wait_time = 2 ** retry_count * 10 # Exponential backoff: 10, 20, 40 seconds + puts "Server error (#{e.response[:status]}) for group_id: #{group_id}." + puts "Retrying in #{wait_time} seconds... (attempt #{retry_count + 1}/3)" + sleep wait_time + fetch_events(group_id: group_id, since_at: since_at, until_at: until_at, retry_count: retry_count + 1) + else + puts "Failed to fetch events for group_id: #{group_id} after #{retry_count} retries." + raise e end end end diff --git a/lib/statistics/tasks/doorkeeper.rb b/lib/statistics/tasks/doorkeeper.rb index 12c3f425..fdd24d91 100644 --- a/lib/statistics/tasks/doorkeeper.rb +++ b/lib/statistics/tasks/doorkeeper.rb @@ -18,6 +18,7 @@ def initialize(dojos, period) def run @dojos.each do |dojo| dojo.dojo_event_services.for(:doorkeeper).each do |dojo_event_service| + puts " Fetching events for #{dojo.name} (group_id: #{dojo_event_service.group_id})" events = @client.fetch_events(**@params.merge(group_id: dojo_event_service.group_id)) (events || []).compact.each do |e| next unless e[:group].to_s == dojo_event_service.group_id @@ -31,6 +32,10 @@ def run participants: e[:participants], evented_at: Time.zone.parse(e[:starts_at])) end + puts " ✓ Successfully fetched #{events&.size || 0} events" + rescue => e + puts " ✗ Failed to fetch events for #{dojo.name} (group_id: #{dojo_event_service.group_id}): #{e.message}" + raise e end end end