data-orchestrator 0.1.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.
Files changed (48) hide show
  1. data_orchestrator-0.1.0/LICENSE +21 -0
  2. data_orchestrator-0.1.0/PKG-INFO +600 -0
  3. data_orchestrator-0.1.0/README.md +572 -0
  4. data_orchestrator-0.1.0/data_orchestrator.egg-info/PKG-INFO +600 -0
  5. data_orchestrator-0.1.0/data_orchestrator.egg-info/SOURCES.txt +46 -0
  6. data_orchestrator-0.1.0/data_orchestrator.egg-info/dependency_links.txt +1 -0
  7. data_orchestrator-0.1.0/data_orchestrator.egg-info/entry_points.txt +2 -0
  8. data_orchestrator-0.1.0/data_orchestrator.egg-info/requires.txt +22 -0
  9. data_orchestrator-0.1.0/data_orchestrator.egg-info/top_level.txt +1 -0
  10. data_orchestrator-0.1.0/orchestrator/__init__.py +17 -0
  11. data_orchestrator-0.1.0/orchestrator/cli.py +229 -0
  12. data_orchestrator-0.1.0/orchestrator/config/__init__.py +5 -0
  13. data_orchestrator-0.1.0/orchestrator/config/loader.py +136 -0
  14. data_orchestrator-0.1.0/orchestrator/config/settings.py +19 -0
  15. data_orchestrator-0.1.0/orchestrator/config/template.py +23 -0
  16. data_orchestrator-0.1.0/orchestrator/connectors/__init__.py +18 -0
  17. data_orchestrator-0.1.0/orchestrator/connectors/base.py +42 -0
  18. data_orchestrator-0.1.0/orchestrator/connectors/builtin/__init__.py +5 -0
  19. data_orchestrator-0.1.0/orchestrator/connectors/builtin/csv_file.py +72 -0
  20. data_orchestrator-0.1.0/orchestrator/connectors/builtin/http_api.py +120 -0
  21. data_orchestrator-0.1.0/orchestrator/connectors/builtin/postgres.py +59 -0
  22. data_orchestrator-0.1.0/orchestrator/connectors/loader.py +26 -0
  23. data_orchestrator-0.1.0/orchestrator/connectors/registry.py +46 -0
  24. data_orchestrator-0.1.0/orchestrator/core/__init__.py +18 -0
  25. data_orchestrator-0.1.0/orchestrator/core/api.py +102 -0
  26. data_orchestrator-0.1.0/orchestrator/core/pipeline.py +110 -0
  27. data_orchestrator-0.1.0/orchestrator/core/runner.py +393 -0
  28. data_orchestrator-0.1.0/orchestrator/core/schedule.py +25 -0
  29. data_orchestrator-0.1.0/orchestrator/core/scheduler.py +369 -0
  30. data_orchestrator-0.1.0/orchestrator/core/task.py +95 -0
  31. data_orchestrator-0.1.0/orchestrator/exceptions.py +42 -0
  32. data_orchestrator-0.1.0/orchestrator/log/__init__.py +5 -0
  33. data_orchestrator-0.1.0/orchestrator/log/models.py +55 -0
  34. data_orchestrator-0.1.0/orchestrator/log/reader.py +197 -0
  35. data_orchestrator-0.1.0/orchestrator/log/writer.py +83 -0
  36. data_orchestrator-0.1.0/orchestrator/notify/__init__.py +12 -0
  37. data_orchestrator-0.1.0/orchestrator/notify/base.py +39 -0
  38. data_orchestrator-0.1.0/orchestrator/notify/builtin/__init__.py +4 -0
  39. data_orchestrator-0.1.0/orchestrator/notify/builtin/feishu_notifier.py +41 -0
  40. data_orchestrator-0.1.0/orchestrator/notify/builtin/log_notifier.py +21 -0
  41. data_orchestrator-0.1.0/orchestrator/notify/manager.py +98 -0
  42. data_orchestrator-0.1.0/orchestrator/streamlit_thread.py +17 -0
  43. data_orchestrator-0.1.0/orchestrator/ui/__init__.py +3 -0
  44. data_orchestrator-0.1.0/orchestrator/ui/app.py +408 -0
  45. data_orchestrator-0.1.0/pyproject.toml +36 -0
  46. data_orchestrator-0.1.0/setup.cfg +4 -0
  47. data_orchestrator-0.1.0/tests/test_cli.py +188 -0
  48. data_orchestrator-0.1.0/tests/test_smoke.py +7 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Livid Su
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,600 @@
1
+ Metadata-Version: 2.4
2
+ Name: data-orchestrator
3
+ Version: 0.1.0
4
+ Summary: Lightweight private data orchestration framework.
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: pydantic>=2.0
9
+ Requires-Dist: pydantic-settings>=2.0
10
+ Requires-Dist: apscheduler>=3.10
11
+ Requires-Dist: tenacity>=8.0
12
+ Requires-Dist: sqlalchemy>=2.0
13
+ Requires-Dist: click>=8.0
14
+ Requires-Dist: pyyaml>=6.0
15
+ Requires-Dist: rich>=13.0
16
+ Requires-Dist: jinja2>=3.0
17
+ Requires-Dist: requests>=2.31
18
+ Provides-Extra: ui
19
+ Requires-Dist: streamlit>=1.30; extra == "ui"
20
+ Provides-Extra: postgres
21
+ Requires-Dist: psycopg2-binary>=2.9; extra == "postgres"
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest; extra == "dev"
24
+ Requires-Dist: pytest-cov; extra == "dev"
25
+ Requires-Dist: responses; extra == "dev"
26
+ Requires-Dist: freezegun; extra == "dev"
27
+ Dynamic: license-file
28
+
29
+ # Data Orchestrator
30
+
31
+ > 轻量级数据编排框架。把所有"定期去某个地方拿数据、处理、再放到某个地方"的事情,统一管理起来。
32
+
33
+ ---
34
+
35
+ ## 目录
36
+
37
+ - [为什么要用这个](#为什么要用这个)
38
+ - [核心特性](#核心特性)
39
+ - [快速开始](#快速开始)
40
+ - [核心概念](#核心概念)
41
+ - [编写 Connector](#编写-connector)
42
+ - [编写 Pipeline (YAML)](#编写-pipeline-yaml)
43
+ - [调度配置](#调度配置)
44
+ - [数据流传递](#数据流传递)
45
+ - [重试与超时](#重试与超时)
46
+ - [告警通知](#告警通知)
47
+ - [Web UI 界面](#web-ui-界面)
48
+ - [命令行与 API 管理](#命令行与-api-管理)
49
+ - [内置 Connector](#内置-connector)
50
+ - [与现有方案对比](#与现有方案对比)
51
+
52
+ ---
53
+
54
+ ## 为什么要用这个
55
+
56
+ 你的数据任务大概是这个样子:
57
+
58
+ ```
59
+ ❌ 现在
60
+ ────────────────────────────────────────────────────────────
61
+ scripts/pull_orders.py ← 每天手动跑,或者一个 crontab
62
+ scripts/sync_feishu.py ← 偶尔失败,你不知道
63
+ scripts/generate_report.py ← 上次跑成功是什么时候?忘了
64
+ ────────────────────────────────────────────────────────────
65
+ 没有重试 没有日志 没有告警 出了问题靠命
66
+ ```
67
+
68
+ ```
69
+ ✅ 用 Orchestrator 之后
70
+ ────────────────────────────────────────────────────────────
71
+ pipelines/
72
+ daily_sync.yaml ← 描述你要做什么
73
+ weekly_report.yaml
74
+ connectors/
75
+ shopify.py ← 一次编写,永久复用
76
+ feishu.py
77
+
78
+ $ orchestrator run ← 启动,自带 Web UI
79
+ ────────────────────────────────────────────────────────────
80
+ ✓ 定时自动触发 ✓ 失败自动重试、超时控制
81
+ ✓ DAG 并发执行与数据流传递 ✓ Web UI 可视化面板与日志检索
82
+ ✓ HTTP API 调度管控 ✓ 飞书告警通知防抖
83
+ ```
84
+
85
+ ---
86
+
87
+ ## 核心特性
88
+
89
+ - **业务与框架分离**:框架只提供骨架(调度、重试、日志、UI、API),Connector 和 Pipeline 完全放在你的项目中独立维护。升级框架不影响你的业务代码。
90
+ - **YAML 编排驱动**:支持任务 DAG 依赖(`depends_on`),可控制全局并发与失败阻断策略。
91
+ - **数据流传递**:支持上游任务输出无缝作为下游任务的输入(`pass_output_from`)。
92
+ - **运行时动态模板**:使用 Jinja 模板(如 `{{ today }}`、`{{ yesterday_iso }}`、`{{ run_id }}`),并在执行时而非加载时动态渲染。
93
+ - **内置 Web UI 与 API**:基于 Streamlit 的可视化看板,并内置轻量级 HTTP API,支持外部系统进行触发管控。
94
+ - **Pipeline 级 Hook**:支持 `on_success` 和 `on_failure`,轻松实现流水线串联或回调通知。
95
+ - **连接器生命周期管理**:连接器在一次 Pipeline 执行中跨 Task 自动复用,提供同步及默认的 `async_fetch` / `async_push` 异步封装。
96
+
97
+ ---
98
+
99
+ ## 快速开始
100
+
101
+ ### 1. 安装
102
+
103
+ ```bash
104
+ pip install data-orchestrator[ui,postgres]
105
+ ```
106
+
107
+ *(可选:仅安装核心依赖 `pip install data-orchestrator`)*
108
+
109
+ ### 2. 初始化项目
110
+
111
+ 使用 `init` 命令快速生成骨架代码:
112
+
113
+ ```bash
114
+ orchestrator init my_data_project
115
+ cd my_data_project
116
+ ```
117
+
118
+ 这将自动生成如下目录结构:
119
+ ```
120
+ my_data_project/
121
+ ├── connectors/
122
+ │ └── demo.py # 你的自定义逻辑
123
+ ├── pipelines/
124
+ │ └── demo.yaml # 任务编排配置
125
+ └── main.py # 启动脚本
126
+ ```
127
+
128
+ ### 3. 启动运行
129
+
130
+ ```bash
131
+ # 通过 CLI 启动
132
+ orchestrator run --config pipelines/ --plugins connectors/
133
+
134
+ # 或者直接运行 main.py
135
+ python main.py
136
+ ```
137
+
138
+ 启动后,访问 **http://localhost:8501** 即可看到内置的可视化看板。
139
+
140
+ ---
141
+
142
+ ## 核心概念
143
+
144
+ ```
145
+ Connector ── 知道怎么和某个系统交互。不仅限 fetch / push,
146
+ 你可以定义任意 action(如 send_report)。
147
+
148
+ Task ── 用某个 Connector 执行具体的动作(拉数据/推数据)
149
+
150
+ Pipeline ── 将多个 Task 按 DAG(有向无环图)组合成一条数据链路
151
+
152
+ Scheduler ── 决定 Pipeline 的执行策略(cron / interval / manual)
153
+
154
+ UI / API ── 可视化与管控接口
155
+ ```
156
+
157
+ **核心设计原则:框架提供骨架,业务代码在框架外。**
158
+ 框架只负责调度、重试、日志、通知这些通用能力。你的 Connector 实现、YAML 配置,完全放在自己的项目里,通过注册机制接入框架。
159
+
160
+ ---
161
+
162
+ ## 编写 Connector
163
+
164
+ 所有 Connector 继承 `BaseConnector`,只需实现自己用到的方法。
165
+ 框架通过 YAML 里的 `action` 字段按名称调用方法,因此 Connector 上的任何公开方法都可以作为 action。`fetch` / `push` / `ping` 是常见约定,但不是强制要求。
166
+
167
+ ```python
168
+ # connectors/shopify.py
169
+ import requests
170
+ from orchestrator import BaseConnector, register_connector
171
+
172
+ @register_connector("shopify")
173
+ class ShopifyConnector(BaseConnector):
174
+
175
+ def __init__(self, config: dict):
176
+ super().__init__(config)
177
+ self.shop_url = config["shop_url"]
178
+ self.access_token = config["access_token"]
179
+ self.session = requests.Session()
180
+ self.session.headers.update({"X-Shopify-Access-Token": self.access_token})
181
+
182
+ def fetch(self, endpoint: str, params: dict = None, **kwargs):
183
+ """拉取数据:返回值将作为 TaskResult.output 传递给下游"""
184
+ url = f"{self.shop_url}/admin/api/2024-01/{endpoint}"
185
+ r = self.session.get(url, params=params)
186
+ r.raise_for_status()
187
+ return r.json()
188
+
189
+ def push(self, data, endpoint: str, **kwargs):
190
+ """推送数据:data 参数可以通过 pass_output_from 由上游 Task 传入"""
191
+ url = f"{self.shop_url}/admin/api/2024-01/{endpoint}"
192
+ self.session.post(url, json=data)
193
+
194
+ def ping(self) -> bool:
195
+ """连通性健康检查:返回 True/False,不要抛异常。框架启动时进行验证"""
196
+ try:
197
+ r = self.session.get(f"{self.shop_url}/admin/api/2024-01/shop.json", timeout=5)
198
+ return r.status_code == 200
199
+ except Exception:
200
+ return False
201
+ ```
202
+
203
+ *(提示:Pipeline 执行过程中,框架会缓存并复用配置相同的 Connector 实例,执行完毕后统一调用 `close()`,降低连接建立开销)*
204
+
205
+ ### 自定义 Action
206
+
207
+ 不是所有场景都适合 `fetch` / `push` 的语义。你可以定义任意方法名:
208
+
209
+ ```python
210
+ import requests
211
+ from orchestrator import BaseConnector, register_connector
212
+
213
+ @register_connector("feishu_daily")
214
+ class FeishuDailyConnector(BaseConnector):
215
+ def __init__(self, config: dict):
216
+ super().__init__(config)
217
+ self.webhook_url = config["webhook_url"]
218
+
219
+ def send_report(self, title: str = "日报", content: str = "", **kwargs):
220
+ payload = {"msg_type": "text", "content": {"text": f"{title}\n{content}"}}
221
+ resp = requests.post(self.webhook_url, json=payload, timeout=10)
222
+ resp.raise_for_status()
223
+ return resp.json()
224
+ ```
225
+
226
+ 在 YAML 里对应的使用方式:
227
+
228
+ ```yaml
229
+ tasks:
230
+ - id: send_daily
231
+ connector: feishu_daily
232
+ action: send_report
233
+ action_kwargs:
234
+ title: "{{ today }} 日报"
235
+ content: "数据同步完成"
236
+ ```
237
+
238
+ ### Connector 配置安全
239
+
240
+ Connector 的敏感配置(token、密码)建议写在 `.env` 中,YAML 里使用 `${VAR_NAME}` 引用:
241
+
242
+ ```yaml
243
+ connector_config:
244
+ shop_url: "${SHOPIFY_SHOP_URL}"
245
+ access_token: "${SHOPIFY_ACCESS_TOKEN}"
246
+ ```
247
+
248
+ ---
249
+
250
+ ## 编写 Pipeline (YAML)
251
+
252
+ 在 `pipelines/` 目录下创建 YAML 文件来编排你的任务:
253
+
254
+ ```yaml
255
+ pipelines:
256
+ - id: daily_order_sync # 唯一 ID,CLI 触发时用
257
+ name: 每日订单同步 # 可读名称,显示在 UI 里
258
+ description: 从 Shopify 拉取昨日订单,写入 Postgres
259
+
260
+ # 调度配置:cron / interval / manual
261
+ schedule:
262
+ type: cron
263
+ cron_expr: "0 6 * * *"
264
+ timezone: "Asia/Shanghai"
265
+
266
+ # Pipeline 级别设置
267
+ max_concurrency: 4 # 无依赖任务的最大并发数
268
+ stop_on_failure: true # 某个 Task 失败后,是否停止后续 Task
269
+
270
+ # 钩子(可选),可串联流水线或触发回调
271
+ on_success: "trigger:another_pipeline_id"
272
+ on_failure: "my_module:my_alert_function"
273
+
274
+ # 通知配置(见下方"告警通知"章节)
275
+ notify:
276
+ on_task_failure: true
277
+ channels:
278
+ - name: feishu
279
+ config:
280
+ webhook_url: "${FEISHU_WEBHOOK}"
281
+
282
+ tasks:
283
+ - id: fetch_orders # Task ID,depends_on 里引用这个
284
+ name: 拉取订单
285
+ connector: shopify # 对应 @register_connector("shopify")
286
+ connector_config:
287
+ shop_url: "${SHOPIFY_URL}"
288
+ access_token: "${SHOPIFY_TOKEN}"
289
+ action: fetch # Connector 上的任意方法名
290
+ action_kwargs: # 传给 connector.fetch() 的参数
291
+ endpoint: orders.json
292
+ params:
293
+ created_at_min: "{{ yesterday_iso }}" # 运行时动态渲染内置变量
294
+ retry:
295
+ times: 3
296
+ delay_seconds: 10
297
+ backoff: 2.0 # 指数退避:10s → 20s → 40s
298
+ timeout_seconds: 60
299
+
300
+ - id: write_to_postgres
301
+ name: 写入数据库
302
+ connector: postgres
303
+ connector_config:
304
+ dsn: "${DATABASE_URL}"
305
+ action: push
306
+ depends_on: [fetch_orders] # 依赖 fetch_orders 完成后才执行
307
+ pass_output_from: fetch_orders # 把 fetch_orders 的输出作为 data 传入
308
+ action_kwargs:
309
+ table: shopify_orders
310
+ mode: upsert
311
+ upsert_key: order_id
312
+ ```
313
+
314
+ ### 内置模板变量
315
+
316
+ 在 `action_kwargs` 中可以使用 Jinja 语法注入时间上下文,**在任务实际执行时计算**(非启动时计算,避免长驻进程时间不更新的问题):
317
+
318
+ | 变量 | 含义 | 示例值 |
319
+ |---|---|---|
320
+ | `{{ now }}` | 当前时间(ISO 8601) | `2024-03-15T06:00:00+08:00` |
321
+ | `{{ today }}` | 今天日期 | `2024-03-15` |
322
+ | `{{ yesterday }}` | 昨天日期 | `2024-03-14` |
323
+ | `{{ yesterday_iso }}` | 昨天 ISO 格式 | `2024-03-14T00:00:00+08:00` |
324
+ | `{{ run_id }}` | 本次执行的唯一 ID | `run_20240315_060001_a3f2` |
325
+ | `{{ pipeline_id }}` | Pipeline ID | `daily_order_sync` |
326
+ | `{{ week_start }}` | 本周一日期 | `2024-03-11` |
327
+ | `{{ month_start }}` | 本月 1 号 | `2024-03-01` |
328
+
329
+ ---
330
+
331
+ ## 调度配置
332
+
333
+ ### Cron 触发
334
+
335
+ ```yaml
336
+ schedule:
337
+ type: cron
338
+ cron_expr: "0 6 * * *" # 每天早上 6:00
339
+ timezone: "Asia/Shanghai" # 默认 Asia/Shanghai
340
+ start_date: "2024-01-01" # 可选:从某天开始
341
+ end_date: "2024-12-31" # 可选:到某天结束
342
+ ```
343
+
344
+ 常用 Cron 表达式参考:
345
+ - `"0 6 * * *"` : 每天 06:00
346
+ - `"0 */4 * * *"` : 每 4 小时
347
+ - `"0 9 * * 1"` : 每周一 09:00
348
+
349
+ ### 间隔触发
350
+
351
+ ```yaml
352
+ schedule:
353
+ type: interval
354
+ interval_seconds: 300 # 每 5 分钟
355
+ ```
356
+
357
+ ### 手动触发(只能通过 CLI 或 UI 触发)
358
+
359
+ ```yaml
360
+ schedule:
361
+ type: manual
362
+ ```
363
+
364
+ ### 并发控制
365
+
366
+ ```yaml
367
+ schedule:
368
+ type: cron
369
+ cron_expr: "*/5 * * * *"
370
+ max_instances: 1 # 上一次未完成时,不启动新实例(默认 1)
371
+ ```
372
+
373
+ ---
374
+
375
+ ## 数据流传递
376
+
377
+ Task 之间可以传递数据,上游的输出可以自动成为下游的输入。这在 ETL 流程中非常常见。
378
+
379
+ ```yaml
380
+ tasks:
381
+ - id: fetch_from_shopify
382
+ connector: shopify
383
+ action: fetch
384
+ # fetch() 返回的数据被存入内部 TaskResult.output
385
+
386
+ - id: transform
387
+ connector: my_transformer
388
+ action: process
389
+ depends_on: [fetch_from_shopify]
390
+ pass_output_from: fetch_from_shopify # fetch_from_shopify 的输出
391
+ # 会作为 data 参数传入这个 Task
392
+
393
+ - id: write_to_db
394
+ connector: postgres
395
+ action: push
396
+ depends_on: [transform]
397
+ pass_output_from: transform # transform 的输出传给 push(data=...)
398
+ ```
399
+
400
+ 对应的 Transformer Connector 里:
401
+
402
+ ```python
403
+ class MyTransformer(BaseConnector):
404
+ def process(self, data=None, **kwargs): # data 参数接收来自上游的数据
405
+ # 处理数据
406
+ transformed = [clean(row) for row in data["orders"]]
407
+ return transformed # 返回值成为下游的 data
408
+ ```
409
+
410
+ ---
411
+
412
+ ## 重试与超时
413
+
414
+ 你可以为每个 Task 单独配置重试策略和超时时间。
415
+
416
+ ```yaml
417
+ tasks:
418
+ - id: fetch_api
419
+ retry:
420
+ times: 3 # 最多重试 3 次(不含第一次执行)
421
+ delay_seconds: 10 # 第一次重试前等待 10 秒
422
+ backoff: 2.0 # 指数退避:10s → 20s → 40s
423
+ timeout_seconds: 120 # 超过 120 秒强制终止该任务
424
+ ```
425
+
426
+ ---
427
+
428
+ ## 告警通知
429
+
430
+ 框架支持基于配置的通知分发机制,支持防抖。
431
+
432
+ ### 飞书 Webhook
433
+
434
+ 内置了飞书通知器,配置方式如下:
435
+
436
+ ```yaml
437
+ # pipelines/daily_sync.yaml
438
+ notify:
439
+ on_task_failure: true
440
+ on_pipeline_failure: true
441
+ on_pipeline_success: false
442
+ failure_threshold: 1 # 连续失败几次才发通知(防抖)
443
+ channels:
444
+ - name: feishu
445
+ config:
446
+ webhook_url: "${FEISHU_WEBHOOK_URL}"
447
+ ```
448
+
449
+ ### 框架内置的 LogOnlyNotifier
450
+
451
+ 开发环境下如果不想配置 Webhook,可以使用内置的 log 通知器:
452
+
453
+ ```yaml
454
+ notify:
455
+ channels:
456
+ - name: log # 内置,直接用,失败信息仅打印到 stdout
457
+ ```
458
+
459
+ ---
460
+
461
+ ## Web UI 界面
462
+
463
+ 安装了 `data-orchestrator[ui]` 后,框架自带基于 Streamlit 的监控大盘。使用 `orchestrator run` 启动时默认会拉起 UI,或单独启动:
464
+
465
+ ```bash
466
+ orchestrator ui # 默认端口 8501
467
+ orchestrator ui --port 9000 # 自定义端口
468
+ ```
469
+
470
+ UI 包含四个页面:
471
+
472
+ - **Dashboard**:今日总览。显示执行次数、成功率、耗时趋势图表;最近 10 次 Pipeline 执行状态;即将触发的任务列表。
473
+ - **Pipeline 管理**:运维操作。展示所有 Pipeline 的调度状态(运行中 / 已暂停);提供手动触发、暂停、恢复按钮。
474
+ - **Run Detail (执行详情)**:点进某次执行查看详情。展示依赖关系 DAG 可视化图;每个 Task 的状态、耗时、重试次数;失败 Task 可展开查看完整错误堆栈。
475
+ - **Log Search (日志查询)**:历史检索。支持按 Pipeline / 状态 / 时间范围过滤;支持关键词搜索错误信息;分页展示并支持结果导出为 CSV。
476
+
477
+ ---
478
+
479
+ ## 命令行与 API 管理
480
+
481
+ Orchestrator 提供了丰富的 CLI 命令用于日常运维:
482
+
483
+ ```bash
484
+ # 启动调度器并同时开启 UI
485
+ orchestrator run --config pipelines/ --plugins connectors/
486
+
487
+ # 无 UI 模式启动
488
+ orchestrator run --no-ui
489
+
490
+ # 仅启动 UI
491
+ orchestrator ui --port 9000
492
+
493
+ # 运维命令
494
+ orchestrator trigger daily_order_sync # 手动立即触发
495
+ orchestrator list # 查看所有注册的 Pipeline
496
+ orchestrator status daily_order_sync # 查看某个 Pipeline 的最近执行记录
497
+ orchestrator pause daily_order_sync # 暂停调度
498
+ orchestrator resume daily_order_sync # 恢复调度
499
+ orchestrator ping # 检查 Connector 连通性 (调用 ping)
500
+ orchestrator validate # 验证 YAML 配置合法性 (不运行)
501
+ ```
502
+
503
+ ### HTTP API
504
+
505
+ 当 Orchestrator 启动后,后台会自动启动一个轻量级的 HTTP API(默认运行在 8765 端口)。你甚至可以将 `ORCHESTRATOR_API_URL` 提供给外部系统进行调度触发与管控:
506
+
507
+ - `GET /pipelines` - 列出所有流水线状态及下次执行时间
508
+ - `GET /pipeline/{id}` - 获取特定流水线的详细配置
509
+ - `GET /upcoming?hours=2` - 获取未来指定小时内即将触发的任务
510
+ - `POST /trigger/{id}` - 异步触发流水线,返回 run_id
511
+ - `POST /pause/{id}` - 暂停指定流水线
512
+ - `POST /resume/{id}` - 恢复指定流水线
513
+
514
+ ---
515
+
516
+ ## 内置 Connector
517
+
518
+ Orchestrator 内置了常见的通用 Connector,你可以直接在 YAML 中使用,无需额外编写代码:
519
+
520
+ ### `postgres`
521
+
522
+ ```yaml
523
+ connector: postgres
524
+ connector_config:
525
+ dsn: "${DATABASE_URL}"
526
+ action: fetch
527
+ action_kwargs:
528
+ query: "SELECT * FROM orders WHERE created_at >= :date"
529
+ params:
530
+ date: "{{ yesterday }}"
531
+ ```
532
+
533
+ ```yaml
534
+ action: push
535
+ action_kwargs:
536
+ table: orders
537
+ mode: upsert # 支持 insert / upsert / replace / truncate_insert
538
+ upsert_key: order_id
539
+ ```
540
+
541
+ ### `http_api`
542
+
543
+ ```yaml
544
+ connector: http_api
545
+ connector_config:
546
+ base_url: "https://api.example.com"
547
+ headers:
548
+ Authorization: "Bearer ${API_TOKEN}"
549
+ rate_limit_rps: 2 # 每秒最多 2 个请求,自动限速
550
+ action: fetch
551
+ action_kwargs:
552
+ endpoint: /v1/orders
553
+ method: GET # GET / POST / PUT / PATCH / DELETE
554
+ params:
555
+ status: paid
556
+ timeout: 30
557
+ ```
558
+
559
+ ### `csv_file`
560
+
561
+ ```yaml
562
+ connector: csv_file
563
+ connector_config:
564
+ base_dir: "/data/exports"
565
+ action: fetch
566
+ action_kwargs:
567
+ path: "orders_{{ today }}.csv"
568
+ encoding: utf-8
569
+ ```
570
+
571
+ ```yaml
572
+ action: push
573
+ action_kwargs:
574
+ path: "output_{{ today }}.csv"
575
+ mode: overwrite # overwrite / append
576
+ ```
577
+
578
+ ---
579
+
580
+ ## 与现有方案对比
581
+
582
+ | | Orchestrator | Airflow | Prefect | crontab + 脚本 |
583
+ |---|---|---|---|---|
584
+ | **部署复杂度** | **极低** (单进程+SQLite 即可) | 重(Webserver+Scheduler+Worker+DB) | 需连接 Prefect Cloud 或自建 Server | 极简 |
585
+ | **自定义 Connector** | **极简** (几十行代码,任意方法名) | 需编写自定义 Operator,有框架抽象限制 | 需适配框架生态 | 随意但无复用 |
586
+ | **配置管理** | **YAML + 环境变量 + 动态渲染** | Python 脚本生成 DAG | Python 脚本 | 硬编码 |
587
+ | **重试/并发/超时** | ✅ 内置 | ✅ | ✅ | ❌ 自己写 |
588
+ | **可视化与监控** | ✅ 内置 Streamlit UI + HTTP API | ✅ 功能完整 | ✅ 功能完整 | ❌ |
589
+ | **适合团队规模** | **1-5 人 / 中小项目** | 10 人以上数据团队 | 中大型团队 | 1 人 |
590
+ | **学习成本** | **低** | 高 | 中 | 零 |
591
+
592
+ **适合用 Orchestrator 的场景:**
593
+ - 小团队或个人,不想维护 Airflow 这类重型基础设施
594
+ - 数据接口高度定制化,通用适配器成本高
595
+ - 想完全掌控执行逻辑,出了问题能追到每一行代码
596
+ - 已有自己的服务器,只需要一个 Python 进程跑起来
597
+
598
+ ---
599
+
600
+ *MIT License*