@@ -190,6 +190,77 @@ def timeout_and_retry_task(x: int) -> int:
190190 assert combined_payload .options .retry .max_retries == 2
191191
192192
193+ def test_task_registration_with_dict_retry_config (
194+ task_registry , task_decorator , mocker
195+ ):
196+ """
197+ Test that registration handles dict retry configs passed to Options().
198+ A caller may construct Options(retry={...}) with a plain dict instead
199+ of a Retry instance. Options.__post_init__ should coerce it.
200+ """
201+ mock_uds_client_class = mocker .patch ("render_sdk.workflows.runner.UDSClient" )
202+ mock_client_instance = mocker .Mock ()
203+ mock_uds_client_class .return_value = mock_client_instance
204+ mock_client_instance .register_tasks = mocker .AsyncMock (
205+ return_value = {"status" : "success" },
206+ )
207+ mock_client_instance .disconnect = mocker .AsyncMock ()
208+
209+ # Options receives a plain dict instead of a Retry instance
210+ dict_retry = {
211+ "max_retries" : 5 ,
212+ "wait_duration_ms" : 2000 ,
213+ "backoff_scaling" : 2.0 ,
214+ }
215+ options = Options (retry = dict_retry )
216+
217+ @task_decorator (options = options )
218+ def my_task (x : int ) -> int :
219+ return x
220+
221+ mock_get_registry = mocker .patch ("render_sdk.workflows.runner.get_task_registry" )
222+ mock_get_registry .return_value = task_registry
223+
224+ register ("/tmp/test.sock" ) # noqa:S108
225+
226+ sent_tasks = mock_client_instance .register_tasks .call_args [0 ][0 ]
227+ task_payload = sent_tasks .tasks [0 ]
228+
229+ assert task_payload .options .retry .max_retries == 5
230+ assert task_payload .options .retry .wait_duration_ms == 2000
231+ assert task_payload .options .retry .factor == 2.0
232+
233+
234+ def test_task_registration_without_retry_config (task_registry , task_decorator , mocker ):
235+ """
236+ Test that tasks with no retry config register successfully. This is the
237+ common case that was unaffected by the dict retry bug.
238+ """
239+ from render_sdk .workflows .callback_api .types import UNSET
240+
241+ mock_uds_client_class = mocker .patch ("render_sdk.workflows.runner.UDSClient" )
242+ mock_client_instance = mocker .Mock ()
243+ mock_uds_client_class .return_value = mock_client_instance
244+ mock_client_instance .register_tasks = mocker .AsyncMock (
245+ return_value = {"status" : "success" },
246+ )
247+ mock_client_instance .disconnect = mocker .AsyncMock ()
248+
249+ @task_decorator
250+ def my_task (x : int ) -> int :
251+ return x
252+
253+ mock_get_registry = mocker .patch ("render_sdk.workflows.runner.get_task_registry" )
254+ mock_get_registry .return_value = task_registry
255+
256+ register ("/tmp/test.sock" ) # noqa:S108
257+
258+ sent_tasks = mock_client_instance .register_tasks .call_args [0 ][0 ]
259+ task_payload = sent_tasks .tasks [0 ]
260+
261+ assert task_payload .options .retry is UNSET
262+
263+
193264@pytest .mark .asyncio
194265async def test_callback_payloads_with_mocked_client (
195266 task_registry ,
0 commit comments