Sunday, October 24, 2010

Scala exercise 4: circuit breaker pattern

Introduction


This is the fourth exercise in my Scala exercises series. If you haven’t seen it before, you may want to start from exercise 1: template method, exercise 2: observer design pattern and exercise 3: decorator and composite design patterns. Below is exercise 4: circuit breaker pattern.
Problem: Create a console program that reads commands from the user. If the command is "q", it will query a hard-coded URL (e.g., http://localhost:1234) and print the result to the console. If the command is "x", it will exit. Below is a sample session:
Enter: q
Hello <-- this is the content at the URL
Enter: q
Hello <-- ditto
Enter: x
Exiting

In practice, if the remote server is overloaded, out of order or the firewall is mis-configured, every time you try to access the URL, it may take up to several minutes for your client to timeout or receive an error. It would also place unnecessary load on that server which possibly is already overloaded. Therefore, a better way to do it is, if the server returns an error (or does that for a consecutive number of times), your client will not try to access it anymore (treat it as an error immediately), until the administrator resets it. This is called the "circuit breaker" pattern.
Now, your task is to implement this behavior by filling in the code below. There is also a new command "r" to reset the circuit breaker. For simplicity, you'll stop calling the server as long as one exception is caught.


//it extends the CircuitBreaker trait to obtain the functionality. Unit is the return
//type of the code block to be protected by the circuit breaker.
object HttpClient extends CircuitBreaker[Unit] {
def main(args: Array[String]) {
while (true) {
print("Enter: ")
try {
readLine match {
case "q" => queryHttpServer
case "r" => reset
case "x" => {
println("Exiting")
return
}
case _ => println("Unknown command")
}
} catch {
case e: Exception => e.printStackTrace
}
}
}

def queryHttpServer {
//run the code block in the protect() method
protect {
... //get the content at http://localhost:1234
}
}
}

trait CircuitBreaker[T] {
var isOpen = false

//run the code block only if the circuit breaker is not open. If it is,
//thrown an CircuitOpenException immediately.
def protect(codeBlock: ...): T = {
...
}

def reset {
println("Resetting the circuit")
isOpen = false
}
}

class CircuitOpenException extends Exception

In addition, for your own testing, you can create a simple HTTP server with netcat. Just run:
  echo -e "HTTP/1.0 200 OK\n\nHello\n" | nc -l 1234

It will quit after serving one request. So, you need to run it again to serve multiple requests.
Try to do it now! Then, click here to see the answer.