0

There are 2 backend machines which will provide the same content. I'm trying to create a round-robin setup and fail-safe so that if one goes down, the request should be sent to other.

As for the round-robin thing, my code is working fine.

For the fail-safe thing, I'm trying to change one IP to some invalid ip (on which no service is running) and then it should connect to other. But it is getting hung up on the line:

client = new Socket(ip, port);

What can be done for this? If I'm not getting connection in 2 seconds, I don't want to retry (if that is what java does, can I reduce the retry timeout?).

Also, after long time, it throws IllegalStateException (I was not expecting it at all)

Here is my constructor for Connect.java:

//Variable declartion

private static int balancer = 0;
private static boolean[] down = {false, false};
private static int[] countDown = {0, 0};
private static final int maxRequests = 10000;
private static int countRequests = 0;

//Constructor
public Connect() throws NullPointerException{
    int use = balancer;
    int flag = 0;

    countRequests = (countRequests + 1) % maxRequests;
    if(countRequests == 0){
        down[0] = down[1] = false;
    }

    if((balancer == 0 && down[0] == false) || down[1] == true){
        ip = Config.IP1;
        port = Config.PORT1;
        use = 0;
        System.out.println("balancer = 0");
    }
    else{
        ip = Config.IP2;
        port = Config.PORT2;
        use = 1;
        System.out.println("balancer = 1");
    }
     LOGGER.setLevel(Level.INFO);
     // Single simple socket 
     try {
        client = new Socket(ip, port);
        System.out.println("client");
        dos = new DataOutputStream(client.getOutputStream());
        dis = new DataInputStream(client.getInputStream());
        if(client == null || dos == null || dis == null){
            throw new IOException("Connection could not be opened properly\n");
        }
        LOGGER.log(Level.INFO, "Connection to : " + ip + " Successfully opened");
        balancer = (balancer == 0) ? 1 : 0;
        countDown[use] = 0;
        flag = 1;
     } catch (IOException e) {
        // TODO Auto-generated catch block
        //e.printStackTrace();
        countDown[use] ++;
        if(countDown[use] >= 3){
            down[use] = true;
        }
        LOGGER.log(Level.SEVERE, ": " + ip + " " + e.getMessage());
     }
     finally{       //if connection was not opened on first 
         if(flag == 0){
             if(use == 0){
                 ip = Config.IP2;
                 port = Config.PORT2;
                 use = 1;
             }
             else{
                 ip = Config.IP1;
                 port = Config.PORT1;
                 use = 0;
             }
             try {
                    client = new Socket(ip, port);
                    dos = new DataOutputStream(client.getOutputStream());
                    dis = new DataInputStream(client.getInputStream());
                    if(client == null || dos == null || dis == null){
                        throw new IOException("Connection could not be opened properly\n");
                    }
                    LOGGER.log(Level.INFO, "Connection to  " + ip + " Successfully opened");
                    balancer = (balancer == 0) ? 1 : 0;
                    countDown[use] = 0;
                    flag = 1;
                 } catch (IOException e) {
                    // TODO Auto-generated catch block
                    //e.printStackTrace();
                    countDown[use] ++;
                    if(countDown[use] >= 3){
                        down[use] = true;
                    }
                    LOGGER.log(Level.SEVERE, ": " + ip + " " + e.getMessage());
                    throw new NullPointerException("Connection could not be opened properly on both machines\n");
                 }
         }
     }
}

What I expected was an IO/NullPointer-Exception and then catch block will be executed

vish4071
  • 5,135
  • 4
  • 35
  • 65
  • Out of curiosity: unless this is for "learning purposes"; what is the sense of implementing something yourself ... that has been done many times before; and that, well, is **hard** to get right? You see, your source code indicates that you are an absolute beginner with Java ... so: do you really think re-inventing the wheel is a good start to gain practice? – GhostCat Dec 29 '15 at 14:58
  • @Jägermeister, why do you say, `hard` to get right. It was a simple implementation so I thought I'd do it myself, considering our system shoud not have any single point of failure. – vish4071 Dec 29 '15 at 15:08
  • Nothing that is dealing with multiple, distributed systems is **easy**. And if your system consists of more code like the one you posted; it is already a failure. Sorry to say that; but this code is absolutely horrible. – GhostCat Dec 29 '15 at 15:13
  • I marked the post duplicate myself...though I tried searching before but was not using the correct keywords it seems. – vish4071 Dec 29 '15 at 15:13
  • @Jägermeister, Actually this was a specific scenario and we are not looking at more back-end machines anytime soon (probably not at all), so this was a bit hard-coded. I'd like to know why you say this code is horrible (I'd like to learn- I'm a beginner alright) or what can be improved. We can have some discussion if you have time. – vish4071 Dec 29 '15 at 15:18
  • Some more keywords you want to google: it seems that you don't understand the difference between static fields and members/attributes of classes. You do **everything** within one constructor. You are using boolean and ints as flags; where you could be using enums. If we were in the same room; we could talk about almost each line of code for 10, 20 minutes. My two suggestions for you: lookout for an experienced java programmer (or a whole group of them). Show them your code; and ask for feedback. Then: read "clean code" by Robert Martin. That should get you going ... – GhostCat Dec 29 '15 at 15:27

1 Answers1

0

How about using the default Socket() constructor, and then connect(SocketAddress, int), which allows you to specify a specific timeout?

Example:

import java.net.*;
public class Test {
  public static void main(String[] args) throws Exception {
    Socket socket = new Socket();
    socket.connect(new InetSocketAddress(args[0], 80), 2000);
  }
}

You can see the timeout in action by timing it:

$ time java Test google.com

real    0m0.154s
user    0m0.079s
sys     0m0.022s

$ time java Test 192.168.2.123
Exception in thread "main" java.net.SocketTimeoutException: connect timed out
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at Test.main(Test.java:5)

real    0m2.111s
user    0m0.076s
sys     0m0.026s
Vlad
  • 18,195
  • 4
  • 41
  • 71