why is gRPC server side stuck after client is done streaming (client and server both written in dart)?

651 Views Asked by At

I want to upload an image from client to server in gRPC. For this purpose i have created the proto file below:

syntax = "proto3";

service EshopService {
    rpc UploadImage (stream ImageToUpload) returns (ImageLink);

}

message ImageToUpload {
    bytes image = 1;
}
message ImageLink {
    string image_links = 1;
}

in client in order to stream the image i have written the code below:

 Future<ImageLink> uploadImage(ImageToUpload image) async {
    return await stub.uploadImage(streamImage(images.image));

  }

  Stream<ImageToUpload> streamImage(List<int> image) async* {
    for (var element in image) {
      yield ImageToUpload(image: [element]);
    }
  }

then on server side I have the code below:

 Future<ImageLink> uploadImage(grpc.ServiceCall call, Stream<ImageToUpload> request) async {
    print('uploading');
    final List<int> image = [];
    await for (var bytes in request) {
      image.addAll(bytes.image);
    }
    print('image gotten');
    File imageFile = File('image.jpg');
    await imageFile.writeAsBytes(image);
    return ImageLinks(imageLinks: 'image');
  }
}

the image is sent to the server and it is being received (I know because I printed it out), but the server never gets out of the await for section. It gets stuck there even after the stream is complete and on client side I get the following error after a while

 gRPC Error (code: 4, codeName: DEADLINE_EXCEEDED, message: Deadline exceeded, details: null, rawResponse: null, trailers: {})

how do I let the server know that the stream is completed so it will get out of the for loop?

1

There are 1 best solutions below

0
On BEST ANSWER

I found the issue. It was because I was sending one byte at a time and that took too long, which resulted in a timeout at the client side. It got fixed when I changed it to 128 bytes in each stream. So basically I changed the client side code to this:

 Future<ImageLink> uploadImage(XFile image) async {
    return await stub.uploadImage(() async* {
      final imageBytes = await image.readAsBytes();
      int index = 0;
      while (index < imageBytes.length) {
        int lastIndex = index + 128;
        if (lastIndex > imageBytes.length) lastIndex = imageBytes.length;
        final data = ImageToUpload(
          image: imageBytes.sublist(index, lastIndex),
        );
        yield data;
        index = lastIndex;
      }
    }.call());
  }