How to handle TIdHTTP fatal network errors without

2019-09-07 01:32发布

问题:

I'd like to elaborate on how to properly handle fatal network exceptions raised by TIdHTTP inside TThread's Execute procedure.

My app runs a while..do loop inside the Execute procedure. Each loop makes a TIdHTTP.Get() call. The exceptions are handled at the loop level. There is also an upper level handler of on E: Exception do (level of Execute).

The scenario assumes a fatal network error during active network operations (i.e. adapter outage, "connection reset by peer", etc.).

10 threads are serialized to make TIdHTTP.Get() requests from inside the loop. The app is running on a laptop when a home router unexpectedly hangs. Here comes #10054. Suppose that the network returns within 10 minutes. I want to make sure that in case of a sudden network death, each thread somehow:

  1. Detects that (well, that's the easiest).
  2. Waits until the network comes back.
  3. Makes sure the network is up.
  4. Re-establishes connection and restores all network hood.
  5. Continues the loop.

The desired result is to keep the thread up and running and just survive the temporary network problem. The threads must periodically check if the network is back. When it is, the exception handler must restore all network hood calling thread's RestoreNetworkConnection and then continue the loop.

What I definitely don't want - is to stop threads' execution.

Questions

  1. Which events/exceptions shall I intercept to handle fatal network errors?
  2. Where to place exception handlers within Execute?
  3. What is correct way of re-establishing connection back to normal state?

回答1:

The easiest way is to do something like this:

procedure TMyThread.Execute;
var
  NetworkDown: Boolean;
begin
  NetworkDown := False;
  try
    while not Terminated do
    begin
      // wait for a successful HTTP response...
      repeat
        if Terminated then Exit;
        try
          IdHTTP.Get(...);
          Break;
        except
          on E: EIdHTTPProtocolException do begin
            // process HTTP error as needed...
          end;
          on E: EIdSocketError do begin
            NetworkDown := True;
            // process socket error as needed...
          end;
          on E: Exception do begin
            // process any other error as needed...
            raise;
          end;
        end;
        Sleep(1000);
      until False;

      // got a response, check if network was previously down
      if NetworkDown then
      begin
        NetworkDown := False;
        RestoreNetworkConnection;
      end;

      // now process HTTP response as needed ...
    end;
  except
    on Exception do begin
      // process fatal error as needed ...
    end;
  end;
end;