state_machine.py python
59 lines 1.8 KB
Raw
sha256:ca1d0e687bff8686b37126eb8e4fb6d38b40e189352a4920d66ae89c7274e340 Add T4 job cancellation retry and validation Human minor ⚠ breaking 41 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 in {
53 TrainingJobStatus.SUCCEEDED,
54 TrainingJobStatus.FAILED,
55 TrainingJobStatus.CANCELLED,
56 TrainingJobStatus.DELETED,
57 }:
58 return current
59 return transition(current, TrainingJobStatus.CANCELLED)
File History 1 commit
sha256:ca1d0e687bff8686b37126eb8e4fb6d38b40e189352a4920d66ae89c7274e340 Add T4 job cancellation retry and validation Human minor 41 days ago