edgecron-python 1.0.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.
- edgecron_python-1.0.0/.github/workflows/publish-python-pypi.yml +34 -0
- edgecron_python-1.0.0/.gitignore +9 -0
- edgecron_python-1.0.0/LICENSE +21 -0
- edgecron_python-1.0.0/PKG-INFO +96 -0
- edgecron_python-1.0.0/README.md +68 -0
- edgecron_python-1.0.0/README.zh-CN.md +68 -0
- edgecron_python-1.0.0/pyproject.toml +47 -0
- edgecron_python-1.0.0/samples/__init__.py +0 -0
- edgecron_python-1.0.0/samples/cron_schedule.py +43 -0
- edgecron_python-1.0.0/samples/schedule_task.py +22 -0
- edgecron_python-1.0.0/samples/webhook_recovery.py +52 -0
- edgecron_python-1.0.0/src/edgecron/__init__.py +69 -0
- edgecron_python-1.0.0/src/edgecron/client.py +57 -0
- edgecron_python-1.0.0/src/edgecron/deliveries.py +37 -0
- edgecron_python-1.0.0/src/edgecron/endpoints.py +43 -0
- edgecron_python-1.0.0/src/edgecron/error.py +18 -0
- edgecron_python-1.0.0/src/edgecron/events.py +41 -0
- edgecron_python-1.0.0/src/edgecron/retries.py +60 -0
- edgecron_python-1.0.0/src/edgecron/schedules.py +61 -0
- edgecron_python-1.0.0/src/edgecron/signer.py +31 -0
- edgecron_python-1.0.0/src/edgecron/subscription.py +28 -0
- edgecron_python-1.0.0/src/edgecron/tasks.py +44 -0
- edgecron_python-1.0.0/src/edgecron/transport.py +146 -0
- edgecron_python-1.0.0/src/edgecron/types.py +303 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Publish Python Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
publish:
|
|
15
|
+
if: github.repository == 'edgecron/edgecron-python'
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout
|
|
20
|
+
uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Setup Python
|
|
23
|
+
uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.12"
|
|
26
|
+
|
|
27
|
+
- name: Install build tooling
|
|
28
|
+
run: python -m pip install --upgrade build
|
|
29
|
+
|
|
30
|
+
- name: Build distributions
|
|
31
|
+
run: python -m build
|
|
32
|
+
|
|
33
|
+
- name: Publish to PyPI
|
|
34
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 EdgeCron Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: edgecron-python
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for the EdgeCron webhook scheduling and callback delivery platform.
|
|
5
|
+
Project-URL: Homepage, https://github.com/edgecron/edgecron-python
|
|
6
|
+
Project-URL: Repository, https://github.com/edgecron/edgecron-python
|
|
7
|
+
Project-URL: Documentation, https://www.edgecron.com
|
|
8
|
+
Author: EdgeCron Team
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: callback,delivery,edgecron,scheduling,webhook
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Requires-Dist: requests<3,>=2.31.0
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
Requires-Dist: pytest<9,>=8; extra == 'test'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# EdgeCron Python SDK
|
|
30
|
+
|
|
31
|
+
Official Python SDK for the EdgeCron webhook scheduling and callback delivery platform.
|
|
32
|
+
|
|
33
|
+
Schedule delayed HTTP requests, deliver webhooks reliably, and automatically retry failed calls — with full execution history so nothing gets lost.
|
|
34
|
+
|
|
35
|
+
中文文档:[README.zh-CN.md](README.zh-CN.md)
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install edgecron-python
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from edgecron import EdgeCron, APIError
|
|
47
|
+
from edgecron.types import CreateScheduleRequest
|
|
48
|
+
|
|
49
|
+
client = EdgeCron("ak_xxx", "sk_xxx")
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
schedule = client.schedules.create(
|
|
53
|
+
CreateScheduleRequest(
|
|
54
|
+
name="my-schedule",
|
|
55
|
+
cron_expr="*/5 * * * *",
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
print(schedule.id)
|
|
59
|
+
except APIError as exc:
|
|
60
|
+
print(exc.code, exc.message, exc.request_id)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Modules
|
|
64
|
+
|
|
65
|
+
| Client method | Description |
|
|
66
|
+
|----------------------------|----------------------------------|
|
|
67
|
+
| `client.schedules.*` | Cron schedule CRUD, pause, resume |
|
|
68
|
+
| `client.tasks.*` | Task execution instances, cancel |
|
|
69
|
+
| `client.events.*` | Event publishing and management |
|
|
70
|
+
| `client.endpoints.*` | Webhook endpoint configuration |
|
|
71
|
+
| `client.deliveries.*` | Delivery attempt records and retry |
|
|
72
|
+
| `client.retries.*` | Retry policies and jobs |
|
|
73
|
+
| `client.subscription.*` | Quota, usage, and resource limits |
|
|
74
|
+
|
|
75
|
+
## Configuration
|
|
76
|
+
|
|
77
|
+
- `base_url` — override API base URL
|
|
78
|
+
- `timeout` — HTTP client timeout in seconds
|
|
79
|
+
- `session` — custom `requests.Session`
|
|
80
|
+
|
|
81
|
+
## Error Handling
|
|
82
|
+
|
|
83
|
+
Service-side business errors raise `APIError`.
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from edgecron import APIError
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
client.schedules.get(123)
|
|
90
|
+
except APIError as exc:
|
|
91
|
+
print(exc.code, exc.message, exc.request_id)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Security Notice
|
|
95
|
+
|
|
96
|
+
This is a server-side SDK. Never expose `secret` in browsers, mobile apps, or other untrusted clients.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# EdgeCron Python SDK
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the EdgeCron webhook scheduling and callback delivery platform.
|
|
4
|
+
|
|
5
|
+
Schedule delayed HTTP requests, deliver webhooks reliably, and automatically retry failed calls — with full execution history so nothing gets lost.
|
|
6
|
+
|
|
7
|
+
中文文档:[README.zh-CN.md](README.zh-CN.md)
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install edgecron-python
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from edgecron import EdgeCron, APIError
|
|
19
|
+
from edgecron.types import CreateScheduleRequest
|
|
20
|
+
|
|
21
|
+
client = EdgeCron("ak_xxx", "sk_xxx")
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
schedule = client.schedules.create(
|
|
25
|
+
CreateScheduleRequest(
|
|
26
|
+
name="my-schedule",
|
|
27
|
+
cron_expr="*/5 * * * *",
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
print(schedule.id)
|
|
31
|
+
except APIError as exc:
|
|
32
|
+
print(exc.code, exc.message, exc.request_id)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Modules
|
|
36
|
+
|
|
37
|
+
| Client method | Description |
|
|
38
|
+
|----------------------------|----------------------------------|
|
|
39
|
+
| `client.schedules.*` | Cron schedule CRUD, pause, resume |
|
|
40
|
+
| `client.tasks.*` | Task execution instances, cancel |
|
|
41
|
+
| `client.events.*` | Event publishing and management |
|
|
42
|
+
| `client.endpoints.*` | Webhook endpoint configuration |
|
|
43
|
+
| `client.deliveries.*` | Delivery attempt records and retry |
|
|
44
|
+
| `client.retries.*` | Retry policies and jobs |
|
|
45
|
+
| `client.subscription.*` | Quota, usage, and resource limits |
|
|
46
|
+
|
|
47
|
+
## Configuration
|
|
48
|
+
|
|
49
|
+
- `base_url` — override API base URL
|
|
50
|
+
- `timeout` — HTTP client timeout in seconds
|
|
51
|
+
- `session` — custom `requests.Session`
|
|
52
|
+
|
|
53
|
+
## Error Handling
|
|
54
|
+
|
|
55
|
+
Service-side business errors raise `APIError`.
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from edgecron import APIError
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
client.schedules.get(123)
|
|
62
|
+
except APIError as exc:
|
|
63
|
+
print(exc.code, exc.message, exc.request_id)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Security Notice
|
|
67
|
+
|
|
68
|
+
This is a server-side SDK. Never expose `secret` in browsers, mobile apps, or other untrusted clients.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# EdgeCron Python SDK
|
|
2
|
+
|
|
3
|
+
EdgeCron Python SDK 是 EdgeCron Webhook 调度与回调投递平台的官方 Python 客户端。
|
|
4
|
+
|
|
5
|
+
调度延迟 HTTP 请求,可靠投递 Webhook,自动重试失败调用 — 完整执行历史,确保不遗漏。
|
|
6
|
+
|
|
7
|
+
English README: [README.md](README.md)
|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install edgecron-python
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 快速开始
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from edgecron import EdgeCron, APIError
|
|
19
|
+
from edgecron.types import CreateScheduleRequest
|
|
20
|
+
|
|
21
|
+
client = EdgeCron("ak_xxx", "sk_xxx")
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
schedule = client.schedules.create(
|
|
25
|
+
CreateScheduleRequest(
|
|
26
|
+
name="my-schedule",
|
|
27
|
+
cron_expr="*/5 * * * *",
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
print(schedule.id)
|
|
31
|
+
except APIError as exc:
|
|
32
|
+
print(exc.code, exc.message, exc.request_id)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 模块说明
|
|
36
|
+
|
|
37
|
+
| 客户端方法 | 说明 |
|
|
38
|
+
|----------------------------|-----------------------------|
|
|
39
|
+
| `client.schedules.*` | Cron 调度器 CRUD、暂停、恢复 |
|
|
40
|
+
| `client.tasks.*` | 任务执行实例、取消 |
|
|
41
|
+
| `client.events.*` | 事件发布与管理 |
|
|
42
|
+
| `client.endpoints.*` | Webhook 端点配置 |
|
|
43
|
+
| `client.deliveries.*` | 投递记录与手动重试 |
|
|
44
|
+
| `client.retries.*` | 重试策略与任务 |
|
|
45
|
+
| `client.subscription.*` | 配额、用量与资源限制 |
|
|
46
|
+
|
|
47
|
+
## 配置项
|
|
48
|
+
|
|
49
|
+
- `base_url`:自定义 API 地址
|
|
50
|
+
- `timeout`:超时时间,单位秒
|
|
51
|
+
- `session`:自定义 `requests.Session`
|
|
52
|
+
|
|
53
|
+
## 错误处理
|
|
54
|
+
|
|
55
|
+
服务端业务错误会抛出 `APIError`。
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from edgecron import APIError
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
client.schedules.get(123)
|
|
62
|
+
except APIError as exc:
|
|
63
|
+
print(exc.code, exc.message, exc.request_id)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 安全说明
|
|
67
|
+
|
|
68
|
+
这是服务端 SDK,不要在浏览器、小程序、移动端或其他不可信客户端暴露 `secret`。
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25.0"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "edgecron-python"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Official Python SDK for the EdgeCron webhook scheduling and callback delivery platform."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "EdgeCron Team" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["edgecron", "webhook", "scheduling", "callback", "delivery"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"requests>=2.31.0,<3"
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
test = [
|
|
35
|
+
"pytest>=8,<9"
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/edgecron/edgecron-python"
|
|
40
|
+
Repository = "https://github.com/edgecron/edgecron-python"
|
|
41
|
+
Documentation = "https://www.edgecron.com"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.wheel]
|
|
44
|
+
packages = ["src/edgecron"]
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Cron schedule CRUD - create, list, update, pause, resume, and delete a schedule."""
|
|
2
|
+
import os
|
|
3
|
+
from edgecron import EdgeCron
|
|
4
|
+
from edgecron.types import CreateScheduleRequest, UpdateScheduleRequest
|
|
5
|
+
|
|
6
|
+
key_id = os.environ["EDGECRON_KEY_ID"]
|
|
7
|
+
secret = os.environ["EDGECRON_SECRET"]
|
|
8
|
+
client = EdgeCron(key_id, secret, base_url="http://localhost:8888")
|
|
9
|
+
|
|
10
|
+
# 1. Create a cron schedule
|
|
11
|
+
schedule = client.schedules.create(CreateScheduleRequest(
|
|
12
|
+
name="daily-report",
|
|
13
|
+
cron_expr="0 8 * * *",
|
|
14
|
+
timezone="Asia/Shanghai",
|
|
15
|
+
payload='{"report": "daily"}',
|
|
16
|
+
))
|
|
17
|
+
print(f"Schedule created: {schedule.id} ({schedule.name})")
|
|
18
|
+
|
|
19
|
+
# 2. List all schedules
|
|
20
|
+
schedules = client.schedules.list(page=1, page_size=20)
|
|
21
|
+
print(f"Total schedules: {schedules.total}")
|
|
22
|
+
|
|
23
|
+
# 3. Get the schedule by ID
|
|
24
|
+
got = client.schedules.get(schedule.id)
|
|
25
|
+
print(f"Got schedule: {got.name} status={got.status}")
|
|
26
|
+
|
|
27
|
+
# 4. Update the schedule name
|
|
28
|
+
updated = client.schedules.update(schedule.id, UpdateScheduleRequest(
|
|
29
|
+
name="daily-report-updated",
|
|
30
|
+
))
|
|
31
|
+
print(f"Updated schedule: {updated.name}")
|
|
32
|
+
|
|
33
|
+
# 5. Pause the schedule
|
|
34
|
+
client.schedules.pause(schedule.id)
|
|
35
|
+
print("Schedule paused")
|
|
36
|
+
|
|
37
|
+
# 6. Resume the schedule
|
|
38
|
+
client.schedules.resume(schedule.id)
|
|
39
|
+
print("Schedule resumed")
|
|
40
|
+
|
|
41
|
+
# 7. Delete the schedule
|
|
42
|
+
client.schedules.delete(schedule.id)
|
|
43
|
+
print("Schedule deleted")
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Schedule a delayed task - EdgeCron's primary use case."""
|
|
2
|
+
import os
|
|
3
|
+
from edgecron import EdgeCron, APIError
|
|
4
|
+
from edgecron.types import CreateEndpointRequest, CreateTaskRequest
|
|
5
|
+
|
|
6
|
+
key_id = os.environ["EDGECRON_KEY_ID"]
|
|
7
|
+
secret = os.environ["EDGECRON_SECRET"]
|
|
8
|
+
client = EdgeCron(key_id, secret, base_url="http://localhost:8888")
|
|
9
|
+
|
|
10
|
+
# 1. Create a webhook endpoint
|
|
11
|
+
endpoint = client.endpoints.create(CreateEndpointRequest(
|
|
12
|
+
name="my-webhook",
|
|
13
|
+
url="https://httpbin.org/post",
|
|
14
|
+
))
|
|
15
|
+
print(f"Endpoint created: {endpoint.id}")
|
|
16
|
+
|
|
17
|
+
# 2. Schedule a task
|
|
18
|
+
task = client.tasks.create(CreateTaskRequest(
|
|
19
|
+
endpoint_id=endpoint.id,
|
|
20
|
+
payload='{"order_id": "ord_9102"}',
|
|
21
|
+
))
|
|
22
|
+
print(f"Task created: {task.id}")
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Webhook delivery recovery - retry policy, endpoint with retry, and manual retry."""
|
|
2
|
+
import os
|
|
3
|
+
from edgecron import EdgeCron
|
|
4
|
+
from edgecron.types import (
|
|
5
|
+
CreateEndpointRequest,
|
|
6
|
+
CreateRetryPolicyRequest,
|
|
7
|
+
CreateTaskRequest,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
key_id = os.environ["EDGECRON_KEY_ID"]
|
|
11
|
+
secret = os.environ["EDGECRON_SECRET"]
|
|
12
|
+
client = EdgeCron(key_id, secret, base_url="http://localhost:8888")
|
|
13
|
+
|
|
14
|
+
# 1. Create a retry policy
|
|
15
|
+
policy = client.retries.create_policy(CreateRetryPolicyRequest(
|
|
16
|
+
name="my-retry-policy",
|
|
17
|
+
max_attempts=5,
|
|
18
|
+
backoff_type="exponential",
|
|
19
|
+
initial_delay_sec=10,
|
|
20
|
+
max_delay_sec=3600,
|
|
21
|
+
))
|
|
22
|
+
print(f"Retry policy created: {policy.id}")
|
|
23
|
+
|
|
24
|
+
# 2. Create an endpoint that uses the retry policy
|
|
25
|
+
endpoint = client.endpoints.create(CreateEndpointRequest(
|
|
26
|
+
name="retry-endpoint",
|
|
27
|
+
url="https://httpbin.org/post",
|
|
28
|
+
retry_policy_id=policy.id,
|
|
29
|
+
))
|
|
30
|
+
print(f"Endpoint created: {endpoint.id} (retry_policy_id={endpoint.retry_policy_id})")
|
|
31
|
+
|
|
32
|
+
# 3. Create a task (will trigger delivery to the endpoint)
|
|
33
|
+
task = client.tasks.create(CreateTaskRequest(
|
|
34
|
+
endpoint_id=endpoint.id,
|
|
35
|
+
payload='{"order_id": "ord_1234"}',
|
|
36
|
+
))
|
|
37
|
+
print(f"Task created: {task.id}")
|
|
38
|
+
|
|
39
|
+
# 4. List deliveries
|
|
40
|
+
deliveries = client.deliveries.list(page=1, page_size=20)
|
|
41
|
+
print(f"Total deliveries: {deliveries.total}")
|
|
42
|
+
if deliveries.list:
|
|
43
|
+
for d in deliveries.list:
|
|
44
|
+
print(f" Delivery {d.id}: task={d.task_id} status={d.status}")
|
|
45
|
+
|
|
46
|
+
# 5. Find the first failed delivery and retry it
|
|
47
|
+
failed = [d for d in deliveries.list if d.status == "failed"]
|
|
48
|
+
if failed:
|
|
49
|
+
result = client.deliveries.retry(failed[0].id)
|
|
50
|
+
print(f"Retry initiated: delivery={result.delivery_id} job={result.retry_job_id} status={result.status}")
|
|
51
|
+
else:
|
|
52
|
+
print("No failed deliveries found to retry")
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""EdgeCron Python SDK."""
|
|
2
|
+
|
|
3
|
+
from .client import EdgeCron
|
|
4
|
+
from .error import APIError, is_api_error
|
|
5
|
+
from .types import (
|
|
6
|
+
CreateEndpointRequest,
|
|
7
|
+
CreateRetryPolicyRequest,
|
|
8
|
+
CreateScheduleRequest,
|
|
9
|
+
CreateTaskRequest,
|
|
10
|
+
Delivery,
|
|
11
|
+
DeliveryList,
|
|
12
|
+
EndpointList,
|
|
13
|
+
Event,
|
|
14
|
+
EventList,
|
|
15
|
+
PublishEventRequest,
|
|
16
|
+
PublishEventResult,
|
|
17
|
+
ResourceLimits,
|
|
18
|
+
RetryDeliveryResult,
|
|
19
|
+
RetryJob,
|
|
20
|
+
RetryJobList,
|
|
21
|
+
RetryPolicy,
|
|
22
|
+
RetryPolicyList,
|
|
23
|
+
Schedule,
|
|
24
|
+
ScheduleList,
|
|
25
|
+
SubscriptionQuota,
|
|
26
|
+
Task,
|
|
27
|
+
TaskList,
|
|
28
|
+
UpdateEndpointRequest,
|
|
29
|
+
UpdateRetryPolicyRequest,
|
|
30
|
+
UpdateScheduleRequest,
|
|
31
|
+
UsageRecords,
|
|
32
|
+
WebhookEndpoint,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__version__ = "1.2.0"
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"APIError",
|
|
39
|
+
"CreateEndpointRequest",
|
|
40
|
+
"CreateRetryPolicyRequest",
|
|
41
|
+
"CreateScheduleRequest",
|
|
42
|
+
"CreateTaskRequest",
|
|
43
|
+
"Delivery",
|
|
44
|
+
"DeliveryList",
|
|
45
|
+
"EdgeCron",
|
|
46
|
+
"EndpointList",
|
|
47
|
+
"Event",
|
|
48
|
+
"EventList",
|
|
49
|
+
"PublishEventRequest",
|
|
50
|
+
"PublishEventResult",
|
|
51
|
+
"ResourceLimits",
|
|
52
|
+
"RetryDeliveryResult",
|
|
53
|
+
"RetryJob",
|
|
54
|
+
"RetryJobList",
|
|
55
|
+
"RetryPolicy",
|
|
56
|
+
"RetryPolicyList",
|
|
57
|
+
"Schedule",
|
|
58
|
+
"ScheduleList",
|
|
59
|
+
"SubscriptionQuota",
|
|
60
|
+
"Task",
|
|
61
|
+
"TaskList",
|
|
62
|
+
"UpdateEndpointRequest",
|
|
63
|
+
"UpdateRetryPolicyRequest",
|
|
64
|
+
"UpdateScheduleRequest",
|
|
65
|
+
"UsageRecords",
|
|
66
|
+
"WebhookEndpoint",
|
|
67
|
+
"__version__",
|
|
68
|
+
"is_api_error",
|
|
69
|
+
]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Public client entrypoint for the EdgeCron SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
|
|
10
|
+
from .deliveries import DeliveriesService
|
|
11
|
+
from .endpoints import EndpointsService
|
|
12
|
+
from .events import EventsService
|
|
13
|
+
from .retries import RetriesService
|
|
14
|
+
from .schedules import SchedulesService
|
|
15
|
+
from .subscription import SubscriptionService
|
|
16
|
+
from .tasks import TasksService
|
|
17
|
+
from .transport import DEFAULT_BASE_URL, SDK_VERSION, Transport
|
|
18
|
+
|
|
19
|
+
_KEY_ID_RE = re.compile(r"^ak_[0-9a-zA-Z_]+$")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class EdgeCron:
|
|
23
|
+
"""EdgeCron API client.
|
|
24
|
+
|
|
25
|
+
The client is safe to reuse across requests. Create once and reuse.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
version = SDK_VERSION
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
key_id: str,
|
|
33
|
+
secret: str,
|
|
34
|
+
*,
|
|
35
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
36
|
+
timeout: float = 30.0,
|
|
37
|
+
session: Optional[requests.Session] = None,
|
|
38
|
+
) -> None:
|
|
39
|
+
if not _KEY_ID_RE.fullmatch(key_id):
|
|
40
|
+
raise ValueError(f"edgecron: key_id must match ak_<hex>, got: {key_id}")
|
|
41
|
+
if not secret:
|
|
42
|
+
raise ValueError("edgecron: secret must not be empty")
|
|
43
|
+
|
|
44
|
+
self._transport = Transport(
|
|
45
|
+
key_id=key_id,
|
|
46
|
+
secret=secret,
|
|
47
|
+
base_url=base_url,
|
|
48
|
+
timeout=timeout,
|
|
49
|
+
session=session,
|
|
50
|
+
)
|
|
51
|
+
self.schedules = SchedulesService(self._transport)
|
|
52
|
+
self.tasks = TasksService(self._transport)
|
|
53
|
+
self.events = EventsService(self._transport)
|
|
54
|
+
self.endpoints = EndpointsService(self._transport)
|
|
55
|
+
self.deliveries = DeliveriesService(self._transport)
|
|
56
|
+
self.retries = RetriesService(self._transport)
|
|
57
|
+
self.subscription = SubscriptionService(self._transport)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Delivery APIs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from .transport import Transport
|
|
8
|
+
from .types import Delivery, DeliveryList, RetryDeliveryResult
|
|
9
|
+
from .schedules import _page_query
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DeliveriesService:
|
|
13
|
+
def __init__(self, transport: Transport) -> None:
|
|
14
|
+
self._transport = transport
|
|
15
|
+
|
|
16
|
+
def list(
|
|
17
|
+
self,
|
|
18
|
+
page: int = 1,
|
|
19
|
+
page_size: int = 20,
|
|
20
|
+
status: str = "",
|
|
21
|
+
task_id: int = 0,
|
|
22
|
+
endpoint_id: int = 0,
|
|
23
|
+
) -> DeliveryList:
|
|
24
|
+
q = _page_query(page, page_size)
|
|
25
|
+
if status:
|
|
26
|
+
q["status"] = status
|
|
27
|
+
if task_id > 0:
|
|
28
|
+
q["task_id"] = task_id
|
|
29
|
+
if endpoint_id > 0:
|
|
30
|
+
q["endpoint_id"] = endpoint_id
|
|
31
|
+
data = self._transport.request_json("GET", "/v1/deliveries", query=q)
|
|
32
|
+
items = [Delivery(**d) for d in (data.get("list") or [])]
|
|
33
|
+
return DeliveryList(total=data.get("total", 0), list=items)
|
|
34
|
+
|
|
35
|
+
def retry(self, id: int) -> RetryDeliveryResult:
|
|
36
|
+
data = self._transport.request_json("POST", f"/v1/deliveries/{id}/retry")
|
|
37
|
+
return RetryDeliveryResult(**data)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Webhook endpoint APIs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from .transport import Transport
|
|
8
|
+
from .types import CreateEndpointRequest, EndpointList, UpdateEndpointRequest, WebhookEndpoint
|
|
9
|
+
from .schedules import _compact, _page_query, _asdict
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class EndpointsService:
|
|
13
|
+
def __init__(self, transport: Transport) -> None:
|
|
14
|
+
self._transport = transport
|
|
15
|
+
|
|
16
|
+
def create(self, req: CreateEndpointRequest) -> WebhookEndpoint:
|
|
17
|
+
data = self._transport.request_json("POST", "/v1/endpoints", body=_asdict(req))
|
|
18
|
+
return WebhookEndpoint(**data)
|
|
19
|
+
|
|
20
|
+
def get(self, id: int) -> WebhookEndpoint:
|
|
21
|
+
data = self._transport.request_json("GET", f"/v1/endpoints/{id}")
|
|
22
|
+
return WebhookEndpoint(**data)
|
|
23
|
+
|
|
24
|
+
def update(self, id: int, req: UpdateEndpointRequest) -> WebhookEndpoint:
|
|
25
|
+
data = self._transport.request_json("PATCH", f"/v1/endpoints/{id}", body=_compact(_asdict(req)))
|
|
26
|
+
return WebhookEndpoint(**data)
|
|
27
|
+
|
|
28
|
+
def list(self, page: int = 1, page_size: int = 20, status: str = "") -> EndpointList:
|
|
29
|
+
q = _page_query(page, page_size)
|
|
30
|
+
if status:
|
|
31
|
+
q["status"] = status
|
|
32
|
+
data = self._transport.request_json("GET", "/v1/endpoints", query=q)
|
|
33
|
+
items = [WebhookEndpoint(**ep) for ep in (data.get("list") or [])]
|
|
34
|
+
return EndpointList(total=data.get("total", 0), list=items)
|
|
35
|
+
|
|
36
|
+
def delete(self, id: int) -> None:
|
|
37
|
+
self._transport.request_json("DELETE", f"/v1/endpoints/{id}")
|
|
38
|
+
|
|
39
|
+
def enable(self, id: int) -> None:
|
|
40
|
+
self._transport.request_json("POST", f"/v1/endpoints/{id}/enable")
|
|
41
|
+
|
|
42
|
+
def disable(self, id: int) -> None:
|
|
43
|
+
self._transport.request_json("POST", f"/v1/endpoints/{id}/disable")
|