question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Race condition when waiting on Promise resolved in other thread

See original GitHub issue

I’m using with LibUsb to achieve asynchronous transfers. Without going into too much details I’m using two threads:

  1. Worker: creates promise (P) and starts async USB transfer with supplied callback © that resolves promise. After starting transfer, thread wait for promise result.
  2. LibUSB event loop: triggers event processing in LibUSB, which will call callback C which will resolve promise and resume Worker thread.

All calls to LibUSB are native calls (ctypes).

Occasionally (one in hundreds) I’m getting AssertionFailed exception on this line: https://github.com/syrusakbary/promise/blob/master/promise/promise.py#L414 with traceback:

Traceback (most recent call last):
  File "C:\Python38\lib\threading.py", line 932, in _bootstrap_inner
    self.run()
  File "C:\Python38\lib\threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "<snip>", line 66, in _run
    packet = self._segmentation.read_packet()
  File "<snip>", line 60, in read_packet
    payload = self._low.low_read(part_size)
  File "<snip>.py", line 56, in low_read
    return bytes(ret.get())
  File "C:\Python38\lib\site-packages\promise\promise.py", line 511, in get
    self._wait(timeout or DEFAULT_TIMEOUT)
  File "C:\Python38\lib\site-packages\promise\promise.py", line 506, in _wait
    self.wait(self, timeout)
  File "C:\Python38\lib\site-packages\promise\promise.py", line 502, in wait
    async_instance.wait(promise, timeout)
  File "C:\Python38\lib\site-packages\promise\async_.py", line 117, in wait
    target.scheduler.wait(target, timeout)
  File "C:\Python38\lib\site-packages\promise\schedulers\immediate.py", line 24, in wait
    promise._then(on_resolve_or_reject, on_resolve_or_reject)
  File "C:\Python38\lib\site-packages\promise\promise.py", line 577, in _then
    target._add_callbacks(did_fulfill, did_reject, promise)
  File "C:\Python38\lib\site-packages\promise\promise.py", line 414, in _add_callbacks
    assert not self._rejection_handler0"
AssertionError

Traceback indicates that assertion failed in context on Worker thread.

I was able to create (sort of…) reproduction of this issue: https://github.com/Novakov/promise/tree/race-condition Unfortunately it’s not great. Running test https://github.com/Novakov/promise/blob/race-condition/tests/test_thread_safety.py#L122 shows the issue in most cases.

Investigation of Promise state suggests that in line https://github.com/syrusakbary/promise/blob/master/promise/promise.py#L577 promise is still pending, than context switch happens, promise gets resolved in loop thread, context switch happends again and _add_callbacks continues on now resolved promise.

Machine details OS: Windows 10 x64 CPU: 4 cores, 8 logical threads Python: 3.8.1 (tags/v3.8.1:1b293b6, Dec 18 2019, 23:11:46) [MSC v.1916 64 bit (AMD64)]

I was not able to reproduce the issue on Linux machine, however it maybe matter of probability

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:1
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
alex-vervecommented, Jul 16, 2020

I think I fixed the problem. Review is welcome https://github.com/syrusakbary/promise/pull/89

0reactions
alex-vervecommented, Jul 9, 2020

Also getting these errors (14 times per 2.5 million requests)

  File "/var/task/graphql/execution/executor.py", line 218, in complete_value_catching_error
    completed = complete_value(exe_context, return_type, field_asts, info, result)
, 
  File "/var/task/graphql/execution/executor.py", line 262, in complete_value
    lambda error: Promise.rejected(GraphQLLocatedError(field_asts, original_error=error))
, 
  File "/var/task/promise/promise.py", line 630, in then
    return self._then(did_fulfill, did_reject)
, 
  File "/var/task/promise/promise.py", line 577, in _then
    target._add_callbacks(did_fulfill, did_reject, promise)
, 
  File "/var/task/promise/promise.py", line 414, in _add_callbacks
    assert not self._rejection_handler0

We’re executing Threads with callbacks which resolve promise (similar to @Novakov case)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Is this a possible race condition if both promises resolve ...
It is not possible for two Promise instances to resolve simultaneously. One will happen before the other. Your situation calls for using Promise ......
Read more >
Fix race condition when pending Promise was resolved in other ...
Successfully merging this pull request may close these issues. Race condition when waiting on Promise resolved in other thread. 2 participants.
Read more >
Node.js race conditions
A race condition is a type of programming error that can occur when multiple processes or threads are accessing the same shared resource,...
Read more >
Promise.race() - JavaScript - MDN Web Docs
A Promise that asynchronously settles with the eventual state of the first promise in the iterable to settle. In other words, it fulfills...
Read more >
Reading 23: Mutual Exclusion
In order to address the races and deadlocks in checkout , we need to think more pessimistically. Every time we await a promise,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found