Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ThreadSafeSingleton provides None if called from separate thread while an earlier call is still processing. #433

Closed
garlandhu opened this issue Mar 23, 2021 · 2 comments
Assignees
Labels

Comments

@garlandhu
Copy link

Hello, 4.6.0 seems to have created an issue with providers.ThreadSafeSingleton.

If the singleton object to be created has a lengthy init time, and the provider is called a second time while the first one is still being created from a seperate thread, the second call returns None instead of the object.

You can recreate this issue with the example below.

import threading
import unittest
from dependency_injector import providers


class ThingThatTakesLongTimeToInitAndNeedsToBeSingleton:
	def __init__(self):
		self.j = 0
		for i in range(1000000):
			self.j += i


provider_of_annoying_object = providers.ThreadSafeSingleton(
	ThingThatTakesLongTimeToInitAndNeedsToBeSingleton
)


class WorkerThatCanMoveToThreadAndCallProvider:

	def __init__(self, provider):
		super().__init__()
		self._provider = provider
		self.thing_i_made = 0

	def use_provider(self):
		self.thing_i_made = self._provider()
		# Interestingly, if you add a print statement here, it prints 3 times, not twice.


class TestProvidersInThreads(unittest.TestCase):

	def test_provider_called_in_thread(self):
		worker_1 = WorkerThatCanMoveToThreadAndCallProvider(provider_of_annoying_object)
		thread_1 = threading.Thread(target=worker_1.use_provider)

		worker_2 = WorkerThatCanMoveToThreadAndCallProvider(provider_of_annoying_object)
		thread_2 = threading.Thread(target=worker_2.use_provider)

		thread_1.start()
		thread_2.start()
		thread_1.join()
		thread_2.join()
		self.assertIsInstance(worker_1.thing_i_made, ThingThatTakesLongTimeToInitAndNeedsToBeSingleton)
		self.assertIsInstance(worker_2.thing_i_made, ThingThatTakesLongTimeToInitAndNeedsToBeSingleton)
		self.assertIs(worker_1.thing_i_made, worker_2.thing_i_made)

For versions > 4.6.0, this test fails with:

self.assertIsInstance(worker_2.thing_i_made, ThingThatTakesLongTimeToInitAndNeedsToBeSingleton)
AssertionError: None is not an instance of <class 'tests.providers.test_why_image_interface_dead.ThingThatTakesLongTimeToInitAndNeedsToBeSingleton'>
@rmk135
Copy link
Member

rmk135 commented Mar 23, 2021

Hi @garlandhu,

Thanks for reporting the issue. I'm sorry to hear that error was introduced in 4.6. I'll work on a fix ASAP.

@rmk135 rmk135 self-assigned this Mar 23, 2021
@rmk135 rmk135 added the bug label Mar 23, 2021
@rmk135
Copy link
Member

rmk135 commented Mar 24, 2021

Fixed in version 4.31.1. @garlandhu thanks again for reporting the issue.

@rmk135 rmk135 closed this as completed Mar 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants