Capnproto - 在服务器回调中发出客户端请求

时间:2018-04-07 20:22:58

标签: c++ rpc capnproto

我需要在服务器回调中执行一些客户端请求,并且不确定在何处存储创建的capnp::EzRpcClientCompareNetwork::Client comparer对象。这是因为客户超出了范围(我认为 - 我只是得到了一个SEGFAULT,但这似乎是原因)。它基本上是一个主人,它将加载请求转发给它的奴隶(奴隶可以通过REG请求注册并存储他们的地址)。
那么 - 我应该在哪里/如何存储客户端对象?这有什么“最佳实践”吗?我认为暂时将它们存储在某个类成员变量中有点脏,不是吗?

GroupMaster2.cpp:

kj::Promise<void> GroupMaster2::CompareMasterImpl::load(LoadContext context) {
    auto loadData = context.getParams().getIds();

    slaveListLock.lock();

    auto promList = kj::Vector<kj::Promise<std::pair<std::string, CompareNetwork::Status>>>();

    for(auto& slave : slaveList) {
        try {
            capnp::EzRpcClient client(slave.second->address);
            CompareNetwork::Client comparer = client.getMain<CompareNetwork>();
            auto request = comparer.loadRequest();
            std::string addrCopy(slave.first);
            request.setIds(loadData);
            auto loadPromise = request.send();
            promList.add(loadPromise.then([addrCopy](auto response) {
                return std::make_pair(addrCopy, response.getStatus());
            },
            [&, addrCopy](kj::Exception && exception) {
                slaveListLock.lock();
                slaveList.erase(addrCopy);//something failed, remove this slave!
                slaveListLock.unlock();
                std::cout << "ErrLoad0: " << std::string(exception.getDescription()) << std::endl;
                return std::make_pair(addrCopy, CompareNetwork::Status::ERROR);
            }));
        }
        catch(...) {
            std::cout << "Error sending load to: " << slave.first << std::endl;
        }
    }

    slaveListLock.unlock();

    auto retProm = kj::joinPromises(promList.releaseAsArray()).then([&, KJ_CPCAP(context)](kj::Array<std::pair<std::string, CompareNetwork::Status>> res) mutable {
        bool error = false;

        for(auto& loadRes : res) {
            switch(loadRes.second) {
                case CompareNetwork::Status::OK: {
                        std::cout << "LOAD OK: " << loadRes.first << std::endl;
                        break;
                    }

                case CompareNetwork::Status::ERROR: {
                        std::cout << "LOAD ERROR: " << loadRes.first << std::endl;
                        error = true;
                        break;
                    }
            }
        }
        if(!error)
            context.getResults().setStatus(CompareNetwork::Status::OK);
        else
            context.getResults().setStatus(CompareNetwork::Status::ERROR);
    }, [](kj::Exception && exception) {
        std::cout << __FILE__ << ":" << __LINE__ << std::string(exception.getDescription()) << std::endl;
    }).eagerlyEvaluate([](kj::Exception && exception) {
        std::cout << __FILE__ << ":" << __LINE__ << std::string(exception.getDescription()) << std::endl;
    });
    std::cout << "ReturnedLoad" << std::endl;
    return retProm;
}

GroupNetworkData.capnp:

interface CompareNetwork {
  compare @0 (jobs :JobPartList) -> (res :JobResList);
  load @1 (ids :WIDList) -> (status :Status);

  struct JobPartList {
    jobParts @0 :List(JobPart);

    struct JobPart {
      jobs @0 :List(Job);
      startID @1 :UInt32;

      struct Job {
        wid1 @0 :UInt32;
        wid2 @1 :UInt32;
      }
    }
  }

  struct JobResList {
    jobResults @0 :List(JobRes);
    struct JobRes {
      jobIndex @0 :UInt32;
      result @1 :Float64;
    }
  }

  struct WIDList {
    ids @0 :List(WID);
    struct WID {
      id @0 :UInt32;
    }
  }

  enum Status {
    ok @0;
    error @1;
  }
}

interface CompareMaster extends(CompareNetwork) {
  reg @0 (data :SlaveData) -> (status :CompareNetwork.Status);
  struct SlaveData {
    perfInd @0 :Float64;
    maxMem @1 :UInt32;
    address @2 :Text;
  }
}

提前致谢! dvs23

1 个答案:

答案 0 :(得分:0)

C ++ 14似乎有答案:
How to capture a unique_ptr into a lambda expression?
使用kj :: heap在堆上分配两个对象,并将kj :: Own移动到回调lambda:

for(auto& slave : slaveList) {
    try {
        auto client = kj::heap<capnp::EzRpcClient>(slave.second->address);
        auto comparer = kj::heap<CompareNetwork::Client>(client->getMain<CompareNetwork>());
        auto request = comparer->loadRequest();
        std::string addrCopy(slave.first);
        request.setIds(loadData);
        auto loadPromise = request.send();
        promList.add(loadPromise.then([addrCopy, client = std::move(client), comparer = std::move(comparer)](auto response) {
            return std::make_pair(addrCopy, response.getStatus());
        },
        [&, addrCopy](kj::Exception && exception) {
            slaveListLock.lock();
            slaveList.erase(addrCopy);//something failed, remove this slave!
            slaveListLock.unlock();
            std::cout << "ErrLoad0: " << std::string(exception.getDescription()) << std::endl;
            return std::make_pair(addrCopy, CompareNetwork::Status::ERROR);
        }));
    }
    catch(...) {
        std::cout << "Error sending load to: " << slave.first << std::endl;
    }
}

欢迎更好的想法,但目前似乎运作良好:)