Skip to content

Commit 85129fb

Browse files
Kowserclaude
andcommitted
Declare the schedule lifecycle as abstractmethods on SchedulerClient
pause/resume/delete/run_now/preview_next/reconcile join the ABC as bare @AbstractMethod declarations, same style as the endpoint methods — the lifecycle is part of the SchedulerClient contract again, with the implementation on OrkesSchedulerClient. get_scheduler_client() returns to the -> SchedulerClient annotation. Guard test now pins abstract-on-ABC / concrete-on-Orkes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 35b9ffd commit 85129fb

11 files changed

Lines changed: 60 additions & 31 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Canonical metrics mode: opt-in harmonized metric surface via `WORKER_CANONICAL_METRICS=true` -- [details](METRICS.md#detailed-technical-notes--unreleased)
1313
- `MetricsSettings` gains `clean_directory` and `clean_dead_pids` for opt-in stale `.db` file cleanup (both default to `False`)
14-
- `OrkesSchedulerClient` now carries the schedule lifecycle operations itself: `pause(reason=)`, `resume`, `delete`, `run_now`, `preview_next`, `reconcile` (declarative tri-state sync) — with typed errors (`ScheduleNotFound`, `InvalidCronExpression`, ...). `pause_schedule` gains an optional `reason=` (stored by OSS Conductor servers; ignored by Orkes servers)
14+
- `SchedulerClient` now carries the schedule lifecycle operations itself: `pause(reason=)`, `resume`, `delete`, `run_now`, `preview_next`, `reconcile` (declarative tri-state sync) — with typed errors (`ScheduleNotFound`, `InvalidCronExpression`, ...). `pause_schedule` gains an optional `reason=` (stored by OSS Conductor servers; ignored by Orkes servers)
1515

1616
### Changed
1717

@@ -23,7 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323

2424
### Removed
2525

26-
- **Breaking:** `AgentScheduleClient` (alias `ScheduleClient`) and `OrkesClients.get_agent_schedule_client()` are removed with no compatibility shim — `OrkesSchedulerClient` (via `OrkesClients.get_scheduler_client()`) is the one schedule client and carries the full lifecycle itself. Replace `AgentScheduleClient(scheduler_client, workflow_client)` constructions with `get_scheduler_client()`; `runtime.schedules_client()` and `AgentClient.schedules` now return that client directly (same methods, same shared instance)
26+
- **Breaking:** `AgentScheduleClient` (alias `ScheduleClient`) and `OrkesClients.get_agent_schedule_client()` are removed with no compatibility shim — `SchedulerClient` (via `OrkesClients.get_scheduler_client()`) is the one schedule client and carries the full lifecycle itself. Replace `AgentScheduleClient(scheduler_client, workflow_client)` constructions with `get_scheduler_client()`; `runtime.schedules_client()` and `AgentClient.schedules` now return that client directly (same methods, same shared instance)
2727

2828
### Fixed
2929

docs/SCHEDULE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Operations for controlling schedule execution state.
4343
4444
## Schedule Lifecycle Helpers
4545

46-
Beyond the endpoint methods above, `OrkesSchedulerClient` carries higher-level lifecycle
46+
Beyond the endpoint methods above, `SchedulerClient` carries higher-level lifecycle
4747
operations (shared with the agents layer). They raise typed errors
4848
(`ScheduleNotFound`, `InvalidCronExpression`, `ScheduleNameConflict` from
4949
`conductor.client.ai.schedule_errors`) instead of raw `ApiException`.

docs/agents/advanced.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ with AgentRuntime() as runtime:
127127
Key methods: `run`/`run_async`, `start`/`start_async`, `deploy`/`deploy_async`,
128128
`schedule(agent, schedules)`, `get_status`, `respond`, `stop`, `signal`,
129129
`stream_sse`, and `.schedules` (the schedule lifecycle — `pause`/`resume`/`delete`/
130-
`run_now`/`preview_next`/`reconcile`, now carried by `OrkesSchedulerClient` itself). Both
130+
`run_now`/`preview_next`/`reconcile`, now carried by `SchedulerClient` itself). Both
131131
sync and async forms exist. Most users call `runtime.run/start/deploy` instead,
132132
which add local-worker management on top of this client.
133133

docs/agents/api-reference.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Context manager (sync and async: `with` / `async with`).
4646
| `signal` | `(execution_id, message) -> None` | Inject persistent context |
4747
| `shutdown` | `() -> None` | Stop all workers |
4848
| `client` (property) | `-> AgentClient` | Control-plane client |
49-
| `schedules_client` | `() -> OrkesSchedulerClient` | Shared schedule client |
49+
| `schedules_client` | `() -> SchedulerClient` | Shared schedule client |
5050

5151
Async variants exist for status/respond/approve/reject/send/stop/shutdown
5252
(`*_async`). Module-level wrappers using a singleton runtime: `run`, `run_async`,
@@ -190,7 +190,7 @@ start_at=None, end_at=None, description=None)` — `cron` is a 5- or 6-field exp
190190
`ScheduleInfo` (read model) fields include `name`, `short_name`, `agent`, `cron`,
191191
`timezone`, `input`, `paused`, `catchup`, `next_run`, `create_time`, `update_time`, ...
192192

193-
The schedule lifecycle lives on `OrkesSchedulerClient` itself (via
193+
The schedule lifecycle lives on `SchedulerClient` itself (via
194194
`runtime.schedules_client()`, `runtime.client.schedules`, or
195195
`OrkesClients.get_scheduler_client()`):
196196

@@ -284,7 +284,7 @@ The control-plane client (formerly `AgentHttpClient`, alias kept). Reach it via
284284
| `stop` | `(execution_id) -> None` | |
285285
| `signal` | `(execution_id, message) -> None` | |
286286
| `stream_sse` | `(execution_id) -> AsyncIterator[dict]` | |
287-
| `schedules` (property) | `-> OrkesSchedulerClient` | |
287+
| `schedules` (property) | `-> SchedulerClient` | |
288288
| `close` | `() -> None` (async) | |
289289

290290
Lower-level endpoint methods (`start_agent`, `deploy_agent`, `compile_agent`) are also

e2e/test_suite21_scheduling.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
ScheduleNameConflict,
3434
)
3535
from conductor.client.ai.schedule import _from_workflow_schedule
36-
from conductor.client.orkes.orkes_scheduler_client import OrkesSchedulerClient
36+
from conductor.client.scheduler_client import SchedulerClient
3737

3838
pytestmark = [pytest.mark.e2e]
3939

@@ -125,12 +125,12 @@ def agent_name(conductor_clients) -> Iterator[str]:
125125

126126

127127
@pytest.fixture()
128-
def schedule_client(conductor_clients) -> OrkesSchedulerClient:
128+
def schedule_client(conductor_clients) -> SchedulerClient:
129129
return conductor_clients.get_scheduler_client()
130130

131131

132132
@pytest.fixture(autouse=True)
133-
def clean_schedules(schedule_client: OrkesSchedulerClient, agent_name: str):
133+
def clean_schedules(schedule_client: SchedulerClient, agent_name: str):
134134
"""Purge any leftover schedules for this agent before each test."""
135135
schedule_client.reconcile(agent_name, [])
136136
yield

src/conductor/ai/agents/runtime/http_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,13 @@ def _workflow_client(self) -> Any:
203203

204204
@property
205205
def schedules(self) -> Any:
206-
"""Cron schedule lifecycle client (:class:`OrkesSchedulerClient`).
206+
"""Cron schedule lifecycle client (:class:`SchedulerClient`).
207207
208208
Exposes ``get_schedule/save_schedule/get_all_schedules`` plus the
209209
lifecycle methods ``pause/resume/delete/run_now/preview_next/
210210
reconcile``. When bound to a runtime, this is the *same*
211-
:class:`OrkesSchedulerClient` instance the runtime uses — there is
212-
one shared schedule surface, not two.
211+
:class:`SchedulerClient` instance the runtime uses — there is one
212+
shared schedule surface, not two.
213213
"""
214214
if self._runtime is not None:
215215
return self._runtime.schedules_client()

src/conductor/ai/agents/runtime/runtime.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2231,7 +2231,7 @@ def client(self) -> Any:
22312231
return self._http
22322232

22332233
def schedules_client(self) -> Any:
2234-
"""Return the shared :class:`OrkesSchedulerClient` for this runtime.
2234+
"""Return the shared :class:`SchedulerClient` for this runtime.
22352235
22362236
Delegates to :attr:`client` so the runtime and the control-plane
22372237
client expose the *same* schedule surface (one instance, not two).

src/conductor/client/ai/schedule.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
prefixed wire name plus server-computed fields like ``next_run``.
1010
1111
The private helpers below (payload mapping, wire-name prefixing, typed error
12-
translation) are shared by ``OrkesSchedulerClient``'s schedule-lifecycle
12+
translation) are shared by ``SchedulerClient``'s schedule-lifecycle
1313
methods and the module-level ``schedules.*`` API. The native
1414
``get_schedule``/``save_schedule``/``get_all_schedules`` endpoint methods are
1515
the source of truth for reads/writes/lists; the ``ScheduleInfo`` view exists

src/conductor/client/orkes_clients.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,7 @@ def get_authorization_client(self) -> AuthorizationClient:
4343
def get_metadata_client(self) -> MetadataClient:
4444
return OrkesMetadataClient(self.configuration)
4545

46-
def get_scheduler_client(self) -> OrkesSchedulerClient:
47-
# Annotated with the concrete class: the schedule-lifecycle methods
48-
# (pause/resume/delete/run_now/preview_next/reconcile) live on
49-
# OrkesSchedulerClient, not on the SchedulerClient endpoint ABC.
46+
def get_scheduler_client(self) -> SchedulerClient:
5047
return OrkesSchedulerClient(self.configuration)
5148

5249
def get_secret_client(self) -> SecretClient:

src/conductor/client/scheduler_client.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,32 @@ def get_scheduler_tags(self, name: str) -> List[MetadataTag]:
7575
@abstractmethod
7676
def delete_scheduler_tags(self, tags: List[MetadataTag], name: str) -> List[MetadataTag]:
7777
pass
78+
79+
@abstractmethod
80+
def pause(self, wire_name: str, reason: Optional[str] = None) -> None:
81+
pass
82+
83+
@abstractmethod
84+
def resume(self, wire_name: str) -> None:
85+
pass
86+
87+
@abstractmethod
88+
def delete(self, wire_name: str) -> None:
89+
pass
90+
91+
@abstractmethod
92+
def preview_next(self,
93+
cron: str,
94+
n: int = 5,
95+
start_at: Optional[int] = None,
96+
end_at: Optional[int] = None,
97+
) -> List[int]:
98+
pass
99+
100+
@abstractmethod
101+
def run_now(self, info: "ScheduleInfo") -> str: # noqa: F821
102+
pass
103+
104+
@abstractmethod
105+
def reconcile(self, agent_name: str, desired: Optional[List["Schedule"]]) -> None: # noqa: F821
106+
pass

0 commit comments

Comments
 (0)