Dealing with various types of exceptions

The most obvious places to wrap a try-catch block are in the code blocks that we need to acquire network resources, for example, querying a database or connecting to a web server. Whenever the network is involved, there is a much higher chance of encountering an issue than doing something locally on the same computer.

It is important to understand what kind of errors can be thrown. Suppose that we continue developing the web crawler use case from the previous section. The index_sites! function is now implemented using the HTTP library as follows:

function index_site!(site::Target)
response = HTTP.get(site.url)
site.finished = true
site.finish_time = now()
println("Site $(site.url) crawled. Status=", response.status)
end

The HTTP.get function is used to retrieve the content from the website. The code looks pretty innocent but it does not handle any error condition. For example, what happens if the site's URL is wrong or if the site is down? In those cases, we would run into a runtime exception, such as the following:

So, at a minimum, we should handle IOError. It turns out that the HTTP library actually does more than that. If the remote site returns any HTTP status code in the 400- or 500-series, then it also wraps the error code and raises a StatusError exception, as follows:

So, how do we know for sure what kind of errors can ever be thrown? Well, we can always read the fine manual or so-called RTFM. From the HTTP package's documentation, we can see that the following exceptions may be thrown when making HTTP requests:

  • HTTP.ExceptionRequest.StatusError
  • HTTP.Parsers.ParseError
  • HTTP.IOExtras.IOError
  • Sockets.DNSError

In Julia, the try-catch block catches all exceptions regardless of the type of exception. So, we should have the ability to handle any other exception even when it is unknown to us. Here is an example of a function that handles exceptions properly:

function try_index_site!(site::Target)
try
index_site!(site)
catch ex
println("Unable to index site: $site")
if ex isa HTTP.ExceptionRequest.StatusError
println("HTTP status error (code = ", ex.status, ")")
elseif ex isa Sockets.DNSError
println("DNS problem: ", ex)
else
println("Unknown error:", ex)
end
end
end

We can see from the preceding code that, in the body of the catch block, we can check the type of exception and handle it appropriately. The else part of the block ensures that all types of exceptions are caught, whether we know about them or not.  Let's hook up the crawl_site! function to this new function:

global function crawl_sites!()
for s in sites
try_index_site!(s)
end
end

We can test out the error handling code now:

This works well!

So, this is one instance; what other places do we want to inject exception handling logic? Let's explore this next.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.246.203