13
13
14
14
from apify_client import ApifyClientAsync
15
15
from apify_shared .consts import ActorEnvVars , ActorExitCodes , ApifyEnvVars
16
+ from crawlee .errors import ServiceConflictError
16
17
from crawlee .events import (
17
18
Event ,
18
19
EventAbortingData ,
@@ -118,9 +119,12 @@ def __init__(
118
119
self ._exit_process = self ._get_default_exit_process () if exit_process is None else exit_process
119
120
self ._is_exiting = False
120
121
121
- if configuration :
122
- service_locator .set_configuration (configuration )
123
- self ._configuration = service_locator .get_configuration ()
122
+ # Actor state when this method is being executed is unpredictable.
123
+ # Actor can be initialized by lazy object proxy or by user directly, or by both.
124
+ # Until `init` method is run, this state of uncertainty remains. This is the reason why any setting done here in
125
+ # `__init__` method should not be considered final.
126
+
127
+ self ._configuration = configuration
124
128
self ._configure_logging = configure_logging
125
129
self ._apify_client = self .new_client ()
126
130
@@ -131,17 +135,17 @@ def __init__(
131
135
# Set the event manager based on whether the Actor is running on the platform or locally.
132
136
self ._event_manager = (
133
137
ApifyEventManager (
134
- configuration = self ._configuration ,
135
- persist_state_interval = self ._configuration .persist_state_interval ,
138
+ configuration = self .config ,
139
+ persist_state_interval = self .config .persist_state_interval ,
136
140
)
137
141
if self .is_at_home ()
138
142
else LocalEventManager (
139
- system_info_interval = self ._configuration .system_info_interval ,
140
- persist_state_interval = self ._configuration .persist_state_interval ,
143
+ system_info_interval = self .config .system_info_interval ,
144
+ persist_state_interval = self .config .persist_state_interval ,
141
145
)
142
146
)
143
147
144
- self ._charging_manager = ChargingManagerImplementation (self ._configuration , self ._apify_client )
148
+ self ._charging_manager = ChargingManagerImplementation (self .config , self ._apify_client )
145
149
146
150
self ._is_initialized = False
147
151
@@ -204,12 +208,18 @@ def apify_client(self) -> ApifyClientAsync:
204
208
@property
205
209
def configuration (self ) -> Configuration :
206
210
"""The Configuration instance the Actor instance uses."""
207
- return self ._configuration
211
+ return self .config
208
212
209
213
@property
210
214
def config (self ) -> Configuration :
211
215
"""The Configuration instance the Actor instance uses."""
212
- return self ._configuration
216
+ if self ._configuration :
217
+ return self ._configuration
218
+ self .log .debug (
219
+ 'Implicit configuration used.'
220
+ "It's recommended to explicitly set the configuration to avoid unexpected behavior."
221
+ )
222
+ return Configuration ()
213
223
214
224
@property
215
225
def event_manager (self ) -> EventManager :
@@ -251,6 +261,21 @@ async def init(self) -> None:
251
261
This method should be called immediately before performing any additional Actor actions, and it should be
252
262
called only once.
253
263
"""
264
+ if self ._configuration :
265
+ # Set explicitly the configuration in the service locator
266
+ service_locator .set_configuration (self .configuration )
267
+ else :
268
+ try :
269
+ # Set implicit default Apify configuration, unless configuration was already set.
270
+ service_locator .set_configuration (self .configuration )
271
+ except ServiceConflictError :
272
+ self .log .info (
273
+ 'Configuration in service locator was set explicitly before Actor. '
274
+ 'Using the existing configuration.'
275
+ )
276
+ # Use the configuration from the service locator
277
+ self ._configuration = service_locator .get_configuration ()
278
+
254
279
if self ._is_initialized :
255
280
raise RuntimeError ('The Actor was already initialized!' )
256
281
@@ -268,7 +293,6 @@ async def init(self) -> None:
268
293
service_locator .set_storage_client (self ._cloud_storage_client )
269
294
270
295
service_locator .set_event_manager (self .event_manager )
271
- service_locator .set_configuration (self .configuration )
272
296
273
297
# The logging configuration has to be called after all service_locator set methods.
274
298
if self ._configure_logging :
@@ -386,8 +410,8 @@ def new_client(
386
410
(increases exponentially from this value).
387
411
timeout: The socket timeout of the HTTP requests sent to the Apify API.
388
412
"""
389
- token = token or self ._configuration .token
390
- api_url = api_url or self ._configuration .api_base_url
413
+ token = token or self .config .token
414
+ api_url = api_url or self .config .api_base_url
391
415
return ApifyClientAsync (
392
416
token = token ,
393
417
api_url = api_url ,
@@ -547,9 +571,9 @@ async def get_input(self) -> Any:
547
571
"""Get the Actor input value from the default key-value store associated with the current Actor run."""
548
572
self ._raise_if_not_initialized ()
549
573
550
- input_value = await self .get_value (self ._configuration .input_key )
551
- input_secrets_private_key = self ._configuration .input_secrets_private_key_file
552
- input_secrets_key_passphrase = self ._configuration .input_secrets_private_key_passphrase
574
+ input_value = await self .get_value (self .config .input_key )
575
+ input_secrets_private_key = self .config .input_secrets_private_key_file
576
+ input_secrets_key_passphrase = self .config .input_secrets_private_key_passphrase
553
577
if input_secrets_private_key and input_secrets_key_passphrase :
554
578
private_key = load_private_key (
555
579
input_secrets_private_key ,
@@ -686,7 +710,7 @@ def off(self, event_name: Event, listener: Callable | None = None) -> None:
686
710
687
711
def is_at_home (self ) -> bool :
688
712
"""Return `True` when the Actor is running on the Apify platform, and `False` otherwise (e.g. local run)."""
689
- return self ._configuration .is_at_home
713
+ return self .config .is_at_home
690
714
691
715
def get_env (self ) -> dict :
692
716
"""Return a dictionary with information parsed from all the `APIFY_XXX` environment variables.
@@ -712,7 +736,7 @@ def get_env(self) -> dict:
712
736
aliases = [field_name ]
713
737
714
738
for alias in aliases :
715
- config [alias ] = getattr (self ._configuration , field_name )
739
+ config [alias ] = getattr (self .config , field_name )
716
740
717
741
env_vars = {env_var .value .lower (): env_var .name .lower () for env_var in [* ActorEnvVars , * ApifyEnvVars ]}
718
742
return {option_name : config [env_var ] for env_var , option_name in env_vars .items () if env_var in config }
@@ -1000,13 +1024,13 @@ async def metamorph(
1000
1024
return
1001
1025
1002
1026
if not custom_after_sleep :
1003
- custom_after_sleep = self ._configuration .metamorph_after_sleep
1027
+ custom_after_sleep = self .config .metamorph_after_sleep
1004
1028
1005
1029
# If is_at_home() is True, config.actor_run_id is always set
1006
- if not self ._configuration .actor_run_id :
1030
+ if not self .config .actor_run_id :
1007
1031
raise RuntimeError ('actor_run_id cannot be None when running on the Apify platform.' )
1008
1032
1009
- await self ._apify_client .run (self ._configuration .actor_run_id ).metamorph (
1033
+ await self ._apify_client .run (self .config .actor_run_id ).metamorph (
1010
1034
target_actor_id = target_actor_id ,
1011
1035
run_input = run_input ,
1012
1036
target_actor_build = target_actor_build ,
@@ -1043,7 +1067,7 @@ async def reboot(
1043
1067
_ActorType ._is_rebooting = True
1044
1068
1045
1069
if not custom_after_sleep :
1046
- custom_after_sleep = self ._configuration .metamorph_after_sleep
1070
+ custom_after_sleep = self .config .metamorph_after_sleep
1047
1071
1048
1072
# Call all the listeners for the PERSIST_STATE and MIGRATING events, and wait for them to finish.
1049
1073
# PERSIST_STATE listeners are called to allow the Actor to persist its state before the reboot.
@@ -1063,10 +1087,10 @@ async def reboot(
1063
1087
* [listener (EventMigratingData ()) for listener in migrating_listeners ],
1064
1088
)
1065
1089
1066
- if not self ._configuration .actor_run_id :
1090
+ if not self .config .actor_run_id :
1067
1091
raise RuntimeError ('actor_run_id cannot be None when running on the Apify platform.' )
1068
1092
1069
- await self ._apify_client .run (self ._configuration .actor_run_id ).reboot ()
1093
+ await self ._apify_client .run (self .config .actor_run_id ).reboot ()
1070
1094
1071
1095
if custom_after_sleep :
1072
1096
await asyncio .sleep (custom_after_sleep .total_seconds ())
@@ -1105,11 +1129,11 @@ async def add_webhook(
1105
1129
return
1106
1130
1107
1131
# If is_at_home() is True, config.actor_run_id is always set
1108
- if not self ._configuration .actor_run_id :
1132
+ if not self .config .actor_run_id :
1109
1133
raise RuntimeError ('actor_run_id cannot be None when running on the Apify platform.' )
1110
1134
1111
1135
await self ._apify_client .webhooks ().create (
1112
- actor_run_id = self ._configuration .actor_run_id ,
1136
+ actor_run_id = self .config .actor_run_id ,
1113
1137
event_types = webhook .event_types ,
1114
1138
request_url = webhook .request_url ,
1115
1139
payload_template = webhook .payload_template ,
@@ -1141,10 +1165,10 @@ async def set_status_message(
1141
1165
return None
1142
1166
1143
1167
# If is_at_home() is True, config.actor_run_id is always set
1144
- if not self ._configuration .actor_run_id :
1168
+ if not self .config .actor_run_id :
1145
1169
raise RuntimeError ('actor_run_id cannot be None when running on the Apify platform.' )
1146
1170
1147
- api_result = await self ._apify_client .run (self ._configuration .actor_run_id ).update (
1171
+ api_result = await self ._apify_client .run (self .config .actor_run_id ).update (
1148
1172
status_message = status_message , is_status_message_terminal = is_terminal
1149
1173
)
1150
1174
@@ -1199,7 +1223,7 @@ async def create_proxy_configuration(
1199
1223
country_code = country_code ,
1200
1224
proxy_urls = proxy_urls ,
1201
1225
new_url_function = new_url_function ,
1202
- _actor_config = self ._configuration ,
1226
+ _actor_config = self .config ,
1203
1227
_apify_client = self ._apify_client ,
1204
1228
)
1205
1229
0 commit comments