Oracle connection timeout inside a Azure Function that cancels at 5mins - oracle

I have the following lines of code inside a Java function:
try{
context.getLogger().info("Paso001");
Class.forName("oracle.jdbc.driver.OracleDriver");
context.getLogger().info("Paso002");
Connection conn = DriverManager.getConnection(
params.get().getConnection(), params.get().getUser(), params.get().getPassword());
if (conn != null) {
context.getLogger().info("Connected to the database!");
} else {
context.getLogger().log(Level.SEVERE, "No connection to the database!");
return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR).body("Error").build();
}
context.getLogger().info("Paso003");
PreparedStatement sentencia = conn.prepareStatement(params.get().getSentence());
int index = 0;
for (Param param : params.get().getParams()) {
index++;
if (param.getType().equals("String")) {
sentencia.setString(index, param.getValue());
} else {
sentencia.setInt(index, Integer.parseInt(param.getValue()));
}
}
ResultSet rs=sentencia.executeQuery();
JSONArray result = JsonHelper.recordList2Json(rs);
context.getLogger().info(result.toString());
return request.createResponseBuilder(HttpStatus.OK).body(result.toString()).build();
} catch(Exception e)
{
context.getLogger().info("Paso00-err");
context.getLogger().log(Level.SEVERE, e.toString());
}
Loging only shows "Paso001" and "Paso002" but connection fails at 300000 ms (5 minutes) because no "Paso00-err" is shown in the logs. I assume that Azure Function is reaching maximum time.
Azure Function is inside a VNET integration and DATABASE is inside another local NET behind an ExpressRoute.
I have assumed that Firewall is correct because opening socket to Host:Port inside the funcion seems ok:
InetAddress IPv4 = null;
try {
IPv4 = InetAddress.getByName(connect.get().getHost());
} catch (UnknownHostException e) {
result = e.toString();
e.printStackTrace();
return request.createResponseBuilder(HttpStatus.OK).body(result.toString()).build();
}
try {
Socket s = new Socket(IPv4, Integer.parseInt(connect.get().getPort()));
result = "Server is listening on port " + connect.get().getPort()+ " of " + connect.get().getHost();
context.getLogger().info(result);
s.close();
}
catch (IOException ex) {
// The remote host is not listening on this port
result = "Server is not listening on port " + connect.get().getPort()+ " of " + connect.get().getHost();
context.getLogger().info(result);
}
Result gets: "Server is listening on port port of host host
Note. I get same error pointing to a public database installed locally.
Is there anything else missing to open? Any ideas?
Edit: I have rewritten code with .NET CORE 3.11...
using (OracleCommand cmd = con.CreateCommand())
{
try
{
log.LogInformation("step001");
con.Open();
log.LogInformation("step002");
cmd.BindByName = true;
cmd.CommandText = sentence;
OracleDataReader reader = cmd.ExecuteReader();
log.LogInformation("step003");
return new OkObjectResult(reader2Json(reader));
}
catch (Exception ex)
{
return new OkObjectResult("Error: "+ex.ToString());
}
}
and similar results but this time exception is going thrown:
Error: Oracle.ManagedDataAccess.Client.OracleException (0x80004005): Connection request timed out
at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword, OracleConnection connRefForCriteria)
at Oracle.ManagedDataAccess.Client.OracleConnection.Open()
at Oracli2.Function1.Run(HttpRequest req, ILogger log) in C:\proy\vscode\dot2\Oracli2\Oracli2\Function1.cs:line 50

You can increase the function time out in the hosts.json file, just so you are aware of that, but I dont think increasing it will fix your issue, 5 minutes is a generous time, unless the query you are running here does in-fact take longer than 5 minutes to return!
Can you set the retry_count & retry_delay for your connection string something small (eg: 3 tries) so you know that the time out is not because of trying to do 100 retries and not see the actual underlying error
Other issues could be to do with connectivity, best bet would be to go into the Kudu Console for the console app, open up SSH and via SSH see if you can connect to your oracle db and run a test query from here, if it's all working from here then connectivity is not the issue.

Related

Sonarlint multiple closes

With this code :
Connection connection = null;
PreparedStatement req = null;
try {
connection = DriverManager.getConnection(url, user, password);
req = connection.prepareStatement(SQL);
} finally {
if (connection != null) {
connection.close();
}
if (req != null) {
req.close();
}
}
SonarLint says :
Close this "PreparedStatement" in a "finally" clause on line 5 (req = ...)
And when i close req first :
Close this "Connection" in a "finally" clause on line 4 (connection = ...)
How can I make SonarLint happy ?
Assuming you are using java.sql.Connection, your code can still end up with resources not being closed at the end of the execution.
If you look at the Connection.close() method signature from Java 6 javadoc, you will see that it can throw a SQLException. Consequently, as you are already in the finally block and if an exception occurs while closing, your code will exit the method without closing the request.
Now, if you invert the close order and start with the request, the same thing can happen. Calling close() can fail, then the connection is never closed, as from the finally block you jump once again directly outside the method.
In order to close both resources properly, I would recommend to deal with it like this:
Connection connection = null;
try {
connection = DriverManager.getConnection(url, user, password);
PreparedStatement req = null;
try {
req = connection.prepareStatement(sql);
} finally {
if (req != null) {
req.close();
}
}
} finally {
if (connection != null) {
connection.close();
}
}

Spring Scheduled Task, strange behavior

I have a Scheduled task which runs every 800 seconds from a server towards its clients to see if they are online. If they are not, it will send me an email, and will send an email when they are back online.
So, this is the scheduled task
#Scheduled(fixedDelay = 800000)
public void pingAllClients() {
logger.debug("Schedule pingClients");
List<Client> clients = clientService.findAllClients();
Iterator<Client> it = clients.iterator();
while (it.hasNext()) {
Client client = it.next();
String ip = client.getCurrentIp();
int idClient = client.getIdClient();
boolean isOnline = client.isOnline();
try {
boolean reachable = reachClient.isReachable(ip);
if (reachable) {
if (!isOnline) {
logger.debug("Client " + idClient + " back online");
client.setOnline(true);
clientService.updateClient(client);
smtp.sendEmail(serverName, ip, true);
}
} else {
logger.debug("Client " + idClient + " not available");
if (isOnline) {
client.setOnline(false);
clientService.updateClient(client);
smtp.sendEmail(serverName, ip, false);
}
}
} catch (Exception e) {
logger.error("Errore", e);
}
}
}
}
reachClient.isReachable(ip) is this method:
public boolean isReachable(String ip){
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(ip, 22), 50*1000);
return true;
} catch (IOException e) {
return false;
} finally {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
So, it should be: every 800 seconds i loop my clients, see if the are reachable or not, and if they change status, i will receive an email. In the email i print the date/time of the request.
It always happens that i get an email from an offline client and soon after (2-10 seconds) an email it is back online, as, for the same client, i'm getting 2 emails in a single iteration, how is it possibile? Each client should be reachable or not for every loop, not both...
The last 2 emails I got are (6 seconds delay)
Client 192.168.42.13 is offline - Date: 11-12-2016 17:14:30
Client 192.168.42.13 back online - Date: 11-12-2016 17:14:36

Android BluetoothLE Disconnection issue

I'm rebuilding a ble app that will commnunicate with a bluetooth device.
The code I found had this odd method called after closing the connection,
bluetoothGatt.disconnect();
which will call the onStateChangeCallback.
The method is this;
private void refreshDeviceCache(final BluetoothGatt gatt) {
int cnt = 0;
boolean success = false;
try {
if (gatt != null) {
final Method refresh = gatt.getClass().getMethod("refresh");
if (refresh != null) {
success = (Boolean) refresh.invoke(gatt);
while (!success && cnt < 100) {
success = (Boolean) refresh.invoke(gatt);
cnt++;
}
Log.e(TAG, "retry refresh : " + cnt + " " + success);
}
}
} catch (Exception e) {
Log.e(TAG, "5", e);
}
}
I can't totally understand what this code will do, but in conclusion, it slows down the connection after the disconnection. It does not slow down the disconnection.
I really can't understand this because after I get the BluetoothProfile.STATE_DISCONNECTED, I will close the bluetoothGatt, and on the broadCastReceiver, unbind the service and close the service itself.
On the connection phase, the service will be recreated.
What line of that code on disconnection may slow down the connection? Please help me out with this.

Windows phone a socket operation encountered a dead network

I am trying to get the IP address of networks like Wi-Fi,Data Network. I use the following class to find the IP.
public class MyIPAddress
{
Action<IPAddress> FoundCallback;
UdpAnySourceMulticastClient MulticastSocket;
const int PortNumber = 50000; // pick a number, any number
string MulticastMessage = "FIND-MY-IP-PLEASE" + new Random().Next().ToString();
public void Find(Action<IPAddress> callback)
{
FoundCallback = callback;
MulticastSocket = new UdpAnySourceMulticastClient(IPAddress.Parse("239.255.255.250"), PortNumber);
MulticastSocket.BeginJoinGroup((result) =>
{
try
{
MulticastSocket.EndJoinGroup(result);
GroupJoined(result);
}
catch (Exception ex)
{
// Debug.WriteLine("EndjoinGroup exception {0}", ex.Message);
// This can happen eg when wifi is off
FoundCallback(null);
}
},
null);
}
void callback_send(IAsyncResult result)
{
}
byte[] MulticastData;
bool keepsearching;
void GroupJoined(IAsyncResult result)
{
MulticastData = Encoding.UTF8.GetBytes(MulticastMessage);
keepsearching = true;
MulticastSocket.BeginSendToGroup(MulticastData, 0, MulticastData.Length, callback_send, null);
while (keepsearching)
{
try
{
byte[] buffer = new byte[MulticastData.Length];
MulticastSocket.BeginReceiveFromGroup(buffer, 0, buffer.Length, DoneReceiveFromGroup, buffer);
}
catch (Exception ex)
{
// Debug.WriteLine("Stopped Group read due to " + ex.Message);
keepsearching = false;
}
}
}
void DoneReceiveFromGroup(IAsyncResult result)
{
string str = "";
IPEndPoint where;
int responselength = MulticastSocket.EndReceiveFromGroup(result, out where);
byte[] buffer = result.AsyncState as byte[];
if (responselength == MulticastData.Length && buffer.SequenceEqual(MulticastData))
{
str = where.Address.ToString();
keepsearching = false;
FoundCallback(where.Address);
}
Console.WriteLine(str);
}
}
I was successful to find out the IP address of connected Wi-Fi. I turn off Wi-Fi and turn on the Data Connection. I am not able to get the IP address of connected network. I got the error ** a socket operation encountered a dead network**. I have also refer this question A socket operation encountered a dead network. How can I solve this problem ?
Question is a bit old, but answer may be useful for someone:
You get this error, because your MyIPAddress class can only find a local IP (the address inside your internal WiFi network, behind router). To get an external IP address you should call an external server that will tell you your IP (eg. whatismyip.com).

Connect to an oracle db in jdbc over an SSH tunnel

Currently we have to tunnel over SSH to access our Oracle database. In order to do this we have to make sure than putty or an equivalent program/script is running on the server doing this tunelling before the application is deployed to Tomcat/Glassfish/etc.
Has anybody found a way to have java handle this tunneling transparently? Perhaps a jdbc driver than itself wraps another jdbc drive handling the tunnelling for you right in Java?
My solution was to use Jsch from JCraft http://www.jcraft.com/jsch/ to open a tunnel when my application server starts up. I close the tunnel when the application server shuts down. I do this via a servlet context listener.
int findUnusedPort() {
final int startingPort = 1025;
final int endingPort = 1200;
for (int port = 1025; port < 1200; port++) {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
return port;
} catch (IOException e) {
System.out.println("Port " + port + "is currently in use, retrying port " + port + 1);
} finally {
// Clean up
if (serverSocket != null) try {
serverSocket.close();
} catch (IOException e) {
throw new RuntimeException("Unable to close socket on port" + port, e);
}
}
}
throw new RuntimeException("Unable to find open port between " + startingPort + " and " + endingPort);
}
private Session doSshTunnel(int tunnelPort) {
// SSH Tunnel
try {
final JSch jsch = new JSch();
sshSession = jsch.getSession("username", "sshhost", 22);
final Hashtable<String, String> config = new Hashtable<String, String>();
config.put("StrictHostKeyChecking", "no");
sshSession.setConfig(config);
sshSession.setPassword("password");
sshSession.connect();
int assigned_port = sshSession.setPortForwardingL(tunnelPort, remoteHost, remotePort);
return sshSession;
} catch (Exception e) {
throw new RuntimeException("Unable to open SSH tunnel", e);
}
}
I have used Apache MINA SSHD for a project a while back and I remember that there was support ofr opening tunnels.
You can check out http://mina.apache.org/sshd/ for more info.
Other options are discussed on this quesiton : SSH library for Java

Resources