etlantic-sqlmodel 0.45.0__tar.gz → 0.47.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/PKG-INFO +6 -6
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/README.md +4 -4
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/pyproject.toml +2 -2
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/__init__.py +1 -1
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/__init__.py +10 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/models.py +16 -0
- etlantic_sqlmodel-0.47.0/src/etlantic_sqlmodel/control_plane/schedule_stores.py +252 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/migrations/__init__.py +1 -0
- etlantic_sqlmodel-0.47.0/src/etlantic_sqlmodel/migrations/versions/004_schedules_0_47.py +29 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/.gitignore +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/cp4_stores.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/durable_stores.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/registry_backup.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/registry_search.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/registry_stores.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/session.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/stores.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/migrations/versions/001_registry_cp2.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/migrations/versions/002_durable_cp3.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/migrations/versions/003_cp4_governance.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/migrations/versions/__init__.py +0 -0
- {etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: etlantic-sqlmodel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.47.0
|
|
4
4
|
Summary: ContractModel ↔ SQLModel bridge for ETLantic.
|
|
5
5
|
Project-URL: Homepage, https://github.com/eddiethedean/etlantic
|
|
6
6
|
Project-URL: Documentation, https://github.com/eddiethedean/etlantic/tree/main/docs
|
|
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
19
|
Classifier: Typing :: Typed
|
|
20
20
|
Requires-Python: >=3.11
|
|
21
|
-
Requires-Dist: etlantic<0.
|
|
21
|
+
Requires-Dist: etlantic<0.48,>=0.47.0
|
|
22
22
|
Requires-Dist: sqlmodel<1,>=0.0.22
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
|
|
@@ -28,13 +28,13 @@ Optional bridge between ETLantic `Data` contracts and
|
|
|
28
28
|
[SQLModel](https://sqlmodel.tiangolo.com/) table models, plus optional CP1
|
|
29
29
|
control-plane reference stores. Install when you need `contract_to_sqlmodel`
|
|
30
30
|
helpers or SQLModel-backed definition/submission stores for local CP1 demos.
|
|
31
|
-
Package version is **0.
|
|
31
|
+
Package version is **0.47.0** — pin with core.
|
|
32
32
|
|
|
33
33
|
## Install
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
pip install 'etlantic-sqlmodel==0.
|
|
37
|
-
# pip install 'etlantic==0.
|
|
36
|
+
pip install 'etlantic-sqlmodel==0.47.0'
|
|
37
|
+
# pip install 'etlantic==0.47.0'
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
## Schema bridge
|
|
@@ -96,6 +96,6 @@ for isolation queries. Use separate engines/schemas per tenant for
|
|
|
96
96
|
|
|
97
97
|
## Links
|
|
98
98
|
|
|
99
|
-
[Optional packages](https://etlantic.readthedocs.io/en/v0.
|
|
99
|
+
[Optional packages](https://etlantic.readthedocs.io/en/v0.47.0/10_REFERENCE/OPTIONAL_PACKAGES/) ·
|
|
100
100
|
[Source](https://github.com/eddiethedean/etlantic/tree/main/packages/etlantic-sqlmodel) ·
|
|
101
101
|
[Issues](https://github.com/eddiethedean/etlantic/issues)
|
|
@@ -4,13 +4,13 @@ Optional bridge between ETLantic `Data` contracts and
|
|
|
4
4
|
[SQLModel](https://sqlmodel.tiangolo.com/) table models, plus optional CP1
|
|
5
5
|
control-plane reference stores. Install when you need `contract_to_sqlmodel`
|
|
6
6
|
helpers or SQLModel-backed definition/submission stores for local CP1 demos.
|
|
7
|
-
Package version is **0.
|
|
7
|
+
Package version is **0.47.0** — pin with core.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
pip install 'etlantic-sqlmodel==0.
|
|
13
|
-
# pip install 'etlantic==0.
|
|
12
|
+
pip install 'etlantic-sqlmodel==0.47.0'
|
|
13
|
+
# pip install 'etlantic==0.47.0'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## Schema bridge
|
|
@@ -72,6 +72,6 @@ for isolation queries. Use separate engines/schemas per tenant for
|
|
|
72
72
|
|
|
73
73
|
## Links
|
|
74
74
|
|
|
75
|
-
[Optional packages](https://etlantic.readthedocs.io/en/v0.
|
|
75
|
+
[Optional packages](https://etlantic.readthedocs.io/en/v0.47.0/10_REFERENCE/OPTIONAL_PACKAGES/) ·
|
|
76
76
|
[Source](https://github.com/eddiethedean/etlantic/tree/main/packages/etlantic-sqlmodel) ·
|
|
77
77
|
[Issues](https://github.com/eddiethedean/etlantic/issues)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "etlantic-sqlmodel"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.47.0"
|
|
4
4
|
description = "ContractModel ↔ SQLModel bridge for ETLantic."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -17,7 +17,7 @@ classifiers = [
|
|
|
17
17
|
"Typing :: Typed",
|
|
18
18
|
]
|
|
19
19
|
dependencies = [
|
|
20
|
-
"etlantic>=0.
|
|
20
|
+
"etlantic>=0.47.0,<0.48",
|
|
21
21
|
"sqlmodel>=0.0.22,<1",
|
|
22
22
|
]
|
|
23
23
|
|
|
@@ -37,6 +37,7 @@ from etlantic_sqlmodel.control_plane.models import (
|
|
|
37
37
|
LogicalIdentityRow,
|
|
38
38
|
PromotionRow,
|
|
39
39
|
RevisionRow,
|
|
40
|
+
ScheduleSnapshotRow,
|
|
40
41
|
SecurityDomainRow,
|
|
41
42
|
SubmissionRow,
|
|
42
43
|
TenantRow,
|
|
@@ -60,6 +61,11 @@ from etlantic_sqlmodel.control_plane.registry_stores import (
|
|
|
60
61
|
SqlModelWorkspaceDirectory,
|
|
61
62
|
create_registry_tables,
|
|
62
63
|
)
|
|
64
|
+
from etlantic_sqlmodel.control_plane.schedule_stores import (
|
|
65
|
+
SCHEDULE_TABLES,
|
|
66
|
+
SQLModelScheduleStore,
|
|
67
|
+
create_schedule_tables,
|
|
68
|
+
)
|
|
63
69
|
from etlantic_sqlmodel.control_plane.session import (
|
|
64
70
|
create_sqlite_engine,
|
|
65
71
|
make_session_factory,
|
|
@@ -78,6 +84,7 @@ __all__ = [
|
|
|
78
84
|
"CP4_TABLES",
|
|
79
85
|
"DURABLE_TABLES",
|
|
80
86
|
"REGISTRY_TABLES",
|
|
87
|
+
"SCHEDULE_TABLES",
|
|
81
88
|
"AliasRow",
|
|
82
89
|
"BackupTranscript",
|
|
83
90
|
"Cp4GovernanceSnapshotRow",
|
|
@@ -99,7 +106,9 @@ __all__ = [
|
|
|
99
106
|
"SQLModelObjectiveStore",
|
|
100
107
|
"SQLModelPolicyProvider",
|
|
101
108
|
"SQLModelQuotaProvider",
|
|
109
|
+
"SQLModelScheduleStore",
|
|
102
110
|
"SQLModelSubmissionStore",
|
|
111
|
+
"ScheduleSnapshotRow",
|
|
103
112
|
"SecurityDomainRow",
|
|
104
113
|
"SqlModelEventStore",
|
|
105
114
|
"SqlModelRegistryProvider",
|
|
@@ -115,6 +124,7 @@ __all__ = [
|
|
|
115
124
|
"create_cp4_tables",
|
|
116
125
|
"create_durable_tables",
|
|
117
126
|
"create_registry_tables",
|
|
127
|
+
"create_schedule_tables",
|
|
118
128
|
"create_sqlite_engine",
|
|
119
129
|
"dump_registry_sqlite",
|
|
120
130
|
"load_registry_sqlite",
|
{etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/models.py
RENAMED
|
@@ -353,6 +353,21 @@ class Cp4GovernanceSnapshotRow(SQLModel, table=True):
|
|
|
353
353
|
updated_at: str | None = None
|
|
354
354
|
|
|
355
355
|
|
|
356
|
+
class ScheduleSnapshotRow(SQLModel, table=True):
|
|
357
|
+
"""Transactional 0.47 schedule-store snapshot (reference provider)."""
|
|
358
|
+
|
|
359
|
+
__tablename__ = "cp_schedule_snapshot"
|
|
360
|
+
__table_args__ = (UniqueConstraint("store_id", name="uq_cp_schedule_snapshot"),)
|
|
361
|
+
|
|
362
|
+
id: int | None = Field(default=None, primary_key=True)
|
|
363
|
+
store_id: str = Field(
|
|
364
|
+
sa_column=Column(String(), index=True, nullable=False), default="default"
|
|
365
|
+
)
|
|
366
|
+
payload_json: str = "{}"
|
|
367
|
+
payload_version: int = Field(default=0, sa_column=Column(Integer(), nullable=False))
|
|
368
|
+
updated_at: str | None = None
|
|
369
|
+
|
|
370
|
+
|
|
356
371
|
__all__ = [
|
|
357
372
|
"AliasRow",
|
|
358
373
|
"Cp4GovernanceSnapshotRow",
|
|
@@ -365,6 +380,7 @@ __all__ = [
|
|
|
365
380
|
"LogicalIdentityRow",
|
|
366
381
|
"PromotionRow",
|
|
367
382
|
"RevisionRow",
|
|
383
|
+
"ScheduleSnapshotRow",
|
|
368
384
|
"SecurityDomainRow",
|
|
369
385
|
"SubmissionRow",
|
|
370
386
|
"TenantRow",
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""SQLModel-backed ScheduleStore (0.47).
|
|
2
|
+
|
|
3
|
+
Reference provider: each mutating call loads the schedule snapshot inside a
|
|
4
|
+
database transaction, applies MemoryScheduleStore semantics, and writes the
|
|
5
|
+
snapshot back. When the paired DurableWorkStore is the SQLModel provider on
|
|
6
|
+
the same engine, firing claim and durable accept share one commit.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
from collections.abc import Callable, Sequence
|
|
13
|
+
from datetime import UTC, datetime
|
|
14
|
+
from typing import Any, TypeVar
|
|
15
|
+
|
|
16
|
+
from sqlalchemy.engine import Engine
|
|
17
|
+
|
|
18
|
+
from etlantic.control_plane.durable_protocols import DurableWorkStore
|
|
19
|
+
from etlantic.control_plane.errors import ControlPlaneError
|
|
20
|
+
from etlantic.control_plane.models import ControlPlaneContext
|
|
21
|
+
from etlantic.control_plane.schedule_memory import MemoryScheduleStore
|
|
22
|
+
from etlantic.control_plane.schedule_models import (
|
|
23
|
+
FiringRecord,
|
|
24
|
+
ScheduleRecord,
|
|
25
|
+
ScheduleSpec,
|
|
26
|
+
)
|
|
27
|
+
from etlantic.control_plane.schedule_protocols import SchedulerLeaderLease
|
|
28
|
+
from etlantic_sqlmodel.control_plane.durable_stores import SQLModelDurableWorkStore
|
|
29
|
+
from etlantic_sqlmodel.control_plane.models import ScheduleSnapshotRow
|
|
30
|
+
from etlantic_sqlmodel.control_plane.session import session_scope
|
|
31
|
+
from sqlmodel import Session, SQLModel, select
|
|
32
|
+
|
|
33
|
+
T = TypeVar("T")
|
|
34
|
+
|
|
35
|
+
SCHEDULE_TABLES = (ScheduleSnapshotRow,)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def create_schedule_tables(engine: Engine) -> None:
|
|
39
|
+
"""Create schedule snapshot tables (tests/demos only)."""
|
|
40
|
+
SQLModel.metadata.create_all(
|
|
41
|
+
engine,
|
|
42
|
+
tables=[cls.__table__ for cls in SCHEDULE_TABLES], # type: ignore[list-item]
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _utcnow_iso() -> str:
|
|
47
|
+
return datetime.now(UTC).isoformat().replace("+00:00", "Z")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class SQLModelScheduleStore:
|
|
51
|
+
"""Transactional ScheduleStore backed by a SQL snapshot row."""
|
|
52
|
+
|
|
53
|
+
def __init__(self, engine: Engine, *, store_id: str = "default") -> None:
|
|
54
|
+
self.engine = engine
|
|
55
|
+
self.store_id = store_id
|
|
56
|
+
|
|
57
|
+
def _txn(self, fn: Callable[[MemoryScheduleStore], T]) -> T:
|
|
58
|
+
with session_scope(self.engine) as session:
|
|
59
|
+
mem, version = self._read(session, for_update=True)
|
|
60
|
+
result = fn(mem)
|
|
61
|
+
self._write(session, mem, expected_version=version)
|
|
62
|
+
return result
|
|
63
|
+
|
|
64
|
+
def _read_only(self, fn: Callable[[MemoryScheduleStore], T]) -> T:
|
|
65
|
+
with session_scope(self.engine) as session:
|
|
66
|
+
mem, _version = self._read(session, for_update=False)
|
|
67
|
+
return fn(mem)
|
|
68
|
+
|
|
69
|
+
def _read(
|
|
70
|
+
self, session: Session, *, for_update: bool
|
|
71
|
+
) -> tuple[MemoryScheduleStore, int]:
|
|
72
|
+
stmt = select(ScheduleSnapshotRow).where(
|
|
73
|
+
ScheduleSnapshotRow.store_id == self.store_id
|
|
74
|
+
)
|
|
75
|
+
if for_update:
|
|
76
|
+
stmt = stmt.with_for_update()
|
|
77
|
+
row = session.exec(stmt).first()
|
|
78
|
+
store = MemoryScheduleStore()
|
|
79
|
+
if row is None:
|
|
80
|
+
return store, 0
|
|
81
|
+
store.load(json.loads(row.payload_json or "{}"))
|
|
82
|
+
return store, int(row.payload_version or 0)
|
|
83
|
+
|
|
84
|
+
def _write(
|
|
85
|
+
self,
|
|
86
|
+
session: Session,
|
|
87
|
+
store: MemoryScheduleStore,
|
|
88
|
+
*,
|
|
89
|
+
expected_version: int,
|
|
90
|
+
) -> None:
|
|
91
|
+
payload = json.dumps(store.dump(), sort_keys=True)
|
|
92
|
+
row = session.exec(
|
|
93
|
+
select(ScheduleSnapshotRow)
|
|
94
|
+
.where(ScheduleSnapshotRow.store_id == self.store_id)
|
|
95
|
+
.with_for_update()
|
|
96
|
+
).first()
|
|
97
|
+
if row is None:
|
|
98
|
+
if expected_version != 0:
|
|
99
|
+
raise ControlPlaneError.conflict(
|
|
100
|
+
"Schedule snapshot version conflict (missing row)"
|
|
101
|
+
)
|
|
102
|
+
session.add(
|
|
103
|
+
ScheduleSnapshotRow(
|
|
104
|
+
store_id=self.store_id,
|
|
105
|
+
payload_json=payload,
|
|
106
|
+
payload_version=1,
|
|
107
|
+
updated_at=_utcnow_iso(),
|
|
108
|
+
)
|
|
109
|
+
)
|
|
110
|
+
return
|
|
111
|
+
current = int(row.payload_version or 0)
|
|
112
|
+
if current != expected_version:
|
|
113
|
+
raise ControlPlaneError.conflict(
|
|
114
|
+
"Schedule snapshot version conflict (stale write)"
|
|
115
|
+
)
|
|
116
|
+
row.payload_json = payload
|
|
117
|
+
row.payload_version = current + 1
|
|
118
|
+
row.updated_at = _utcnow_iso()
|
|
119
|
+
session.add(row)
|
|
120
|
+
|
|
121
|
+
def create(
|
|
122
|
+
self,
|
|
123
|
+
ctx: ControlPlaneContext,
|
|
124
|
+
*,
|
|
125
|
+
definition_id: str,
|
|
126
|
+
profile_name: str,
|
|
127
|
+
spec: ScheduleSpec,
|
|
128
|
+
schedule_id: str | None = None,
|
|
129
|
+
policy_fingerprint: str = "",
|
|
130
|
+
parameter_refs: dict[str, str] | None = None,
|
|
131
|
+
secret_refs: dict[str, str] | None = None,
|
|
132
|
+
next_fire_at: str | None = None,
|
|
133
|
+
) -> ScheduleRecord:
|
|
134
|
+
return self._txn(
|
|
135
|
+
lambda m: m.create(
|
|
136
|
+
ctx,
|
|
137
|
+
definition_id=definition_id,
|
|
138
|
+
profile_name=profile_name,
|
|
139
|
+
spec=spec,
|
|
140
|
+
schedule_id=schedule_id,
|
|
141
|
+
policy_fingerprint=policy_fingerprint,
|
|
142
|
+
parameter_refs=parameter_refs,
|
|
143
|
+
secret_refs=secret_refs,
|
|
144
|
+
next_fire_at=next_fire_at,
|
|
145
|
+
)
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
def get(self, ctx: ControlPlaneContext, schedule_id: str) -> ScheduleRecord:
|
|
149
|
+
return self._read_only(lambda m: m.get(ctx, schedule_id))
|
|
150
|
+
|
|
151
|
+
def list_schedules(self, ctx: ControlPlaneContext) -> Sequence[ScheduleRecord]:
|
|
152
|
+
return self._read_only(lambda m: m.list_schedules(ctx))
|
|
153
|
+
|
|
154
|
+
def pause(self, ctx: ControlPlaneContext, schedule_id: str) -> ScheduleRecord:
|
|
155
|
+
return self._txn(lambda m: m.pause(ctx, schedule_id))
|
|
156
|
+
|
|
157
|
+
def resume(self, ctx: ControlPlaneContext, schedule_id: str) -> ScheduleRecord:
|
|
158
|
+
return self._txn(lambda m: m.resume(ctx, schedule_id))
|
|
159
|
+
|
|
160
|
+
def delete(self, ctx: ControlPlaneContext, schedule_id: str) -> ScheduleRecord:
|
|
161
|
+
return self._txn(lambda m: m.delete(ctx, schedule_id))
|
|
162
|
+
|
|
163
|
+
def acquire_leader_lease(
|
|
164
|
+
self, ctx: ControlPlaneContext, *, owner_id: str, ttl_seconds: int
|
|
165
|
+
) -> SchedulerLeaderLease:
|
|
166
|
+
return self._txn(
|
|
167
|
+
lambda m: m.acquire_leader_lease(
|
|
168
|
+
ctx, owner_id=owner_id, ttl_seconds=ttl_seconds
|
|
169
|
+
)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def heartbeat_leader(
|
|
173
|
+
self,
|
|
174
|
+
ctx: ControlPlaneContext,
|
|
175
|
+
*,
|
|
176
|
+
owner_id: str,
|
|
177
|
+
fencing_token: int,
|
|
178
|
+
ttl_seconds: int,
|
|
179
|
+
) -> SchedulerLeaderLease:
|
|
180
|
+
return self._txn(
|
|
181
|
+
lambda m: m.heartbeat_leader(
|
|
182
|
+
ctx,
|
|
183
|
+
owner_id=owner_id,
|
|
184
|
+
fencing_token=fencing_token,
|
|
185
|
+
ttl_seconds=ttl_seconds,
|
|
186
|
+
)
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def release_leader(
|
|
190
|
+
self, ctx: ControlPlaneContext, *, owner_id: str, fencing_token: int
|
|
191
|
+
) -> None:
|
|
192
|
+
self._txn(
|
|
193
|
+
lambda m: m.release_leader(
|
|
194
|
+
ctx, owner_id=owner_id, fencing_token=fencing_token
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
def due_schedules(
|
|
199
|
+
self, ctx: ControlPlaneContext, *, now: str
|
|
200
|
+
) -> Sequence[ScheduleRecord]:
|
|
201
|
+
return self._read_only(lambda m: m.due_schedules(ctx, now=now))
|
|
202
|
+
|
|
203
|
+
def list_firings(
|
|
204
|
+
self, ctx: ControlPlaneContext, schedule_id: str
|
|
205
|
+
) -> Sequence[FiringRecord]:
|
|
206
|
+
return self._read_only(lambda m: m.list_firings(ctx, schedule_id))
|
|
207
|
+
|
|
208
|
+
def claim_firing(
|
|
209
|
+
self,
|
|
210
|
+
ctx: ControlPlaneContext,
|
|
211
|
+
*,
|
|
212
|
+
schedule_id: str,
|
|
213
|
+
revision_id: str,
|
|
214
|
+
nominal_fire_time: str,
|
|
215
|
+
owner_id: str,
|
|
216
|
+
fencing_token: int,
|
|
217
|
+
plan_fingerprint: str,
|
|
218
|
+
durable: DurableWorkStore | None = None,
|
|
219
|
+
next_fire_at: str | None = None,
|
|
220
|
+
require_leader_lease: bool = True,
|
|
221
|
+
skip_status: str | None = None,
|
|
222
|
+
) -> tuple[FiringRecord, bool]:
|
|
223
|
+
kwargs: dict[str, Any] = {
|
|
224
|
+
"schedule_id": schedule_id,
|
|
225
|
+
"revision_id": revision_id,
|
|
226
|
+
"nominal_fire_time": nominal_fire_time,
|
|
227
|
+
"owner_id": owner_id,
|
|
228
|
+
"fencing_token": fencing_token,
|
|
229
|
+
"plan_fingerprint": plan_fingerprint,
|
|
230
|
+
"next_fire_at": next_fire_at,
|
|
231
|
+
"require_leader_lease": require_leader_lease,
|
|
232
|
+
"skip_status": skip_status,
|
|
233
|
+
}
|
|
234
|
+
if (
|
|
235
|
+
isinstance(durable, SQLModelDurableWorkStore)
|
|
236
|
+
and durable.engine is self.engine
|
|
237
|
+
):
|
|
238
|
+
with session_scope(self.engine) as session:
|
|
239
|
+
sched, sv = self._read(session, for_update=True)
|
|
240
|
+
dur_mem, dv = durable._read(session, for_update=True)
|
|
241
|
+
result = sched.claim_firing(ctx, durable=dur_mem, **kwargs)
|
|
242
|
+
self._write(session, sched, expected_version=sv)
|
|
243
|
+
durable._write(session, dur_mem, expected_version=dv)
|
|
244
|
+
return result
|
|
245
|
+
return self._txn(lambda m: m.claim_firing(ctx, durable=durable, **kwargs))
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
__all__ = [
|
|
249
|
+
"SCHEDULE_TABLES",
|
|
250
|
+
"SQLModelScheduleStore",
|
|
251
|
+
"create_schedule_tables",
|
|
252
|
+
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""004 — schedule snapshot storage for 0.47 ScheduleStore."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from sqlalchemy.engine import Engine
|
|
6
|
+
|
|
7
|
+
from etlantic_sqlmodel.control_plane.models import ScheduleSnapshotRow
|
|
8
|
+
from sqlmodel import SQLModel
|
|
9
|
+
|
|
10
|
+
TABLES = (ScheduleSnapshotRow,)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def upgrade(engine: Engine) -> None:
|
|
14
|
+
"""Create schedule snapshot tables."""
|
|
15
|
+
SQLModel.metadata.create_all(
|
|
16
|
+
engine,
|
|
17
|
+
tables=[cls.__table__ for cls in TABLES], # type: ignore[list-item]
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def downgrade(engine: Engine) -> None:
|
|
22
|
+
"""Drop schedule snapshot tables."""
|
|
23
|
+
SQLModel.metadata.drop_all(
|
|
24
|
+
engine,
|
|
25
|
+
tables=[cls.__table__ for cls in reversed(TABLES)], # type: ignore[list-item]
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
__all__ = ["downgrade", "upgrade"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/session.py
RENAMED
|
File without changes
|
{etlantic_sqlmodel-0.45.0 → etlantic_sqlmodel-0.47.0}/src/etlantic_sqlmodel/control_plane/stores.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|