Class: Aws::AWSErrorHandler

Inherits:
Object show all
Defined in:
lib/awsbase/right_awsbase.rb

Constant Summary collapse

DEFAULT_CLOSE_ON_4XX_PROBABILITY =

0-100 (%)

10
@@reiteration_start_delay =
0.2
@@reiteration_time =
5
@@close_on_error =
true
@@close_on_4xx_probability =
DEFAULT_CLOSE_ON_4XX_PROBABILITY

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(aws, parser, params = {}) ⇒ AWSErrorHandler

params:

:reiteration_time
:errors_list
:close_on_error           = true | false
:close_on_4xx_probability = 1-100


549
550
551
552
553
554
555
556
557
558
559
560
# File 'lib/awsbase/right_awsbase.rb', line 549

def initialize(aws, parser, params={}) #:nodoc:
    @aws = aws # Link to RightEc2 | RightSqs | RightS3 instance
    @parser = parser # parser to parse Amazon response
    @started_at = Time.now
    @stop_at = @started_at + (params[:reiteration_time] || @@reiteration_time)
    @errors_list = params[:errors_list] || []
    @reiteration_delay = @@reiteration_start_delay
    @retries = 0
    # close current HTTP(S) connection on 5xx, errors from list and 4xx errors
    @close_on_error = params[:close_on_error].nil? ? @@close_on_error : params[:close_on_error]
    @close_on_4xx_probability = params[:close_on_4xx_probability] || @@close_on_4xx_probability
end

Class Method Details

.close_on_4xx_probabilityObject



536
537
538
# File 'lib/awsbase/right_awsbase.rb', line 536

def self.close_on_4xx_probability
    @@close_on_4xx_probability
end

.close_on_4xx_probability=(close_on_4xx_probability) ⇒ Object



540
541
542
# File 'lib/awsbase/right_awsbase.rb', line 540

def self.close_on_4xx_probability=(close_on_4xx_probability)
    @@close_on_4xx_probability = close_on_4xx_probability
end

.close_on_errorObject



526
527
528
# File 'lib/awsbase/right_awsbase.rb', line 526

def self.close_on_error
    @@close_on_error
end

.close_on_error=(close_on_error) ⇒ Object



530
531
532
# File 'lib/awsbase/right_awsbase.rb', line 530

def self.close_on_error=(close_on_error)
    @@close_on_error = close_on_error
end

.reiteration_start_delayObject



506
507
508
# File 'lib/awsbase/right_awsbase.rb', line 506

def self.reiteration_start_delay
    @@reiteration_start_delay
end

.reiteration_start_delay=(reiteration_start_delay) ⇒ Object



510
511
512
# File 'lib/awsbase/right_awsbase.rb', line 510

def self.reiteration_start_delay=(reiteration_start_delay)
    @@reiteration_start_delay = reiteration_start_delay
end

.reiteration_timeObject



516
517
518
# File 'lib/awsbase/right_awsbase.rb', line 516

def self.reiteration_time
    @@reiteration_time
end

.reiteration_time=(reiteration_time) ⇒ Object



520
521
522
# File 'lib/awsbase/right_awsbase.rb', line 520

def self.reiteration_time=(reiteration_time)
    @@reiteration_time = reiteration_time
end

Instance Method Details

#check(request) ⇒ Object

Returns false if



563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
# File 'lib/awsbase/right_awsbase.rb', line 563

def check(request) #:nodoc:
    result = false
    error_found = false
    redirect_detected= false
    error_match = nil
    last_errors_text = ''
    response = @aws.last_response
    # log error
    request_text_data = "#{request[:server]}:#{request[:port]}#{request[:request].path}"
    # is this a redirect?
    # yes!
    if response.is_a?(Net::HTTPRedirection)
        redirect_detected = true
    else
        # no, it's an error ...
        @aws.logger.warn("##### #{@aws.class.name} returned an error: #{response.code} #{response.message}\n#{response.body} #####")
        @aws.logger.warn("##### #{@aws.class.name} request: #{request_text_data} ####")
    end
    # Check response body: if it is an Amazon XML document or not:
    if redirect_detected || (response.body && response.body[/<\?xml/]) # ... it is a xml document
        @aws.class.bench_xml.add! do
            error_parser = RightErrorResponseParser.new
            error_parser.parse(response)
            @aws.last_errors = error_parser.errors
            @aws.last_request_id = error_parser.requestID
            last_errors_text = @aws.last_errors.flatten.join("\n")
            # on redirect :
            if redirect_detected
                location = response['location']
                # ... log information and ...
                @aws.logger.info("##### #{@aws.class.name} redirect requested: #{response.code} #{response.message} #####")
                @aws.logger.info("##### New location: #{location} #####")
                # ... fix the connection data
                request[:server] = URI.parse(location).host
                request[:protocol] = URI.parse(location).scheme
                request[:port] = URI.parse(location).port
            end
        end
    else # ... it is not a xml document(probably just a html page?)
        @aws.last_errors = [[response.code, "#{response.message} (#{request_text_data})"]]
        @aws.last_request_id = '-undefined-'
        last_errors_text = response.message
    end
    # now - check the error
    unless redirect_detected
        @errors_list.each do |error_to_find|
            if last_errors_text[/#{error_to_find}/i]
                error_found = true
                error_match = error_to_find
                @aws.logger.warn("##### Retry is needed, error pattern match: #{error_to_find} #####")
                break
            end
        end
    end
    # check the time has gone from the first error come
    if redirect_detected || error_found
        # Close the connection to the server and recreate a new one.
        # It may have a chance that one server is a semi-down and reconnection
        # will help us to connect to the other server
        if !redirect_detected && @close_on_error
            @aws.connection.finish "#{self.class.name}: error match to pattern '#{error_match}'"
        end

        if (Time.now < @stop_at)
            @retries += 1
            unless redirect_detected
                @aws.logger.warn("##### Retry ##{@retries} is being performed. Sleeping for #{@reiteration_delay} sec. Whole time: #{Time.now-@started_at} sec ####")
                sleep @reiteration_delay
                @reiteration_delay *= 2

                # Always make sure that the fp is set to point to the beginning(?)
                # of the File/IO. TODO: it assumes that offset is 0, which is bad.
                if (request[:request].body_stream && request[:request].body_stream.respond_to?(:pos))
                    begin
                        request[:request].body_stream.pos = 0
                    rescue Exception => e
                        @logger.warn("Retry may fail due to unable to reset the file pointer" +
                                " -- #{self.class.name} : #{e.inspect}")
                    end
                end
            else
                @aws.logger.info("##### Retry ##{@retries} is being performed due to a redirect.  ####")
            end
            result = @aws.request_info(request, @parser)
        else
            @aws.logger.warn("##### Ooops, time is over... ####")
        end
        # aha, this is unhandled error:
    elsif @close_on_error
        # Is this a 5xx error ?
        if @aws.last_response.code.to_s[/^5\d\d$/]
            @aws.connection.finish "#{self.class.name}: code: #{@aws.last_response.code}: '#{@aws.last_response.message}'"
            # Is this a 4xx error ?
        elsif @aws.last_response.code.to_s[/^4\d\d$/] && @close_on_4xx_probability > rand(100)
            @aws.connection.finish "#{self.class.name}: code: #{@aws.last_response.code}: '#{@aws.last_response.message}', " +
                    "probability: #{@close_on_4xx_probability}%"
        end
    end
    result
end