dartist / redis_client

A high-performance async/non-blocking Redis client for Dart
BSD 2-Clause "Simplified" License
100 stars 29 forks source link

callback missing when use Future.wait #42

Open himulawang opened 10 years ago

himulawang commented 10 years ago
IRedisHandlerPool redisPool = new IRedisHandlerPool();

  redisPool.init(store['redis'])
  .then((_) {
    List waitList = [];
    User user = new User()..setPK(1);
    RedisClient handler = new IRedisHandlerPool().getReaderHandler(UserRedisStore.store, user);
    /*
    waitList..add(UserRedisStore.get(1, 'u:1'))
            ..add(UserRedisStore.get(2, 'u:1'));
            */
    waitList
      ..add(handler.hmget('u:1:1', user.getMapAbb().keys).then((_) => print(1)))
      ..add(handler.hmget('u:1:2', user.getMapAbb().keys).then((_) => print(2)))
      ..add(handler.hmget('u:1:3', user.getMapAbb().keys).then((_) => print(3)))
      ..add(handler.hmget('u:1:4', user.getMapAbb().keys).then((_) => print(4)))
      ..add(handler.hmget('u:1:5', user.getMapAbb().keys).then((_) => print(5)))
    ;

    return Future.wait(waitList);
  })
  .then((List list) => print(list));

output

/home/ila/ide/dart/dart-sdk/bin/dart --ignore-unrecognized-flags --debug:43375 --package-root=/home/ila/project/i_dart/packages/ /home/ila/project/i_dart/test/test.dart
Redis connected.
1
2

callback from 3 to 5 was not called

bbss commented 10 years ago

I'm not certain what causes this. Do you get any exceptions? I haven't done much with multiple requests yet, and am yet to look in to implementing MULTI.

himulawang commented 10 years ago

no exception throws. just wait there.

I use MONITOR command, Seems redis has received the command.

bbss commented 10 years ago
test('Future.wait HMGET', () {
  async(
    client.hset('first-hash', 'some-key','some-value').then((_) => 
    client.hset('second-hash', 'some-key', 'some-value').then((_) =>
    client.hset('third-hash', 'some-key', 'some-value').then((_) {
      List waitList = [];
      waitList..add(client.hmget('first-hash', ['some-key']));
      waitList..add(client.hmget('second-hash', ['some-key']));
      waitList..add(client.hmget('third-hash', ['some-key']));

      return Future.wait(waitList);
    }).then(print))));

works for me.

himulawang commented 10 years ago

I can't use pub get after upgrade to 1.1.0-dev.5.6 at home. I will confirm this again at company next Monday.

Thanks

himulawang commented 10 years ago

Hi

I use hmget to get one field, it's OK

waitList
      ..add(handler.hmget('u:1:1', ['a']).then((_) => print(1)))
      ..add(handler.hmget('u:1:2', ['a']).then((_) => print(2)))
      ..add(handler.hmget('u:1:3', ['a']).then((_) => print(3)))
    ;
/home/ila/ide/dart/dart-sdk/bin/dart --ignore-unrecognized-flags --debug:40514 --package-root=/home/ila/project/i_dart/packages/ /home/ila/project/i_dart/test/test.dart
Redis connected.
1
2
3
[null, null, null]

But if i change to multiple fields

waitList
      ..add(handler.hmget('u:1:1', ['a', 'b']).then((_) => print(1)))
      ..add(handler.hmget('u:1:2', ['a', 'b']).then((_) => print(2)))
      ..add(handler.hmget('u:1:3', ['a', 'b']).then((_) => print(3)))
    ;

callback missing

/home/ila/ide/dart/dart-sdk/bin/dart --ignore-unrecognized-flags --debug:44698 --package-root=/home/ila/project/i_dart/packages/ /home/ila/project/i_dart/test/test.dart
Redis connected.
1
2
bbss commented 10 years ago

I will have a look tomorrow.

himulawang commented 10 years ago

Thanks

bbss commented 10 years ago

I am looking into it. But also very busy so I can't make any promises for when it will be finished.

himulawang commented 10 years ago

Not the problem, just take your time.

I use dart for fun, not for work.

Any clue show where the problem is? I'm not familar with redis protocol, but maybe I can help

himulawang commented 10 years ago

any progress?

bbss commented 10 years ago

I am currently very busy as I just arrived in Shanghai for an internship, as you can see in the referenced PR I had a look today and found something that might give a clue as to what makes this bug happen (the clue being the wrong callback being fulfilled) however since I can not reproduce I am still left in the dark a bit.

What I was thinking about before is making use of darts' Zone API to get a better callstack for the errors. However I have not thought for very long about different solutions, and if this will actually work for the time-outs.

Question for @himulawang , can you run all_tests normally?

himulawang commented 10 years ago

Haha... What a coincidence! I am Chinese from Shanghai. But today I am leaving for Japan for a trip. Back to S.H. at 02.12. C u later.

himulawang commented 10 years ago

I can't run all_tests normally.

Two questions:

First,

.then((String value) => expect(value, equals("16.800000000000001")))

this line causes:

Uncaught Error: Expected: '16.800000000000001' Expected: '16.800000000000001' Actual: '16.8' Actual: '16.8' Which: is different. Both strings start the same, but the given value is missing the following trailing characters: 0000000000 ... Which: is different. Both strings start the same, but the given value is missing the following trailing characters: 0000000000 ...

Second, after I block this line,

output:

/home/ila/ide/dart/dart-sdk/bin/dart --ignore-unrecognized-flags --debug:52060 --package-root=/home/ila/project/redis_client/packages/ /home/ila/project/redis_client/test/all_tests.dart

unittest-suite-wait-for-done

just wait there.

This result just like Future.wait. Callback missing.

himulawang commented 10 years ago

I'm looking into this problem.


// source from redis_connection.dart

socket.transform(new StreamTransformer.fromHandlers(handleData: handleData, handleError:   handleError, handleDone: handleDone))
  .listen(_onRedisReply, onError: _onStreamError, onDone: _onStreamDone);

I add 3 hmget requests to waitList, and handleData function is only called 2 times.

Seems the response is missing in StreamTransformer.

also, I find another problem. Ref: https://github.com/dartist/redis_client/issues/48

himulawang commented 10 years ago

Today I find what's really happening in this problem.

When you send 2 commands in a very short time, Redis will response 2 requests with one net package.

So handleData function is invoked only once.

Send one command a time:

void handleData(List<int> data, EventSink<RedisReply> output) {
print(data)

//[42, 50, 13, 10, 36, 45, 49, 13, 10, 36, 45, 49, 13, 10]

Send two command a time:

void handleData(List<int> data, EventSink<RedisReply> output) {
print(data)

//[42, 50, 13, 10, 36, 45, 49, 13, 10, 36, 45, 49, 13, 10, 42, 50, 13, 10, 36, 45, 49, 13, 10, 36, 45, 49, 13, 10]

What we should do is create a buffer pool, a callback queue, every time a handleData is invoked, check the buffer pool, get first valid reply, cut it out, and get the first function from callback queue, call it with reply.

We can see this as ref: https://github.com/mranney/node_redis/blob/master/index.js