1

I am getting this exception when I close the pool very soon after closing a query:

Uncaught Error: Bad state: Cannot write to socket, it is closed
Stack Trace: 
#0      BufferedSocket.writeBufferPart (package:sqljocky/src/buffered_socket.dart:114:7)
#1      BufferedSocket.writeBuffer (package:sqljocky/src/buffered_socket.dart:108:27)
#2      _Connection._sendBufferPart (package:sqljocky/src/connection.dart:261:31)
#3      _Connection._sendBuffer (package:sqljocky/src/connection.dart:249:29)
#4      _Connection.processHandler (package:sqljocky/src/connection.dart:289:16)
#5      ConnectionPool._closeQuery.<anonymous closure> (package:sqljocky/src/connection_pool.dart:220:29)
#6      _rootRunUnary (dart:async/zone.dart:730)
#7      _RootZone.runUnary (dart:async/zone.dart:864)
#8      _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:488)
#9      _Future._propagateToListeners (dart:async/future_impl.dart:571)
#10     _Future._completeWithValue (dart:async/future_impl.dart:331)
#11     _Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:393)
#12     _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:23)
#13     _asyncRunCallback (dart:async/schedule_microtask.dart:32)
#14     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:128)


Unhandled exception:
Bad state: Cannot write to socket, it is closed
#0      _rootHandleUncaughtError.<anonymous closure>.<anonymous closure> (dart:async/zone.dart:713)
#1      _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:23)
#2      _asyncRunCallback (dart:async/schedule_microtask.dart:32)
#3      _asyncRunCallback (dart:async/schedule_microtask.dart:36)
#4      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:128)

the issue seems to be that the query close fires of a Future internally, so the close() function returns before the close is actually finished:

void _closeQuery(Query q, bool retain) {
  _log.finest("Closing query: ${q.sql}");
  for (var cnx in _pool) {
    var preparedQuery = cnx.removePreparedQueryFromCache(q.sql);
    if (preparedQuery != null) {
      _waitUntilReady(cnx).then((_) {
        _log.finest("Connection ready - closing query: ${q.sql}");
        var handler = new _CloseStatementHandler(preparedQuery.statementHandlerId);
        cnx.autoRelease = !retain;
        cnx.processHandler(handler, noResponse: true);
      });
    }
  }
}

The pool close happens immediately, it closes the socket right away. This means the query close (which is delayed till after the pool close due to the Future) fails, unable to send whatever information it needs to through the socket. I've opened a ticket to sqljocky at https://github.com/jamesots/sqljocky/issues/44 but I've received no replies, and I need a workaround if it's going to take a while to get a response.

This code has allowed me to replicate the issue 100% of the time:

Future _putMethod(RestRequest request) {
  return new Future.sync(() {
  mysql.ConnectionPool pool = getConnectionPool();
    return pool.prepare("SELECT * FROM files").then((mysql.Query query) {
      return query.execute().then((result) {
        // Do something?
      }).then((_) {
        this._log.info("Closing");
        query.close();
      });
    }).then((_) {
      pool.close();
    });
  });
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
SanMadJack
  • 388
  • 1
  • 4
  • 14

2 Answers2

0

This is yet more a question than an answer but I can't put this code in a comment in a usable way.

You should ensure that you return the Future returned from every async invocation. I don't know if the lines where I added the comment // added return are async invocations.

Can you please try and give feedback if this changes anything.

Future _putMethod(RestRequest request) {
  return new Future.sync(() {
  mysql.ConnectionPool pool = getConnectionPool();
    return pool.prepare("SELECT * FROM files").then((mysql.Query query) {
      return query.execute().then((result) {
        // Do something? // also ensure that a Future of an async invocation is returned
      }).then((_) {
        this._log.info("Closing");
        return query.close(); // added return
      });
    }).then((_) {
      return pool.close(); // added return
    });
  });
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Neither query.close nor pool.close return a Future. Internally they are async, but they don't give me the ability to wait for that async to complete. That's what the ticket I opened with the creator is about, making those return Futures. – SanMadJack Jul 14 '14 at 13:47
0

I solved an issue like that by going to the mysql terminal relative to the connection (in workbench) and run:

mysql>resetconnection