@@ -35,14 +35,14 @@ void SetupSpan(
3535 std::string_view method_name
3636);
3737
38- grpc::Status ReportHandlerError (const std::exception& ex, CallState& state) noexcept ;
39-
40- void ReportRpcInterruptedError (CallState& state) noexcept ;
41-
4238grpc::Status ReportCustomError (const USERVER_NAMESPACE::server::handlers::CustomHandlerException& ex, CallState& state)
4339 noexcept ;
4440
45- void ReportFinish (bool finish_op_succeeded, const grpc::Status& status, CallState& state) noexcept ;
41+ grpc::Status ReportHandlerError (const std::exception& ex, CallState& state) noexcept ;
42+
43+ void ReportFinished (const grpc::Status& status, CallState& state) noexcept ;
44+
45+ void ReportInterrupted (CallState& state) noexcept ;
4646
4747template <typename Response>
4848void UnpackResult (Result<Response>&& result, std::optional<Response>& response, grpc::Status& status) {
@@ -64,6 +64,28 @@ void UnpackResult(StreamingResult<Response>&& result, std::optional<Response>& r
6464 }
6565}
6666
67+ template <typename CallTraits>
68+ bool Finish (
69+ impl::Responder<CallTraits>& responder,
70+ const std::optional<typename CallTraits::Response>& response,
71+ grpc::Status& status
72+ ) {
73+ if (status.ok ()) {
74+ if constexpr (IsServerStreaming (CallTraits::kCallKind )) {
75+ if (response.has_value ()) {
76+ return responder.Finish (*response);
77+ } else {
78+ return responder.Finish ();
79+ }
80+ } else {
81+ UINVARIANT (response.has_value (), " response should not be empty" );
82+ return responder.Finish (*response);
83+ }
84+ } else {
85+ return responder.FinishWithError (status);
86+ }
87+ }
88+
6789template <typename CallTraits>
6890class CallProcessor final {
6991public:
@@ -84,7 +106,7 @@ class CallProcessor final {
84106 )
85107 : state_(std::move(params), CallTraits::kCallKind ),
86108 responder_ (state_, raw_responder),
87- middleware_call_context_(utils::impl::InternalTag{}, state_),
109+ middleware_call_context_(utils::impl::InternalTag{}, state_, status_ ),
88110 initial_request_(initial_request),
89111 service_(service),
90112 service_method_(service_method)
@@ -102,52 +124,29 @@ class CallProcessor final {
102124 void DoCall () {
103125 RunOnCallStart ();
104126
127+ bool finished = false ;
128+
105129 // Don't keep the config snapshot for too long, especially for streaming RPCs.
106130 state_.config_snapshot .reset ();
107131
108- // Final response is the response sent to the client together with status in the final batch.
109- std::optional<Response> final_response;
110-
111- if (!Status ().ok ()) {
112- RunOnCallFinish (final_response);
113- impl::ReportFinish (responder_.FinishWithError (Status ()), Status (), state_);
114- return ;
132+ std::optional<Response> response;
133+ if (!engine::current_task::ShouldCancel () && status_.ok ()) {
134+ RunWithCatch ([this , &response] {
135+ auto result = CallHandler ();
136+ impl::UnpackResult (std::move (result), response, status_);
137+ });
115138 }
116139
117- RunWithCatch ([this , &final_response] {
118- auto result = CallHandler ();
119- impl::UnpackResult (std::move (result), final_response, Status ());
120- });
121-
122- // Streaming handler can detect RPC breakage during a network interaction => IsInterrupted().
123- // RpcFinishedEvent can signal RPC interruption while in the handler => ShouldCancel.
124- if (responder_.IsInterrupted () || engine::current_task::ShouldCancel ()) {
125- impl::ReportRpcInterruptedError (state_);
126- // Don't run OnCallFinish.
127- return ;
140+ if (!engine::current_task::ShouldCancel () && !responder_.IsInterrupted ()) {
141+ RunOnCallFinish (response);
142+ finished = impl::Finish (responder_, response, status_);
128143 }
129144
130- if (!Status ().ok ()) {
131- RunOnCallFinish (final_response);
132- impl::ReportFinish (responder_.FinishWithError (Status ()), Status (), state_);
133- return ;
134- }
135-
136- RunOnCallFinish (final_response);
137-
138- if (!Status ().ok ()) {
139- impl::ReportFinish (responder_.FinishWithError (Status ()), Status (), state_);
140- return ;
141- }
142-
143- if constexpr (IsServerStreaming (CallTraits::kCallKind )) {
144- if (!final_response) {
145- impl::ReportFinish (responder_.Finish (), Status (), state_);
146- return ;
147- }
145+ if (finished) {
146+ impl::ReportFinished (status_, state_);
147+ } else {
148+ impl::ReportInterrupted (state_);
148149 }
149- UASSERT (final_response);
150- impl::ReportFinish (responder_.Finish (*final_response), Status (), state_);
151150 }
152151
153152private:
@@ -169,37 +168,37 @@ class CallProcessor final {
169168 UASSERT (success_pre_hooks_count_ == 0 );
170169 for (const auto & m : state_.middlewares ) {
171170 RunWithCatch ([this , &m] { m->OnCallStart (middleware_call_context_); });
172- if (!Status () .ok ()) {
171+ if (!status_ .ok ()) {
173172 return ;
174173 }
175174 // On fail, we must call OnRpcFinish only for middlewares for which OnRpcStart has been called successfully.
176175 // So, we watch to count of these middlewares.
177176 ++success_pre_hooks_count_;
178177 if constexpr (std::is_base_of_v<google::protobuf::Message, InitialRequest>) {
179178 RunWithCatch ([this , &m] { m->PostRecvMessage (middleware_call_context_, initial_request_); });
180- if (!Status () .ok ()) {
179+ if (!status_ .ok ()) {
181180 return ;
182181 }
183182 }
184183 }
185184 }
186185
187- void RunOnCallFinish (std::optional<Response>& final_response ) {
186+ void RunOnCallFinish (std::optional<Response>& response ) {
188187 const auto & mids = state_.middlewares ;
189188 const auto rbegin = mids.rbegin () + (mids.size () - success_pre_hooks_count_);
190189 for (auto it = rbegin; it != mids.rend (); ++it) {
191190 const auto & middleware = *it;
192191
193192 if constexpr (std::is_base_of_v<google::protobuf::Message, Response>) {
194- if (Status () .ok () && final_response .has_value ()) {
195- RunWithCatch ([this , &middleware, &final_response ] {
196- middleware->PreSendMessage (middleware_call_context_, *final_response );
193+ if (status_ .ok () && response .has_value ()) {
194+ RunWithCatch ([this , &middleware, &response ] {
195+ middleware->PreSendMessage (middleware_call_context_, *response );
197196 });
198197 }
199198 }
200199
201200 // We must call all OnRpcFinish despite the failures. So, don't check the status.
202- RunWithCatch ([this , &middleware] { middleware->OnCallFinish (middleware_call_context_, Status () ); });
201+ RunWithCatch ([this , &middleware] { middleware->OnCallFinish (middleware_call_context_, status_ ); });
203202 }
204203 }
205204
@@ -208,23 +207,22 @@ class CallProcessor final {
208207 try {
209208 func ();
210209 } catch (MiddlewareRpcInterruptionError& ex) {
211- Status () = ex.ExtractStatus ();
210+ status_ = ex.ExtractStatus ();
212211 } catch (ErrorWithStatus& ex) {
213- Status () = ex.ExtractStatus ();
212+ status_ = ex.ExtractStatus ();
214213 } catch (const USERVER_NAMESPACE::server::handlers::CustomHandlerException& ex) {
215- Status () = impl::ReportCustomError (ex, state_);
214+ status_ = impl::ReportCustomError (ex, state_);
216215 } catch (const RpcInterruptedError& /* ex*/ ) {
217216 UASSERT (responder_.IsInterrupted ());
218217 // RPC interruption will be reported below.
219218 } catch (const std::exception& ex) {
220- Status () = impl::ReportHandlerError (ex, state_);
219+ status_ = impl::ReportHandlerError (ex, state_);
221220 }
222221 }
223222
224- grpc::Status& Status () { return middleware_call_context_.GetStatus (utils::impl::InternalTag{}); }
225-
226223 CallState state_;
227224 Responder responder_;
225+ grpc::Status status_;
228226 MiddlewareCallContext middleware_call_context_;
229227 // Initial request is the request which is sent to the service together with RPC initiation.
230228 // Unary-request RPCs have an initial request, client-streaming RPCs don't.
0 commit comments