state_machine.py python
54 lines 1.7 KB
Raw
sha256:91e875d4a97bb1e35f37992f803988d5713931f1782d870c371c50054574af22 Add fixture provenance retention deletion Human minor ⚠ breaking 43 days ago
1 """Deterministic T2 training job state machine."""
2
3 from __future__ import annotations
4
5 from types import MappingProxyType
6
7 from scooling_lab.contracts import TrainingJobStatus
8 from scooling_lab.errors import ApiError, ErrorCode
9
10
11 TRANSITION_TABLE: MappingProxyType[TrainingJobStatus, frozenset[TrainingJobStatus]] = (
12 MappingProxyType(
13 {
14 TrainingJobStatus.QUEUED: frozenset(
15 {
16 TrainingJobStatus.RUNNING,
17 TrainingJobStatus.FAILED,
18 TrainingJobStatus.CANCELLED,
19 }
20 ),
21 TrainingJobStatus.RUNNING: frozenset(
22 {
23 TrainingJobStatus.SUCCEEDED,
24 TrainingJobStatus.FAILED,
25 TrainingJobStatus.CANCELLED,
26 }
27 ),
28 TrainingJobStatus.SUCCEEDED: frozenset({TrainingJobStatus.DELETED}),
29 TrainingJobStatus.DELETED: frozenset(),
30 TrainingJobStatus.FAILED: frozenset(),
31 TrainingJobStatus.CANCELLED: frozenset(),
32 }
33 )
34 )
35
36
37 def transition(
38 current: TrainingJobStatus, target: TrainingJobStatus
39 ) -> TrainingJobStatus:
40 """Return the next state or raise for invalid non-idempotent transitions."""
41
42 if current == target:
43 return current
44 if target in TRANSITION_TABLE[current]:
45 return target
46 raise ApiError(ErrorCode.INVALID_TRANSITION, 409)
47
48
49 def cancel(current: TrainingJobStatus) -> TrainingJobStatus:
50 """Cancel a queued or running job; terminal replay is idempotent."""
51
52 if current == TrainingJobStatus.CANCELLED:
53 return current
54 return transition(current, TrainingJobStatus.CANCELLED)
File History 1 commit
sha256:91e875d4a97bb1e35f37992f803988d5713931f1782d870c371c50054574af22 Add fixture provenance retention deletion Human minor 43 days ago