Retry an Unreliable Operation
Problem
An operation can fail by throwing an exception. The first line is the maximum number of attempts N. The second line has the results of the calls, one letter for each call in order: S for success and F for failure (the operation throws). Call the operation again after a failure, up to N attempts in total. Print success after K attempts (M failures) as soon as an attempt works, or gave up after N attempts when all N attempts failed. K is the number of the successful attempt and M the number of failed attempts before it.
Constraints
- 1 <= N <= 100
- enough results for N calls
Examples
Input
3 F F S
Output
success after 3 attempts (2 failures)
Solutions
A retry loop must have a limit, or a permanent failure would loop forever. Real programs also wait between attempts (often longer each time: exponential backoff) and retry only errors that can go away, such as a network timeout, not a wrong password.
/*
* Problem : Process lines.
* Input : Several lines.
* Output : The result.
* Approach: A limit and the results of the calls.
* Time : O(N)
* Space : O(1)
* Java : 8 or newer.
*/
import java.util.Scanner;
public class Main {
// Step 1: The unreliable operation takes its results from a list. A failure is an exception.
static class Operation {
private final String[] results;
private int position = 0;
Operation(String[] results) {
this.results = results;
}
void run() {
if (results[position++].equals("F")) {
throw new IllegalStateException("operation failed");
}
}
}
// This method solves the task. It receives the input and returns the answer.
static String solve(String[] lines) {
int limit = Integer.parseInt(lines[0].trim());
Operation operation = new Operation(lines[1].trim().split(" "));
int failures = 0;
// Step 2: Try again after each failure until the limit is reached.
for (int attempt = 1; attempt <= limit; attempt++) {
try {
operation.run();
return "success after " + attempt + " attempts (" + failures + " failures)";
} catch (IllegalStateException error) {
// Step 3: Count the failure and go to the next attempt.
failures++;
}
}
// Step 4: After the last attempt we give up. We do not hide the failure: we report it.
return "gave up after " + limit + " attempts";
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
java.util.List<String> all = new java.util.ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (!line.isEmpty()) {
all.add(line);
}
}
String[] lines = all.toArray(new String[0]);
System.out.println(solve(lines));
}
}
Hints (1)
- Which errors should not be retried?