dart-drivers / mysql

MySQL Connector for Dart
Other
99 stars 38 forks source link

sqljocky blocks until a connection is available #38

Closed RedRoserade closed 10 years ago

RedRoserade commented 10 years ago

I was trying out sqljocky for a small project, to try and see if it was worth using Dart instead of NodeJS.

The setup was as follows: -A Dart HttpServer was running on localhost, and requests queried a MySQL database. It was running on Windows. -The database was present on an Ubuntu Server virtual machine. -sqljocky was configured to target MySQL running on such vm.

Everything was fine, until the day which I turned off the VM and made a request to the server, to see what happened if the db couldn't be reached.

What happened was that the first request came and sqljocky started querying the db, but until that connection attempt times out, no more requests were treated by the HttpServer, even if they weren't dependent on the db.

In NodeJS's MySQL connector, even if the db can't be reached, subsequent requests are treated asynchronously.

Here's an excerpt of my code (could be me screwing up!), starting with the code that queries the db:

// Create a connection pool to handle DB queries.
_sql.ConnectionPool _pool = new _sql.ConnectionPool(
  host: '192.168.56.101',
  user: 'psiapp',
  password: '**redacted**',
  db: 'letrinhas'
);

/// Fetches tests from the database, and returns them as a [Map].
_async.Future<Map<String, dynamic>> getTestsFromDb() {
  return _pool.query('SELECT * FROM Testes;')
      .then((results) => results.toList())
      .then((rows) {
        var data = <String, dynamic> {
          'tests': <Map<String, dynamic>>[],
          'success': 1
        };

        // For each row, we'll add a new test
        // object to the test list.
        data['tests'] = rows.map((row) => {
          // Whatever
        }).toList(growable: false);

        return data;
      })
      .catchError((e) {
        _printError(e);
        return <String, dynamic> {
          'tests': [],
          'success': 0
        };
      });
}

And finally, the code for the HttpServer:

void startServer() {
  _io.HttpServer.bind('0.0.0.0', 8080).then((server) {
    server.listen(_handleRequest);
  });

  print('Server running on 0.0.0.0:8080');
}

void _handleRequest(_io.HttpRequest req) {
  var formattedDate = formatDate();
  // Even if the db connection wasn't working, the server should at least print this if a new request came.
  print('[$formattedDate] Got a ${req.method} request to ${req.uri.path} from ${req.connectionInfo.remoteAddress.address}');

  if (req.method == 'POST') {
    // Handle POST requests.

    switch (req.requestedUri.path) {
      case '/postTestResults':
        // Whatever
    }
  } else if (req.method == 'GET') {
    switch (req.requestedUri.path) {
      case '/testList':
        _fetchTests(req);
        break;
      default:
        _sendNotFound(req);
    }
  } else {
    // If we got this far, it means something went wrong.
    _sendNotFound(req);
  }
}

void _fetchTests(_io.HttpRequest req) {
  tasks.getTestsFromDb()
      .then((data) {
        req.response.write(_convert.JSON.encode(data));
        req.response.close();

        print('[${formatDate()}]Sent results to the client!');
      });
}
jamesots commented 10 years ago

If you run this program, you'll get the same kind of results, so it's not a problem with sqljocky:

import 'dart:io';

main() {
  var x = 0;
  HttpServer.bind('localhost', 8089, backlog: 10).then((server) {
    server.listen((request) {
      x++;
      print("Handling request $x");
//      request.response.close();
    });
  });

  print('Server running');
}

The problem is that the web browser doesn't try to make a second request for a resource if there's already a request for it in progress. If you open up multiple browsers you'll find that the dart program is still responding to requests.

(I didn't know that until today!)

RedRoserade commented 10 years ago

Correct, it does happen to me as well with the code you posted, unless if the request comes from different browsers.

However, the code I sent does block even if the request comes from different browsers. In this picture, the requests came both from IE and Chrome. Chrome went first, and IE second, separated by about 2 to 3 seconds. IE's connection is taken only after the connection to the DB fails, which takes about 20 seconds.

captura de ecr 263

jamesots commented 10 years ago

That's strange. For me then it makes no difference whether I use your test code or mine - they both behave in the same way.

I can't think of any reason why making a connection to the mysql server would cause the http server to stop responding. Unless there's some bug in the Windows version of Dart which causes the VM to hang while connecting? I only have access to Linux machines at the moment.

RedRoserade commented 10 years ago

A quick test on my Ubuntu Server VM confirms what you said. It's most likely a Dart VM bug on the windows version. captura de ecr 264

I guess it's time to make a bug report, I don't know what's causing it though (probably something related to Sockets?). I at least know that's still present on Dart 1.3.0 on Windows.

RedRoserade commented 10 years ago

I reported this bug on the tracker, if you're interested. It does seem to be related to sockets. https://code.google.com/p/dart/issues/detail?id=18154&thanks=18154&ts=1397168596