@@ -721,21 +721,64 @@ def self.run(options={})
721
721
Core . run_with_options ( options )
722
722
end
723
723
724
- def self . send_command ( run_loop , cmd , timeout = 60 )
724
+ def self . send_command ( run_loop , cmd , options = { timeout : 60 } , num_retries = 0 , last_error = nil )
725
+ if num_retries > 3
726
+ if last_error
727
+ raise last_error
728
+ else
729
+ raise "Max retries exceeded #{ num_retries } > 3. No error recorded."
730
+ end
731
+ end
732
+
733
+ if options . is_a? ( Numeric )
734
+ options = { timeout : options }
735
+ end
725
736
726
737
if not cmd . is_a? ( String )
727
738
raise "Illegal command #{ cmd } (must be a string)"
728
739
end
729
740
741
+ if not options . is_a? ( Hash )
742
+ raise "Illegal options #{ options } (must be a Hash (or number for compatibility))"
743
+ end
744
+
745
+ timeout = options [ :timeout ] || 60
746
+ logger = options [ :logger ]
747
+ interrupt_retry_timeout = options [ :interrupt_retry_timeout ] || 25
730
748
731
- expected_index = Core . write_request ( run_loop , cmd )
749
+ expected_index = run_loop [ :index ]
732
750
result = nil
751
+ begin
752
+ expected_index = Core . write_request ( run_loop , cmd )
753
+ rescue Errno ::EINTR => intr_error
754
+ # Attempt recover from interrupt by attempting to read result (assuming write went OK)
755
+ # or retry if attempted read result fails
756
+ run_loop [ :index ] = expected_index # restore expected index in case it changed
757
+ log_info ( logger , "Core.write_request was interrupted: #{ intr_error } . Attempting recovery..." )
758
+ sleep ( 1 ) # Arbitrary wait in hope that the system condition causing the interrupt passes
759
+ if intr_error && intr_error . backtrace
760
+ log_info ( logger , "backtrace: #{ intr_error . backtrace . join ( "\n " ) } " )
761
+ end
762
+ log_info ( logger , "Attempting read in case the request was received... Please wait (#{ interrupt_retry_timeout } )..." )
763
+ begin
764
+ Timeout ::timeout ( interrupt_retry_timeout , TimeoutError ) do
765
+ result = Core . read_response ( run_loop , expected_index )
766
+ end
767
+ # Update run_loop expected index since we succeeded in reading the index
768
+ run_loop [ :index ] = expected_index + 1
769
+ log_info ( logger , "Did read response for interrupted request of index #{ expected_index } ... Proceeding." )
770
+ return result
771
+ rescue TimeoutError => _
772
+ log_info ( logger , "Read did not result in a response for index #{ expected_index } ... Retrying send_command..." )
773
+ return send_command ( run_loop , cmd , options , num_retries +1 , intr_error )
774
+ end
775
+ end
776
+
733
777
734
778
begin
735
779
Timeout ::timeout ( timeout , TimeoutError ) do
736
780
result = Core . read_response ( run_loop , expected_index )
737
781
end
738
-
739
782
rescue TimeoutError => _
740
783
raise TimeoutError , "Time out waiting for UIAutomation run-loop for command #{ cmd } . Waiting for index:#{ expected_index } "
741
784
end
@@ -776,4 +819,12 @@ def self.validate_script(script)
776
819
script
777
820
end
778
821
822
+ def self . log_info ( device_logger , message )
823
+ msg = "#{ Time . now } : #{ message } "
824
+ if device_logger && device_logger . respond_to? ( :info )
825
+ logger . info ( msg )
826
+ else
827
+ puts msg if ENV [ 'DEBUG' ] == '1'
828
+ end
829
+ end
779
830
end
0 commit comments