Skip to content

Commit e822104

Browse files
committed
fix: handle condition waiting better in thread_task_executor
The pattern used for the condition waiting was not robust enough and was susceptible to a race condition. This prevents that class of race condition by persisting the status and checking it when the signal is received, rather then relying on the assumption the notification always happens after all the relevant waiters are ready to receive it. JIRA: CQ-2677 risk: low
1 parent 0b272b4 commit e822104

1 file changed

Lines changed: 5 additions & 1 deletion

File tree

packages/gooddata-flight-server/src/gooddata_flight_server/tasks/thread_task_executor.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ class _TaskExecution:
158158
"_result_future",
159159
"_lock",
160160
"_completed",
161+
"_done",
161162
"_stats",
162163
)
163164

@@ -189,6 +190,8 @@ def __init__(
189190
# all these are protected using the lock
190191
self._result_future: Future[Union[TaskResult, TaskError]] | None = None
191192
self._completed: threading.Condition = threading.Condition(self._lock)
193+
# indicates the task actually finished
194+
self._done: bool = False
192195

193196
@property
194197
def task(self) -> Task:
@@ -235,6 +238,7 @@ def on_result_done(self, fut: Future) -> None:
235238

236239
with self._lock:
237240
execution_result = self._cb.process_task_result(self, self._result_future)
241+
self._done = True
238242
self._completed.notify_all()
239243

240244
self._complete_execution_span(execution_result)
@@ -291,7 +295,7 @@ def cancel(self) -> bool:
291295

292296
def wait_for_completion(self, timeout: float | None = None) -> None:
293297
with self._lock:
294-
completed = self._completed.wait(timeout=timeout)
298+
completed = self._completed.wait_for(lambda: self._done, timeout=timeout)
295299

296300
if not completed:
297301
raise TaskWaitTimeoutError(task_id=self._task.task_id, cmd=self._task.cmd)

0 commit comments

Comments
 (0)