@@ -461,6 +461,24 @@ def step() -> Iterable[SR]:
461461 return step
462462
463463
464+ class _StepTimedOut (Exception ):
465+ """A timed `step_proof` exhausted its `step_timeout` budget. Carries the budget for logging."""
466+
467+ budget : int
468+
469+ def __init__ (self , budget : int ) -> None :
470+ super ().__init__ (budget )
471+ self .budget = budget
472+
473+
474+ class _StepShrunk (_StepTimedOut ):
475+ """The timed-out step was shrunk; `advance_proof` should re-fetch steps and retry it smaller."""
476+
477+
478+ class _StepExhausted (_StepTimedOut ):
479+ """The timed-out step could not be shrunk further; `advance_proof` should stop."""
480+
481+
464482class Prover (ContextManager ['Prover' ], Generic [P , PS , SR ]):
465483 """Abstract class which advances `Proof`s with `init_proof()` and `step_proof()`.
466484
@@ -528,6 +546,27 @@ def interrupt(self) -> None:
528546 """
529547 ...
530548
549+ def _execute_step (self , step : PS , executor : Executor | None ) -> Iterable [SR ]:
550+ """Run one `step_proof`, honoring `step_timeout` when an `executor` is given.
551+
552+ With no executor, runs the step synchronously with no time limit. With one, runs the step
553+ under the `step_timeout` budget; on timeout it interrupts the step, asks the prover to
554+ `shrink_step`, and raises `_StepShrunk` (a smaller step is ready to retry) or `_StepExhausted`
555+ (already minimal, give up). Returns the step results when the step completes within budget.
556+ """
557+ if executor is None :
558+ return self .step_proof (step )
559+
560+ budget = self .step_timeout
561+ assert budget is not None
562+ future = executor .submit (self .step_proof , step )
563+ try :
564+ return future .result (timeout = budget )
565+ except FuturesTimeoutError :
566+ self .interrupt ()
567+ wait ([future ]) # let the interrupted step unwind before we reuse the prover
568+ raise (_StepShrunk if self .shrink_step () else _StepExhausted )(budget ) from None
569+
531570 def advance_proof (
532571 self ,
533572 proof : P ,
@@ -553,8 +592,9 @@ def advance_proof(
553592 _LOGGER .info (f'Initializing proof: { proof .id } ' )
554593 self .init_proof (proof )
555594
556- timed = self .step_timeout is not None
557- executor = ThreadPoolExecutor (max_workers = 1 ) if timed else None
595+ # When `step_timeout` is set, run each step on a worker thread so it can be timed and
596+ # interrupted; otherwise steps run synchronously and `executor` stays `None`.
597+ executor = ThreadPoolExecutor (max_workers = 1 ) if self .step_timeout is not None else None
558598 try :
559599 while True :
560600 steps = list (proof .get_steps ())
@@ -569,31 +609,19 @@ def advance_proof(
569609 return
570610 if max_iterations is not None and max_iterations <= iterations :
571611 return
572- if timed :
573- assert executor is not None
574- budget = self .step_timeout
575- assert budget is not None
576- future = executor .submit (self .step_proof , step )
577- try :
578- results = future .result (timeout = budget )
579- except FuturesTimeoutError :
580- # The step exhausted its budget: interrupt it, ask the prover to do less
581- # work per step, and re-fetch steps so the same node is retried smaller.
582- self .interrupt ()
583- wait ([future ])
584- if not self .shrink_step ():
585- _LOGGER .warning (
586- f'Proof { proof .id } : step exhausted { budget } s budget and cannot be '
587- f'shrunk further; stopping.'
588- )
589- return
590- _LOGGER .warning (
591- f'Proof { proof .id } : step exhausted { budget } s budget; shrinking and retrying.'
592- )
593- shrank_step = True
594- break
595- else :
596- results = self .step_proof (step )
612+ try :
613+ results = self ._execute_step (step , executor )
614+ except _StepShrunk as timeout :
615+ _LOGGER .warning (
616+ f'Proof { proof .id } : step exceeded { timeout .budget } s budget; shrinking and retrying.'
617+ )
618+ shrank_step = True # re-fetch steps and retry the same node, now smaller
619+ break
620+ except _StepExhausted as timeout :
621+ _LOGGER .warning (
622+ f'Proof { proof .id } : step exceeded { timeout .budget } s budget and cannot shrink further; stopping.'
623+ )
624+ return
597625 iterations += 1
598626 for result in results :
599627 proof .commit (result )
0 commit comments