mirror of https://github.com/qt/qtgrpc.git
Emit cancelled finished() in channel implementation
Currently, the QGrpcOperation was finishing itself so that the channel implementation should only cancel the corresponding RPC. This is the only place such self-finishing is used. Let the channel implementation rather take care of the cancellation logic and emit the finished signal. The actual handler implementation is responsible for itself, i.e. finished meaning it's done and no communication will happen through this stream. Simplify the logic for timeouts and requested cancellations. Update the deadline testcase to not check for specific messages but rather for non-empty messages. Changes will only be relevant for custom channel implementation. [ChangeLog][QGrpcOperationContext][Important Behavior Changes] Cancellation logic should also emit finished now. Custom QAbstractGrpcChannel implementations should adapt their logic. Pick-to: 6.10 6.9 6.8 Change-Id: Ic4e70b50afe46b5a883f099a6cf245ea9a0e66c1 Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
This commit is contained in:
parent
3fea4be230
commit
814c0b6ac2
|
|
@ -286,6 +286,7 @@ public:
|
|||
|
||||
void finish(const QGrpcStatus &status);
|
||||
void asyncFinish(const QGrpcStatus &status);
|
||||
void cancelWithStatus(const QGrpcStatus &status);
|
||||
|
||||
[[nodiscard]] bool expired() const { return !m_operation; }
|
||||
|
||||
|
|
@ -299,10 +300,13 @@ public:
|
|||
}
|
||||
|
||||
// context slot handlers:
|
||||
void cancel();
|
||||
void cancel() { cancelWithStatus({ StatusCode::Cancelled, tr("Cancelled by client") }); }
|
||||
void writesDone();
|
||||
void writeMessage(QByteArrayView data);
|
||||
void deadlineTimeout();
|
||||
void deadlineTimeout()
|
||||
{
|
||||
cancelWithStatus({ StatusCode::DeadlineExceeded, tr("Deadline exceeded") });
|
||||
}
|
||||
|
||||
void handleHeaders(const HPack::HttpHeader &headers, HeaderPhase phase);
|
||||
|
||||
|
|
@ -437,10 +441,8 @@ Http2Handler::Http2Handler(QGrpcOperationContext *operation, QGrpcHttp2ChannelPr
|
|||
// QHttp2Stream will handle any outstanding cancellations appropriately.
|
||||
QObject::connect(operation, &QGrpcOperationContext::destroyed, this,
|
||||
&Http2Handler::deleteLater);
|
||||
QObject::connect(operation, &QGrpcOperationContext::cancelRequested, this, [this] {
|
||||
cancel();
|
||||
deleteLater();
|
||||
});
|
||||
QObject::connect(operation, &QGrpcOperationContext::cancelRequested, this,
|
||||
&Http2Handler::cancel);
|
||||
QObject::connect(operation, &QGrpcOperationContext::writesDoneRequested, this,
|
||||
&Http2Handler::writesDone);
|
||||
if (!m_endStreamAtFirstData) {
|
||||
|
|
@ -704,7 +706,7 @@ void Http2Handler::asyncFinish(const QGrpcStatus &status)
|
|||
QTimer::singleShot(0, m_operation.get(), [this, status]() { finish(status); });
|
||||
}
|
||||
|
||||
void Http2Handler::cancel()
|
||||
void Http2Handler::cancelWithStatus(const QGrpcStatus &status)
|
||||
{
|
||||
if (m_state >= State::Cancelled)
|
||||
return;
|
||||
|
|
@ -718,6 +720,8 @@ void Http2Handler::cancel()
|
|||
qGrpcDebug("Failed cancellation on stream: %p, Handler::state: %s", m_stream.get(),
|
||||
QDebug::toBytes(m_state).data());
|
||||
}
|
||||
|
||||
finish(status);
|
||||
}
|
||||
|
||||
void Http2Handler::writesDone()
|
||||
|
|
@ -734,14 +738,6 @@ void Http2Handler::writesDone()
|
|||
processQueue();
|
||||
}
|
||||
|
||||
void Http2Handler::deadlineTimeout()
|
||||
{
|
||||
Q_ASSERT_X(m_stream, "onDeadlineTimeout", "stream is not available");
|
||||
|
||||
cancel();
|
||||
finish({ StatusCode::DeadlineExceeded, "Deadline Exceeded" });
|
||||
}
|
||||
|
||||
void Http2Handler::handleHeaders(const HPack::HttpHeader &headers, HeaderPhase phase)
|
||||
{
|
||||
// ABNF syntax: Rule, [Optional-Rule], *Variable-Repetition
|
||||
|
|
|
|||
|
|
@ -149,13 +149,10 @@ bool QGrpcOperation::read(QProtobufMessage *message) const
|
|||
*/
|
||||
void QGrpcOperation::cancel()
|
||||
{
|
||||
if (!isFinished()) {
|
||||
if (isFinished())
|
||||
return;
|
||||
Q_D(QGrpcOperation);
|
||||
d->isFinished.storeRelaxed(true);
|
||||
emit d->operationContext->cancelRequested();
|
||||
Q_EMIT finished(QGrpcStatus{ QtGrpc::StatusCode::Cancelled,
|
||||
tr("Operation is cancelled by client") });
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -103,8 +103,9 @@ QT_BEGIN_NAMESPACE
|
|||
This signal is emitted by QGrpcOperation when requesting cancellation of the
|
||||
communication.
|
||||
|
||||
The channel is expected to connect its cancellation logic to this signal and
|
||||
attempt to cancel the RPC and return immediately. Successful cancellation
|
||||
The channel is expected to connect its cancellation logic to this signal
|
||||
and attempt to cancel the RPC and finish it with a
|
||||
\l{QtGrpc::StatusCode::}{Cancelled} status code. Successful cancellation
|
||||
cannot be guaranteed. Further processing of the data received from a
|
||||
channel is not required and should be avoided.
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ void QtGrpcClientDeadlineTest::channelDeadlineCallExceeds()
|
|||
|
||||
const auto code = qvariant_cast<QGrpcStatus>(finSpy.at(0).first());
|
||||
QCOMPARE_EQ(code.code(), QtGrpc::StatusCode::DeadlineExceeded);
|
||||
QCOMPARE_EQ(code.message(), QString("Deadline Exceeded"));
|
||||
QVERIFY(!code.message().isEmpty());
|
||||
}
|
||||
|
||||
void QtGrpcClientDeadlineTest::channelDeadlineCallFinishes()
|
||||
|
|
|
|||
Loading…
Reference in New Issue