apify-sdk-python
apify-sdk-python copied to clipboard
Make Actor consistently reusable without raising `ServiceConflictError`
Description
The following patterns should all be equivalent and valid:
1) Actor + Actor - works ✔️
async with Actor:
Actor.exit_process = False
print('Hello world')
async with Actor:
print('Hello world')
2) Actor() + Actor - works ✔️
async with Actor(exit_process=False) as actor:
print('Hello world')
async with Actor:
print('Hello world')
3) Actor + Actor() - ServiceConflictError ❗
async with Actor:
Actor.exit_process = False
print('Hello world')
async with Actor() as actor:
print('Hello world')
4) Actor() + Actor() - ServiceConflictError ❗
async with Actor(exit_process=False) as actor:
print('Hello world')
async with Actor() as actor:
print('Hello world')
We have real use cases for this (e.g., in the example-code-runner-py Actor).
However, some of these code paths currently raise a ServiceConflictError:
crawlee.errors.ServiceConflictError: Service EventManager is already in use. Existing value: <crawlee.events._local_event_manager.LocalEventManager object at 0x7f84b5460ad0>, attempted new value: <crawlee.events._local_event_manager.LocalEventManager object at 0x7f84b7483d90>.
This means the Actor context manager is not fully isolated between runs.
Possible solution
Apply the same service-locator cleanup/isolation logic that we already use in conftest.py:
# Reset the services in the service locator.
service_locator._configuration = None
service_locator._event_manager = None
service_locator._storage_client = None
service_locator.storage_instance_manager.clear_cache()
This should allow all async with Actor usages to behave consistently and avoid cross-run conflicts.