Запрос Python gRPC периодически отсутствует

Я использую gRPC в python с django и django-grpc-framework.

Когда я запускаю unittest, в моем models.py есть кусок кода, который создает странную проблему: я запрашиваю три gRPC-запроса, но только один достигает серверной стороны.


Подробности проблемы

Чтобы упростить проблему, следующий код объясняет ситуацию:

class MyModel(models.Model):
    def some_method(self):
        for stub in [stub1, stub2, stub3]:
            resp = stub.RetractObject(base_pb2.RetractObjectRequest(
                app_label='...',
                object_type='...',
                object_id='...',
                exchange_id='...',
                remark='...',
                date_record='...',
            ))

Здесь метод some_method срабатывает в функции unittest django.test.TestCase, в то время как gRPC подключается к внешнему запущенному экземпляру сервера.

А соответствующие .proto файлы выглядят следующим образом:

// base.proto
// ...
message CreditRecord {
    int64 id = 1;
    string username = 2;
    string app_label = 3;
    string flag = 4;
    string object_type = 5;
    int64 object_id = 6;
    int64 amount = 7;
    int64 balance = 8;
    string remark = 9;
    string date_record = 10;
    string exchange_id = 11;
    int64 retract_ref = 12;
}

message RetractObjectRequest {
    string app_label = 1;
    string object_type = 2;
    int64 object_id = 3;
    string exchange_id = 4;
    string remark = 5;
    string date_record = 6;
}
// ...
// stub1 - stub3 has the similar structure below
syntax = "proto3";

package mjtest.growth;

import "mjtest/growth/base.proto";

service CreditController {
    // ...
    rpc RetractObject (RetractObjectRequest) returns (stream CreditRecord) {}
}

А код на стороне сервера выглядит примерно так (с использованием django-grpc-framework):

# services.py
class GenericCreditService(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericService):
    def RetractObject(self, request: base_pb2.RetractObjectRequest, context):
        print('Request reached!', request)
        # ...
        records = model_class.retract_object(...)
        # Here, records has aready return a list, not a iterator.
        for rec in records:
            yield self.serializer_class(rec).message

Итак, когда я запускаю unittest, сторона клиента вызывает ТРИ раза, чтобы запросить RetractObject gRPC-метод.

Но только ОДИН раз, когда Request reached! был напечатан.


Попытка №1: добавление sleep(0.5)

Я предполагаю, что есть какая-то проблема на стороне клиента, и я добавляю sleep(0.5) после каждого запроса.

class MyModel(models.Model):
    def some_method(self):
        for stub in [stub1, stub2, stub3]:
            resp = stub.RetractObject(base_pb2.RetractObjectRequest(...))
            sleep(0.5)

Тогда все три запроса достигают!


Попытка №2: обход ответа в явном виде.

Я предполагаю, что ответ потока без потребляемого может вызвать проблему, поэтому я передаю ответ в список явно.

class MyModel(models.Model):
    def some_method(self):
        for stub in [stub1, stub2, stub3]:
            resp = stub.RetractObject(base_pb2.RetractObjectRequest(...))
            list(resp)

Тогда все три запроса достигают!


Проблема настолько странная, и ни один из способов, которые я запрашиваю, не выдает ошибку.

Может ли кто-нибудь помочь?

Вернуться на верх