Skip to content

Commit 311adc8

Browse files
TaskContext should not trigger cancellation. (#833)
TaskContext should not trigger cancellation after request was completed. This could happen when the execution function keeps the last owning reference to the object that cancels task context in destruction. Resolves: OLPSUP-10456 Signed-off-by: Mykhailo Kuchma <[email protected]>
1 parent f8437a8 commit 311adc8

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

olp-cpp-sdk-core/include/olp/core/client/TaskContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ class CORE_API TaskContext {
228228
response.GetError().GetErrorCode() == ErrorCode::RequestTimeout)) {
229229
user_response = std::move(response);
230230
}
231+
232+
// Reset the context after the task is finished.
233+
context_ = CancellationContext();
231234
}
232235

233236
if (callback) {

olp-cpp-sdk-core/tests/client/TaskContextTest.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,42 @@ TEST(TaskContextTest, CancelToken) {
216216
EXPECT_EQ(response.GetError().GetErrorCode(), ErrorCode::Cancelled);
217217
}
218218

219+
TEST(TaskContextTest, OLPSUP_10456) {
220+
// Cancel should not be triggered from the inside of Execute function.
221+
// This happens when the execution function is keeping the last owning
222+
// reference to the object that cancels the task in the destructor.
223+
struct TaskWrapper {
224+
~TaskWrapper() { context->BlockingCancel(std::chrono::milliseconds(0)); }
225+
std::shared_ptr<TaskContext> context;
226+
};
227+
228+
auto wrapper = std::make_shared<TaskWrapper>();
229+
230+
bool cancel_triggered = false;
231+
auto cancel_function = [&]() { cancel_triggered = true; };
232+
233+
ExecuteFunc execute_func = [&, wrapper](CancellationContext c) -> Response {
234+
c.ExecuteOrCancelled([&]() { return CancellationToken(cancel_function); });
235+
return std::string("Success");
236+
};
237+
238+
Response response;
239+
Callback callback = [&](Response r) { response = std::move(r); };
240+
241+
// Initialize the task context
242+
wrapper->context = std::make_shared<TaskContext>(
243+
TaskContext::Create(std::move(execute_func), std::move(callback)));
244+
245+
TaskContext task_context = *(wrapper->context).get();
246+
247+
// Now execute_func is the only owner of task context via TaskWrapper.
248+
wrapper.reset();
249+
250+
// Execute the execute_func,
251+
task_context.Execute();
252+
253+
EXPECT_EQ(response.GetResult(), "Success");
254+
EXPECT_FALSE(cancel_triggered);
255+
}
256+
219257
} // namespace

0 commit comments

Comments
 (0)