Skip to content

Commit a33e6fb

Browse files
authored
Add update_progress() timeout tests (#1666)
* Add update_progress() timeout tests * Extend timeout for CI
1 parent 529d2c7 commit a33e6fb

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import time
2+
import unittest
3+
4+
from tensorlake import (
5+
Graph,
6+
GraphRequestContext,
7+
tensorlake_function,
8+
)
9+
from tensorlake.functions_sdk.graph_serialization import graph_code_dir_path
10+
from testing import remote_or_local_graph, test_graph_name
11+
12+
13+
@tensorlake_function(inject_ctx=True, timeout=5)
14+
def function_with_progress_updates(ctx: GraphRequestContext, x: int) -> str:
15+
"""Function that calls update_progress multiple times during execution.
16+
17+
This function takes longer than the timeout (5 seconds) but should succeed
18+
because update_progress() calls reset the timeout.
19+
"""
20+
# Sleep for 2 seconds, then report progress
21+
time.sleep(2)
22+
ctx.update_progress(current=1, total=4)
23+
24+
# Sleep for another 2 seconds, then report progress again
25+
time.sleep(2)
26+
ctx.update_progress(current=2, total=4)
27+
28+
# Sleep for another 2 seconds, then report progress again
29+
time.sleep(2)
30+
ctx.update_progress(current=3, total=4)
31+
32+
# Final sleep and completion
33+
time.sleep(2)
34+
ctx.update_progress(current=4, total=4)
35+
36+
return "completed_with_progress_updates"
37+
38+
39+
@tensorlake_function(inject_ctx=True, timeout=5)
40+
def function_without_progress_updates(ctx: GraphRequestContext, x: int) -> str:
41+
"""Function that sleeps longer than timeout without reporting progress.
42+
43+
This function should timeout because it doesn't call update_progress().
44+
"""
45+
46+
# This exceeds the 5-second timeout and the 30-second check making
47+
# sure the timeout happens at all.
48+
time.sleep(60)
49+
50+
return "should_not_reach_here"
51+
52+
53+
class TestTimeoutResetOnProgress(unittest.TestCase):
54+
def test_function_succeeds_with_progress_updates(self):
55+
"""Test that functions with progress updates don't timeout even if they exceed the original timeout."""
56+
graph = Graph(
57+
name=test_graph_name(self),
58+
description="test timeout reset on progress",
59+
start_node=function_with_progress_updates,
60+
)
61+
graph = remote_or_local_graph(graph, remote=True)
62+
63+
start_time = time.monotonic()
64+
invocation_id = graph.run(block_until_done=True, x=1)
65+
duration = time.monotonic() - start_time
66+
67+
# Should take about 8 seconds (4 * 2 seconds) but succeed
68+
self.assertGreater(duration, 7, "Function should take at least 7 seconds")
69+
self.assertLess(duration, 15, "Function should complete within reasonable time")
70+
71+
# Check that the function succeeded
72+
outputs = graph.output(invocation_id, function_with_progress_updates.name)
73+
self.assertEqual(len(outputs), 1)
74+
self.assertEqual(outputs[0], "completed_with_progress_updates")
75+
76+
def test_function_fails_without_progress_updates(self):
77+
"""Test that functions without progress updates timeout as expected."""
78+
graph = Graph(
79+
name=test_graph_name(self),
80+
description="test timeout without progress",
81+
start_node=function_without_progress_updates,
82+
)
83+
graph = remote_or_local_graph(graph, remote=True)
84+
85+
start_time = time.monotonic()
86+
invocation_id = graph.run(block_until_done=True, x=1)
87+
duration = time.monotonic() - start_time
88+
89+
# Should timeout after about 5 seconds, but CI can be slow,
90+
# so we check against 30.
91+
self.assertLess(duration, 30, "Function should timeout quickly")
92+
93+
# Check that the function failed (no outputs)
94+
outputs = graph.output(invocation_id, function_without_progress_updates.name)
95+
self.assertEqual(len(outputs), 0, "Function should have failed due to timeout")
96+
97+
98+
if __name__ == "__main__":
99+
unittest.main()

0 commit comments

Comments
 (0)