vert.x goes to dead lock

363 views
Skip to first unread message

omid pourhadi

unread,
Jul 12, 2017, 7:25:10 AM7/12/17
to vert.x
Hi,

I'm running a vert.x fat jar  on a server with java -jar fatjar.jar command contains following code.

after sending a few requests everything freezes and no result come out.

package com.test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.Map;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.ext.jdbc.JDBCClient;
import io.vertx.ext.sql.ResultSet;
import io.vertx.ext.sql.SQLConnection;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;

/**
 * @author omidp
 *
 */

public class TransactionResource extends AbstractVerticle
{

   
public static final String LOG_FILE = "/opt/vertx_log.txt";

   
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionResource.class);
   
   

   
@Override
   
public void start() throws Exception
   
{
        vertx
.executeBlocking(b -> {
            vertx
.fileSystem().createFileBlocking(LOG_FILE);
       
}, rh -> {
           
System.out.println("log file is ready");
       
});
       
//
       
JsonObject dbconfig = new JsonObject().put("url", "jdbc:oracle:thin:@//127.0.0.1:1521/mydb").put("user", "test")
               
.put("password", "test").put("max_pool_size", 30)
               
.put("provider_class", "io.vertx.ext.jdbc.spi.impl.C3P0DataSourceProvider")
               
.put("driver_class", "oracle.jdbc.driver.OracleDriver");
       
JDBCClient client = JDBCClient.createShared(vertx, dbconfig);
       
//
       
Router router = Router.router(vertx);
        router
.route().handler(BodyHandler.create());
       
TestTransactions testTx = new TestTransactions(client);
        router
.route("/trx").failureHandler(h -> {
           
SQLConnection conn = h.get("conn");
           
if (conn != null)
           
{
                conn
.close(v -> {
                    log
("connection closed");
               
});
           
}
            sendError
(h);
       
}).handler(testTx::handle);
        vertx
.createHttpServer().requestHandler(router::accept).listen(8585);
       
System.out.println("Test Transaction server is up...");
        log
("Test Transaction server is up...");
   
}

   
public static class TestTransactions
   
{
       
private JDBCClient client;
       
       
public EpurseTransactions(JDBCClient client)
       
{
           
this.client = client;
       
}

       
public void handle(RoutingContext rc)
       
{

           
HttpServerResponse response = rc.response();
            response
.putHeader("content-type", "application/json");
           
//
           
String panno = rc.request().params().get("panno");
           
if (panno == null || panno.trim().length() == 0)
           
{
                sendError
(rc);
               
return;
           
}
           
final JsonArray params = new JsonArray();
           
params.add(panno);

           
String where = rc.request().params().get("where");
            log
("WHERE QUERY : " + where);

           
//
           
            client
.getConnection(res -> {
               
if (res.succeeded())
               
{
                   
try
                   
{

                       
SQLConnection connection = res.result();
                        rc
.put("conn", connection);
                       
StringBuffer queryString = new StringBuffer();
                        queryString
.append(" SELECT *   FROM (SELECT a.*, rownum rn  FROM ( ");
                        queryString
.append("select * ")
                               
.append(" from trx tx  ").append(" left join trm t on  ")
                               
.append(" tx.TRMID = t.TRMID where tx.PAN = ? ");
                       
// where
                       
if (where != null && where.trim().length() > 0)
                            createQuery
(queryString, where, params);
                       
//
                        queryString
.append(" order by tx.TXNDATELOCAL desc ) a ");
                        queryString
.append(" WHERE rownum <= ?) b WHERE b.rn >= ? ");
                       
String pageParam = rc.request().params().get("page");
                       
int page = (pageParam == null || pageParam.length() == 0) ? 0 : Integer.parseInt(pageParam);
                       
//
                       
String perPageParam = rc.request().params().get("per_page");
                       
int perPage = (perPageParam == null || perPageParam.length() == 0) ? 10 : Integer.parseInt(perPageParam);
                       
//
                       
if (page != 0)
                       
{
                           
params.add((page + 1) * perPage);
                           
params.add((page * perPage) + 1);
                       
}
                       
else
                       
{
                           
params.add(10);
                           
params.add(0);
                       
}
                       
StringBuilder sb = new StringBuilder().append("[");
                        log
(queryString.toString());
                       
//
                        rc
.response().putHeader("X-Pagination-Per-Page", String.valueOf(perPage));
                        rc
.response().putHeader("X-Pagination-Current-Page", String.valueOf(page));
                       
//
                       
StringBuffer countQuery = new StringBuffer();
                        countQuery
.append("select count(*) as cnt ").append(" from trx tx  ").append(" left join trm t on  ")
                               
.append(" tx.TRMID = t.TRMID where tx.PAN = ? ");

                       
//
                        connection
.queryWithParams(queryString.toString(), params, rs -> {
                           
if (rs.succeeded())
                           
{
                               
int i = 0;
                               
ResultSet result = rs.result();
                               
for (JsonObject line : result.getRows())
                               
{
                                   
if (i > 0)
                                        sb
.append(", ");
                                    sb
.append(line.encode());
                                    i
++;
                               
}
                                sb
.append("]");
                               
//
                                log
("execute count query : " + countQuery.toString());
                               
final JsonArray cntParams = new JsonArray();
                                cntParams
.add(panno);
                               
if (where != null && where.trim().length() > 0)
                                    createQuery
(countQuery, where, cntParams);
                                connection
.queryWithParams(countQuery.toString(), cntParams, cnt -> {
                                   
if (cnt.succeeded())
                                   
{
                                       
if (perPage > 0)
                                       
{
                                           
ResultSet cntRes = cnt.result();
                                            rc
.response().putHeader("X-Pagination-Total-Pages",
                                                   
String.valueOf(cntRes.getRows().iterator().next().getLong("CNT") / perPage));
                                       
}
                                   
}
                                   
else
                                   
{
                                        log
(cnt.cause().getMessage());
                                   
}
                                    response
.end(sb.toString());
                                    connection
.close();
                               
});

                           
}
                       
});

                   
}
                   
catch (Exception e)
                   
{
                        log
(e.getMessage());
                        sendError
(rc);
                       
SQLConnection conn = rc.get("conn");
                       
if (conn != null)
                       
{
                            conn
.close(v -> {
                           
});
                       
}
                   
}

               
}
               
else
               
{
                   
// Failed to get connection - deal with it
                    log
("Connection failed");
                    sendError
(rc);
                   
SQLConnection conn = rc.get("conn");
                   
if (conn != null)
                   
{
                        conn
.close(v -> {
                       
});
                   
}

               
}
           
});

       
}

       
private void createQuery(StringBuffer queryString, String where, JsonArray arr)
       
{

           
QueryBuilder qb = new QueryBuilder(where);
           
List<String> properties = qb.getProperties();
           
Map<String, Object> values = qb.getValues();
           
int k = 0;
           
for (String prop : properties)
           
{
                queryString
.append(" AND ").append(prop);
               
String operator = qb.getOperators().get(k);
               
if (QueryBuilder.EQ.equals(operator))
               
{
                    queryString
.append("= ? ");
                    arr
.add(values.get(prop));
               
}
               
if (QueryBuilder.GT.equals(operator))
               
{
                    queryString
.append("> ? ");
                    arr
.add(values.get(prop));
               
}
               
if (QueryBuilder.GTE.equals(operator))
               
{
                    queryString
.append(">= ? ");
                    arr
.add(values.get(prop));
               
}

                k
++;
           
}
       
}
   
}

   
public static void log(String content)
   
{
       
try
       
{
           
Files.write(Paths.get(LOG_FILE), content.concat("\n\r").getBytes(), StandardOpenOption.APPEND);
       
}
       
catch (IOException e)
       
{
           
// DO NOTHING
       
}
   
}

   
public static void sendError(RoutingContext rc)
   
{
        rc
.response().setStatusCode(500).end("{\"msg\" : \"invalid data\", \"type\": 500}");
   
}

   
public static void main(String[] args)
   
{
       
Runner.runExample(TransactionResource.class);      
   
}

}

It is a simple REST service which is selecting from Oracle database .I am using the latest version of vert.x.  Am I doing it wrong ?

ad...@cs.miami.edu

unread,
Jul 12, 2017, 10:48:17 PM7/12/17
to vert.x
Have you tried isolating where/when the "deadlock" occurs?  If I were you I would slowly and systematically remove portions of the code (to move towards a simpler verticle), eventually as you trim it down, it will likely start to work.  While this will not be the functionality you ultimately want, it will help you find out where the error is. 

-Adam

omid pourhadi

unread,
Jul 13, 2017, 12:44:05 AM7/13/17
to vert.x
Thank you for  your response.

I put some logs in my applications and realized it must be related to database connections

I have a few questions :

1. Which one is better ? create a JDBCClient on testTx::handle method or the way I use it (pass it to constructor) ?
2. Can I use one connection for multiple queries or I should use client.getConnection for each query ?
3. Which one is correct first response.end(sb.toString()); then connection.close(); or vice versa ?

ad...@cs.miami.edu

unread,
Jul 13, 2017, 12:48:04 PM7/13/17
to vert.x
Hi,

Your posted code has LOTS of moving parts (lots of code).  I recommend that you do a simple minimal verticle that responds with a simple databasae querry.  Strip out all of the query builder code, and just hardcode in a simple SQL query.  The vercile should then be only about 2 dozen lines of code.  Then you will likey see what works and what does not work, and it will be easier for us to go through your code.

-Adam


On Wednesday, July 12, 2017 at 7:25:10 AM UTC-4, omid pourhadi wrote:

omid pourhadi

unread,
Jul 16, 2017, 7:58:48 AM7/16/17
to vert.x
I changed my code and  narrowed it down to only two queries one for count and one for select and hope for vert.x at least could do that, After application remains idle for approximately 45 minutes, the first request takes approximately 12 minutes to respond then everything back to work again just fine. in order to solve this issue, I scheduled a dummy request every 5 minutes but I think this behavior from vert.x is weird. BTW this is the cleanest code I can write in vert.x for a simple select query with json response and pagination.

public class TransactionResource extends AbstractVerticle
{

   
public static final String LOG_FILE = "/opt/vertx_log.txt";

   
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionResource.class);

   
@Override
   
public void start() throws Exception
   
{
        vertx
.executeBlocking(b -> {
            vertx
.fileSystem().createFileBlocking(LOG_FILE);
       
}, rh -> {
           
System.out.println("log file is ready");
       
});
       
//

       
JsonObject dbconfig = new JsonObject().put("max_pool_size", 250)

               
.put("provider_class", "io.vertx.ext.jdbc.spi.impl.C3P0DataSourceProvider")
               
.put("driver_class", "oracle.jdbc.driver.OracleDriver");
       
JDBCClient client = JDBCClient.createShared(vertx, dbconfig);
       
//
       
Router router = Router.router(vertx);
        router
.route().handler(BodyHandler.create());
       
TestTransactions testTx = new TestTransactions(client);
        router
.route("/trx").failureHandler(h -> {
           
SQLConnection conn = h.get("conn");
           
if (conn != null)
           
{
                conn
.close(v -> {
                    log
("connection closed");
               
});
           
}
            sendError
(h);
       
}).handler(testTx::handle);
        vertx
.createHttpServer().requestHandler(router::accept).listen(8585);

       
System.out.println(" server is up...");
        log
(" server is up...");

   
}

   
public static class TestTransactions
   
{
       
private JDBCClient client;


       
public TestTransactions(JDBCClient client)

       
{
           
this.client = client;
       
}

       
public void handle(RoutingContext rc)
       
{

       
final String panno = "123456789";
       
final String where = "";
            client
.getConnection(ar -> {
               
if (ar.failed())
               
{
                    LOGGER
.error("Could not open a database connection", ar.cause());
               
}
               
else
               
{
                   
SQLConnection connection = ar.result();
                    rc
.put("conn", connection);
                   
final QueryParameters countQuery = createCountQuery(panno, where);
                    connection
.queryWithParams(countQuery.getQuery(), countQuery.getParams(), res -> {
                        connection
.close();
                       
if (res.failed())
                       
{
                            log
("query failed");
                            LOGGER
.error("query failed", ar.cause());
                            sendError
(rc);
                       
}
                       
else
                       
{
                            rc
.response().putHeader("X-Pagination-Total-Pages", "140");
                            createJsonResult
(client, where, params, rc);
                       
}
                   
});
               
}
           
});
       
}

       
private void createJsonResult(JDBCClient dbclient, String where, JsonArray qparams, RoutingContext rc)
       
{
           
QueryParameters qp = createListQuery(where, qparams);
            dbclient
.getConnection(res -> {
               
SQLConnection result = res.result();

                result
.queryWithParams(qp.getQuery(), qp.getParams(), rs -> {
                   
StringBuilder sb = new StringBuilder();
                    result
.close();
                   
ResultSet queryResult = rs.result();
                    sb
.append("[");
                   
int i = 0;
                   
for (JsonObject line : queryResult.getRows())

                   
{
                       
if (i > 0)
                            sb
.append(", ");
                        sb
.append(line.encode());
                        i
++;
                   
}
                    sb
.append("]");

                    rc
.response().end(sb.toString());
               
});
           
});
       
}

       
private QueryParameters createCountQuery(String panno, String where)
       
{
           
StringBuffer countQuery = new StringBuffer("select count(*) from view");          
           
return new QueryParameters(countQuery.toString(), cntParams);
       
}

       
private QueryParameters createListQuery(String where, JsonArray params)
       
{
           
StringBuffer queryString = new StringBuffer("select * from view");
           
return new QueryParameters(queryString.toString(), params);
       
}

       
public static class QueryParameters
       
{
           
private String query;
           
private JsonArray params;

           
public QueryParameters(String query, JsonArray params)
           
{
               
this.query = query;
               
this.params = params;
           
}

           
public String getQuery()
           
{
               
return query;
           
}

           
public void setQuery(String query)
           
{
               
this.query = query;
           
}

           
public JsonArray getParams()
           
{
               
return params;
           
}

           
public void setParams(JsonArray params)
           
{
               
this.params = params;

omid pourhadi

unread,
Jul 16, 2017, 8:25:01 AM7/16/17
to vert.x
This wasn't vert.x fault, it was sth on Oracle network connection settings all connections had been closed after 30 minutes and vert.x connection pool didn't know about that . consider this thread closed.
vert.x rocks and thank you for gentle guide to asynchronous programming with Eclipse Vert.x for Java developers document.

Julien Ponge

unread,
Jul 18, 2017, 3:10:14 PM7/18/17
to ve...@googlegroups.com
vert.x rocks and thank you for gentle guide to asynchronous programming with Eclipse Vert.x for Java developers document. 

Thanks :-) 
Reply all
Reply to author
Forward
0 new messages