TL; DR: Devi chiamare sia grpc::Server::Shutdown()
e grpc::CompletionQueue::Shutdown()
(per ogni coda di completamento utilizzati nel servizio) a chiudere in modo pulito.
Se si chiama cq_->Shutdown()
, l'unico effetto osservabile è che le chiamate successive a Service::AsyncService::RequestFoo()
(metodo generato per il corrispondente Foo
RPC) sicuro con un'affermazione. Dalla lettura della documentazione del metodo API C corrispondente (grpc_completion_queue_shutdown()
), sembra che sia illegale aggiungere nuovi lavori alla coda — ovvero chiamando RequestFoo()
— così ho aggiunto un membro is_shutdown_
alle mie classi wrapper del servizio (protetto da un mutex) in modo che non vengano effettuati tentativi di accodamento dopo la chiamata a cq_->Shutdown()
. Tuttavia, dopo aver eseguito questa operazione, la coda di completamento si blocca indefinitamente in cq_->Next()
. Nessuno dei tag enqueued è completo (con un errore o altro).
Se invece si chiama server_->Shutdown()
, tutti i tag accodati vengono completati immediatamente (con ok == false
). Tuttavia, la coda di completamento continua a bloccare indefinitamente in cq_->Next()
.
Calling sia cq_->Shutdown()
(per ogni coda di completamento definito) e server_->Shutdown()
si traduce in un arresto pulito.
Un avvertimento: se si utilizza grpc::ServerContext::AsyncNotifyWhenDone()
per registrare un tag per la cancellazione delle chiamate, questi saranno non essere restituiti dal cq_->Next()
se il server si spegne prima che la richiesta iniziale è ricevuto per quella chiamata. Dovrai essere cauto con la gestione della memoria della struttura di tag corrispondente, se vuoi evitare perdite di memoria.