Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bad state: Cannot write to socket, it is closed on query close #44

Open
sanmadjack opened this issue Jul 11, 2014 · 2 comments
Open

Bad state: Cannot write to socket, it is closed on query close #44

sanmadjack opened this issue Jul 11, 2014 · 2 comments
Assignees

Comments

@sanmadjack
Copy link

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 think the query close either needs to be changed to return a Future that doesn't complete until the query is actually closed, or the query close needs to be changed to be able to deal with the closed socket.

Code to replicate the issue:

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();
      });
  });
}
@sanmadjack
Copy link
Author

I've encountered an additional variation of this, when running this code:

Future _putMethod(RestRequest request) {
  return new Future.sync(() {
    mysql.ConnectionPool pool = getConnectionPool();

      return pool.prepare("SELECT name FROM files").then((mysql.Query query) {
        return query.execute().then((result) {
          return result.first.then((row) {
            return row.first;
          });
        }).then((_) {
         _log.info("Closing");
        });
      }).then((_) {
        pool.close();
      });
  });
}

This produces:

Uncaught Error: Bad state: Cannot read from socket, it is closed
Stack Trace: 
#0      BufferedSocket.readBuffer (package:sqljocky/src/buffered_socket.dart:156:7)
#1      _handleHeader (package:sqljocky/src/connection.dart:144:25)
#2      _rootRunUnary (dart:async/zone.dart:730)
#3      _RootZone.runUnary (dart:async/zone.dart:864)
#4      _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:488)
#5      _Future._propagateToListeners (dart:async/future_impl.dart:571)
#6      _Future._completeWithValue (dart:async/future_impl.dart:331)
#7      _Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:393)
#8      _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:23)
#9      _asyncRunCallback (dart:async/schedule_microtask.dart:32)
#10     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:128)


Unhandled exception:
Bad state: Cannot read from 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)

Which is similar to above, but you can see that this one is failing on a read, rather than a write. These errors are preventing me from managing the connection in my application, though I am also wondering if I am doing it wrong. My app is set up as an http server that creates a new connectionpool object for each request. I did this after noting that one global pool object wasn't playing nice when I tried to perform additional requests while a long-running request was running (sorry I don't have the message it used to give me, I changed and moved on). One pool per request resolved this issue, but that means I have to deliberately manage all queries and pools, but these errors are making that quite difficult. Is there a mistake in my understanding?

@sanmadjack
Copy link
Author

So, I switched back to one global pool in my project after figuring out the issue I was having with concurrent connections (I opened another ticket for what I discovered there), so this is not as important to me now. I did also find you documentation where you state that calling close on the pool is dangerous, thought I think that making query.close a future so that we can wait for it to finish is a good idea.

@jamesots jamesots self-assigned this Jul 14, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants