Skip to content

Commit dc50e42

Browse files
committed
Add scheduling parity and API alignment for v0.4.0
- Add SchedulerHealthResponse dataclass (13-field GET /health/scheduler) - Add get_scheduler_health() method to ScheduleClient - Add lazy-loaded Client.schedules property for ScheduleClient access - Export all schedule types from package __init__ - Fix ScheduleClient._request() to parse JSON response - Add 17 test cases covering all 11 ScheduleClient methods - Bump version to 0.4.0
1 parent b391cef commit dc50e42

5 files changed

Lines changed: 504 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [0.4.0] - 2026-02-07
9+
10+
### Added
11+
12+
#### Scheduling Parity & API Alignment
13+
- **SchedulerHealthResponse** — New dataclass for the 13-field `GET /health/scheduler` endpoint
14+
- **`get_scheduler_health()`** — New method on `ScheduleClient` to query scheduler health
15+
- **`Client.schedules` property** — Lazy-loaded `ScheduleClient` accessible directly from the main `Client` instance
16+
- **Schedule type exports** — All schedule dataclasses now exported from `symbiont` package (`CreateScheduleRequest`, `ScheduleSummary`, `ScheduleDetail`, `SchedulerHealthResponse`, etc.)
17+
18+
#### Test Coverage
19+
- **ScheduleClient tests** — 18 test cases covering all 11 methods (list, create, get, update, delete, pause, resume, trigger, history, next-runs, scheduler-health) plus edge cases
20+
21+
---
22+
23+
## [0.3.1] - 2025-01-16
24+
25+
### Added
26+
- ScheduleClient for cron schedule management API
27+
- Test compatibility fixes for enhanced Client class
28+
29+
## [0.3.0] and earlier
30+
31+
See previous releases for historical changes.

symbiont/__init__.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,25 @@
8282
WorkflowExecutionRequest,
8383
WorkflowExecutionResponse,
8484
)
85+
from .schedules import (
86+
CreateScheduleRequest,
87+
CreateScheduleResponse,
88+
DeleteScheduleResponse,
89+
NextRunsResponse,
90+
ScheduleActionResponse,
91+
ScheduleClient,
92+
ScheduleDetail,
93+
ScheduleHistoryResponse,
94+
SchedulerHealthResponse,
95+
ScheduleRunEntry,
96+
ScheduleSummary,
97+
UpdateScheduleRequest,
98+
)
8599

86100
# Load environment variables from .env file
87101
load_dotenv()
88102

89-
__version__ = "0.3.1"
103+
__version__ = "0.4.0"
90104

91105
__all__ = [
92106
# Client
@@ -128,6 +142,15 @@
128142
'HttpInputConfig', 'HttpInputServerInfo', 'HttpInputCreateRequest', 'HttpInputUpdateRequest',
129143
'WebhookTriggerRequest', 'WebhookTriggerResponse',
130144

145+
# Schedule Models
146+
'ScheduleClient',
147+
'CreateScheduleRequest', 'CreateScheduleResponse',
148+
'UpdateScheduleRequest',
149+
'ScheduleSummary', 'ScheduleDetail', 'ScheduleRunEntry',
150+
'ScheduleHistoryResponse', 'NextRunsResponse',
151+
'ScheduleActionResponse', 'DeleteScheduleResponse',
152+
'SchedulerHealthResponse',
153+
131154
# Exceptions
132155
'SymbiontError',
133156
'APIError',

symbiont/client.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
WebhookTriggerResponse,
8585
WorkflowExecutionRequest,
8686
)
87+
from .schedules import ScheduleClient
8788

8889

8990
class Client:
@@ -147,6 +148,16 @@ def __init__(self,
147148
self.api_key = self.config.api_key
148149
self.base_url = self.config.base_url
149150

151+
# Lazy-loaded sub-clients
152+
self._schedules: Optional[ScheduleClient] = None
153+
154+
@property
155+
def schedules(self) -> ScheduleClient:
156+
"""Lazy-loaded schedule management client."""
157+
if self._schedules is None:
158+
self._schedules = ScheduleClient(self)
159+
return self._schedules
160+
150161
def _request(self, method: str, endpoint: str, **kwargs):
151162
"""Make an HTTP request to the API.
152163

symbiont/schedules.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
from dataclasses import dataclass, field
88
from typing import Any, Dict, List, Optional
99

10-
from .exceptions import APIError, NotFoundError
11-
1210

1311
@dataclass
1412
class CreateScheduleRequest:
@@ -119,6 +117,25 @@ class DeleteScheduleResponse:
119117
deleted: bool
120118

121119

120+
@dataclass
121+
class SchedulerHealthResponse:
122+
"""Scheduler health response from GET /health/scheduler."""
123+
124+
is_running: bool
125+
store_accessible: bool
126+
jobs_total: int
127+
jobs_active: int
128+
jobs_paused: int
129+
jobs_dead_letter: int
130+
global_active_runs: int
131+
max_concurrent: int
132+
runs_total: int
133+
runs_succeeded: int
134+
runs_failed: int
135+
average_execution_time_ms: float
136+
longest_run_ms: float
137+
138+
122139
class ScheduleClient:
123140
"""Client for managing cron schedules via the Symbiont Runtime API.
124141
@@ -140,7 +157,8 @@ def _request(
140157
params: Optional[Dict[str, Any]] = None,
141158
) -> Any:
142159
"""Make an authenticated request through the parent client."""
143-
return self._client._request(method, path, json=json, params=params)
160+
response = self._client._request(method, path, json=json, params=params)
161+
return response.json()
144162

145163
def list_schedules(self) -> List[ScheduleSummary]:
146164
"""List all scheduled jobs. ``GET /schedules``"""
@@ -219,3 +237,8 @@ def get_schedule_next_runs(
219237
"GET", f"/schedules/{job_id}/next-runs", params={"count": count}
220238
)
221239
return NextRunsResponse(**data)
240+
241+
def get_scheduler_health(self) -> SchedulerHealthResponse:
242+
"""Get scheduler health status. ``GET /health/scheduler``"""
243+
data = self._request("GET", "/health/scheduler")
244+
return SchedulerHealthResponse(**data)

0 commit comments

Comments
 (0)