moduleActiveUtilsmoduleNetworkConnectionRetriesDEFAULT_RETRIES=3DEFAULT_CONNECTION_ERRORS={EOFError=>"The remote server dropped the connection",Errno::ECONNRESET=>"The remote server reset the connection",Timeout::Error=>"The connection to the remote server timed out",Errno::ETIMEDOUT=>"The connection to the remote server timed out",SocketError=>"The connection to the remote server could not be established",OpenSSL::SSL::SSLError=>"The SSL connection to the remote server could not be established"}defself.included(base)base.send(:attr_accessor,:retry_safe)enddefretry_exceptions(options={})connection_errors=DEFAULT_CONNECTION_ERRORS.merge(options[:connection_exceptions]||{})retry_network_exceptions(options)dobeginyieldrescueErrno::ECONNREFUSED=>eraiseActiveUtils::RetriableConnectionError,"The remote server refused the connection"rescueOpenSSL::X509::CertificateError=>eNetworkConnectionRetries.log(options[:logger],:error,e.message,options[:tag])raiseActiveUtils::ClientCertificateError,"The remote server did not accept the provided SSL certificate"rescueZlib::BufError=>eraiseActiveUtils::InvalidResponseError,"The remote server replied with an invalid response"rescue*connection_errors.keys=>eraiseActiveUtils::ConnectionError,derived_error_message(connection_errors,e.class)endendendprivatedefretry_network_exceptions(options={})initial_retries=options[:max_retries]||DEFAULT_RETRIESretries=initial_retriesrequest_start=nilbeginrequest_start=Time.now.to_fresult=yieldlog_with_retry_details(options[:logger],initial_retries-retries+1,Time.now.to_f-request_start,"success",options[:tag])resultrescueActiveUtils::RetriableConnectionError=>eretries-=1log_with_retry_details(options[:logger],initial_retries-retries,Time.now.to_f-request_start,e.message,options[:tag])unlessretries.zero?Kernel.sleep(options[:delay])ifoptions[:delay]retryendraiseActiveUtils::ConnectionError,e.messagerescueActiveUtils::ConnectionError,ActiveUtils::InvalidResponseError=>eretries-=1log_with_retry_details(options[:logger],initial_retries-retries,Time.now.to_f-request_start,e.message,options[:tag])if(options[:retry_safe]||retry_safe)&&!retries.zero?Kernel.sleep(options[:delay])ifoptions[:delay]retryendraiseendenddefself.log(logger,level,message,tag=nil)tag||=self.class.to_smessage="[#{tag}] #{message}"logger.send(level,message)ifloggerendprivatedeflog_with_retry_details(logger,attempts,time,message,tag)NetworkConnectionRetries.log(logger,:info,"connection_attempt=%d connection_request_time=%.4fs connection_msg=\"%s\""%[attempts,time,message],tag)enddefderived_error_message(errors,klass)key=(errors.keys&klass.ancestors).firstkey?errors[key]:nilendendend