hello-datap-component-base 0.2.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.
@@ -0,0 +1,596 @@
1
+ Metadata-Version: 2.4
2
+ Name: hello-datap-component-base
3
+ Version: 0.2.0
4
+ Summary: A unified server management framework for data processing component
5
+ Author-email: zhaohaidong <zhaohaidong389@hellobike.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://gitlab.hellorobotaxi.top/hdata/hello-datap-component-base
8
+ Keywords: data,hello,management,microservice
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: click>=8.0.0
22
+ Requires-Dist: pydantic>=2.0.0
23
+ Requires-Dist: python-json-logger>=2.0.0
24
+ Requires-Dist: pyyaml>=6.0.0
25
+ Requires-Dist: aliyun-mns>=1.1.5
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
28
+ Requires-Dist: black>=23.0.0; extra == "dev"
29
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
30
+
31
+ # 数据处理平台组件基类
32
+
33
+ 统一的数据处理平台组件开发框架,提供标准化的服务管理,统一用户代码的入参和出参以及程序执行入口。
34
+
35
+ ## 功能特性
36
+
37
+ - ✅ **统一的接口规范**:标准化的入参和出参格式
38
+ - ✅ **灵活的执行方式**:可以运行在集群上,也可以独立运行
39
+ - ✅ **灵活的配置加载**:支持本地JSON文件和HTTP远程JSON文件
40
+ - ✅ **完整的生命周期管理**:预处理、处理、后处理钩子
41
+ - ✅ **内置日志系统**:结构化的日志输出,自动包含服务名称和版本信息
42
+ - ✅ **服务发现机制**:自动发现和加载服务类
43
+ - ✅ **动态依赖安装**:支持在配置文件中指定pip包,服务启动前自动安装
44
+ - ✅ **Ray兼容**:日志系统兼容Ray分布式计算框架
45
+
46
+ ## 安装
47
+
48
+ ```bash
49
+ # 从源码安装
50
+ pip install -e .
51
+ ```
52
+
53
+ ## 文档导航
54
+
55
+ - **[用户介入手册](USER_GUIDE.md)** - 详细的用户使用指南,包含安装、开发、配置等完整流程
56
+ - **[快速开始指南](QUICKSTART.md)** - 快速上手指南
57
+
58
+ ## 快速开始
59
+
60
+ ### 1. 创建服务类
61
+
62
+ 创建一个继承自 `BaseService` 的服务类:
63
+
64
+ ```python
65
+ from hello_datap_component_base import BaseService, ServiceConfig
66
+ import asyncio
67
+
68
+ class MyDataService(BaseService):
69
+ """我的数据处理服务"""
70
+
71
+ async def process(self, data: dict) -> dict:
72
+ """处理业务逻辑"""
73
+ # 你的业务逻辑 here
74
+ result = {
75
+ "status": "success",
76
+ "processed_data": data
77
+ }
78
+ return result
79
+ ```
80
+
81
+ ### 2. 创建配置文件
82
+
83
+ 创建配置文件 `config.json`:
84
+
85
+ ```json
86
+ {
87
+ "name": "my-service",
88
+ "version": "1.0.0",
89
+ "runtime_env": {
90
+ "pip": ["requests>=2.25.0"],
91
+ "env_vars": {
92
+ "LOG_LEVEL": "INFO"
93
+ }
94
+ },
95
+ "params": {
96
+ "key": "value",
97
+ "field1": "data1"
98
+ }
99
+ }
100
+ ```
101
+
102
+ **说明**:
103
+ - `runtime_env.pip`: 指定需要安装的Python包,服务启动前会自动安装
104
+ - `params`: 这些参数会作为输入数据传递给 `process` 方法
105
+
106
+ ### 3. 运行服务
107
+
108
+ #### 方式一:使用命令行工具
109
+
110
+ ```bash
111
+ # 启动服务并执行一次处理(输入数据从配置文件的 params 获取)
112
+ component_manager start config.json
113
+
114
+ # 或使用HTTP远程配置
115
+ component_manager start http://example.com/config.json
116
+ ```
117
+
118
+ **注意**:服务启动后会执行一次处理,输出结果后自动退出。输入数据来自配置文件的 `params` 字段,整个 `params` 字典会作为输入数据传递给 `process` 方法。
119
+
120
+ #### 方式二:在代码中直接使用
121
+
122
+ ```python
123
+ import asyncio
124
+ from hello_datap_component_base import BaseService, ServiceConfig
125
+
126
+ # 创建配置
127
+ config = ServiceConfig(
128
+ name="my-service",
129
+ params={"custom_param": "value"}
130
+ )
131
+
132
+ # 创建服务实例
133
+ service = MyDataService(config)
134
+
135
+ # 处理请求
136
+ result = await service.handle_request({"input": "data"})
137
+ ```
138
+
139
+ ## 配置说明
140
+
141
+ ### 配置文件格式
142
+
143
+ 配置文件支持JSON格式,可以存储在本地文件或通过HTTP URL访问。
144
+
145
+ #### 本地文件配置
146
+
147
+ ```json
148
+ {
149
+ "name": "service-name",
150
+ "version": "1.0.0",
151
+ "work_flow_id": 123,
152
+ "work_flow_instance_id": 456,
153
+ "task_id": "task-12345",
154
+ "runtime_env": {
155
+ "pip": ["emoji==2.15.0", "requests>=2.25.0"],
156
+ "env_vars": {
157
+ "LOG_LEVEL": "INFO",
158
+ "CUSTOM_VAR": "value",
159
+ "MNS_ENDPOINT": "https://123456789.mns.cn-shanghai.aliyuncs.com",
160
+ "MNS_ACCESS_KEY_ID": "your-access-key-id",
161
+ "MNS_ACCESS_KEY_SECRET": "your-access-key-secret"
162
+ }
163
+ },
164
+ "params": {
165
+ "field1": "value1",
166
+ "field2": 100
167
+ }
168
+ }
169
+ ```
170
+
171
+ **注意**:
172
+ - `runtime_env.pip` 中的包会在服务启动前自动安装
173
+ - `params` 中的内容会作为输入数据传递给 `process` 方法
174
+ - `work_flow_id`、`work_flow_instance_id`、`task_id` 会包含在返回结果中
175
+ - 如果配置了 MNS 相关环境变量,处理结果会自动发送到 MNS 队列
176
+
177
+ #### HTTP远程配置
178
+
179
+ 配置文件可以通过HTTP URL访问:
180
+
181
+ ```bash
182
+ component_manager start http://example.com/configs/my-service.json
183
+ ```
184
+
185
+ ### 配置字段说明
186
+
187
+ - **name** (必需): 服务名称
188
+ - **version** (可选): 服务版本,会在日志中体现
189
+ - **work_flow_id** (可选): 工作流ID,用于结果追踪
190
+ - **work_flow_instance_id** (可选): 工作流实例ID,用于结果追踪
191
+ - **task_id** (可选): 任务ID,用于结果追踪
192
+ - **runtime_env** (可选): 运行时环境配置
193
+ - **pip**: Python包列表,服务启动前会自动安装这些包。例如:`["emoji==2.15.0", "requests>=2.25.0"]`
194
+ - **env_vars**: 环境变量字典
195
+ - **MNS_ENDPOINT**: 阿里云MNS服务端点(可选,用于发送结果到队列)
196
+ - **MNS_ACCESS_KEY_ID**: 阿里云MNS访问密钥ID(可选)
197
+ - **MNS_ACCESS_KEY_SECRET**: 阿里云MNS访问密钥(可选)
198
+ - **MNS_QUEUE_NAME**: MNS队列名称(可选,默认为 aiinfra-data-process-component-result-queue)
199
+ - **params** (可选): 服务参数,会作为输入数据传递给 `process` 方法,也可以通过 `self.params` 访问
200
+
201
+ ## API 参考
202
+
203
+ ### BaseService
204
+
205
+ 所有服务类必须继承自 `BaseService`。
206
+
207
+ #### 必需实现的方法
208
+
209
+ - `async def process(self, data: Dict[str, Any]) -> Dict[str, Any]`
210
+ - 处理请求的核心业务逻辑
211
+
212
+ #### 可选重写的方法
213
+
214
+ - `async def pre_process(self, data: Dict[str, Any]) -> Dict[str, Any]`
215
+ - 预处理钩子,在 `process` 之前调用
216
+ - 默认返回原始数据
217
+
218
+ - `async def post_process(self, data: Dict[str, Any], result: Dict[str, Any]) -> Dict[str, Any]`
219
+ - 后处理钩子,在 `process` 之后调用
220
+ - 默认返回处理结果
221
+
222
+ #### 属性
223
+
224
+ - `self.config`: 服务配置对象 (`ServiceConfig`)
225
+ - `self.params`: 服务参数字典
226
+ - `self.logger`: 日志器对象
227
+
228
+ ### ServiceConfig
229
+
230
+ 服务配置类:
231
+
232
+ ```python
233
+ ServiceConfig(
234
+ name: str,
235
+ version: Optional[str] = None,
236
+ params: Dict[str, Any] = {},
237
+ runtime_env: Optional[Dict[str, Any]] = None,
238
+ work_flow_id: Optional[int] = None,
239
+ work_flow_instance_id: Optional[int] = None,
240
+ task_id: Optional[str] = None
241
+ )
242
+ ```
243
+
244
+ ### 返回结果格式
245
+
246
+ `handle_request` 方法会自动封装返回结果,格式如下:
247
+
248
+ **正常情况:**
249
+ ```json
250
+ {
251
+ "code": 0,
252
+ "message": "success",
253
+ "processing_time": 0.123,
254
+ "data": {
255
+ "work_flow_id": 123,
256
+ "work_flow_instance_id": 456,
257
+ "task_id": "task-12345",
258
+ "out_put": {
259
+ // 用户程序 process 方法返回的结果
260
+ }
261
+ }
262
+ }
263
+ ```
264
+
265
+ **异常情况:**
266
+ ```json
267
+ {
268
+ "code": -1,
269
+ "message": "错误消息",
270
+ "processing_time": 0.045,
271
+ "data": {
272
+ "work_flow_id": 123,
273
+ "work_flow_instance_id": 456,
274
+ "task_id": "task-12345",
275
+ "out_put": null
276
+ }
277
+ }
278
+ ```
279
+
280
+ **注意**:无论正常还是异常,结果都会自动发送到 MNS 队列(如果配置了 MNS 环境变量)。
281
+
282
+ ### ServiceRunner
283
+
284
+ 服务运行器,用于启动和管理服务:
285
+
286
+ ```python
287
+ runner = ServiceRunner(config_path: str, class_name: Optional[str] = None)
288
+ runner.run()
289
+ ```
290
+
291
+ ## 命令行工具
292
+
293
+ ### 使用方式
294
+
295
+ **方式1:直接使用命令(需要 PATH 配置)**
296
+ ```bash
297
+ component_manager start <config_path>
298
+ component_manager list
299
+ component_manager validate <config_path>
300
+ component_manager test <config_path>
301
+ ```
302
+
303
+ **方式2:使用 Python 模块方式(推荐,不依赖 PATH)**
304
+ ```bash
305
+ python -m hello_datap_component_base.cli start <config_path>
306
+ python -m hello_datap_component_base.cli list
307
+ python -m hello_datap_component_base.cli validate <config_path>
308
+ python -m hello_datap_component_base.cli test <config_path>
309
+ ```
310
+
311
+ ### 启动服务
312
+
313
+ ```bash
314
+ component_manager start <config_path> [--class-name <class_name>]
315
+ # 或
316
+ python -m hello_datap_component_base.cli start <config_path> [--class-name <class_name>]
317
+ ```
318
+
319
+ - `config_path`: 配置文件路径(本地文件或HTTP URL)
320
+ - `--class-name, -c`: 指定要使用的服务类名(可选)
321
+
322
+ ### 列出服务类
323
+
324
+ ```bash
325
+ component_manager list [--json]
326
+ # 或
327
+ python -m hello_datap_component_base.cli list [--json]
328
+ ```
329
+
330
+ 列出所有可用的服务类。
331
+
332
+ ### 验证配置
333
+
334
+ ```bash
335
+ component_manager validate <config_path>
336
+ # 或
337
+ python -m hello_datap_component_base.cli validate <config_path>
338
+ ```
339
+
340
+ 验证配置文件的有效性(支持本地文件或HTTP URL)。
341
+
342
+ ### 测试服务
343
+
344
+ ```bash
345
+ component_manager test <config_path> [data] [--file <file>]
346
+ # 或
347
+ python -m hello_datap_component_base.cli test <config_path> [data] [--file <file>]
348
+ ```
349
+
350
+ 测试服务功能。
351
+
352
+ ## 使用示例
353
+
354
+ 查看 `example_service.py` 了解完整的使用示例。
355
+
356
+ 运行示例:
357
+
358
+ ```bash
359
+ # 直接运行示例代码
360
+ python example_service.py
361
+
362
+ # 或使用配置文件启动(方式1:直接命令)
363
+ component_manager start example_config.json
364
+
365
+ # 或使用配置文件启动(方式2:Python 模块方式,推荐)
366
+ python -m hello_datap_component_base.cli start example_config.json
367
+ ```
368
+
369
+ ## 项目结构
370
+
371
+ ```
372
+ hello-datap-component-base/
373
+ ├── hello_datap_component_base/
374
+ │ ├── __init__.py # 模块导出
375
+ │ ├── base.py # 基础服务类
376
+ │ ├── config.py # 配置管理
377
+ │ ├── runner.py # 服务运行器
378
+ │ ├── cli.py # 命令行工具
379
+ │ ├── discover.py # 服务发现
380
+ │ ├── logger.py # 日志管理
381
+ │ └── mns_client.py # MNS 队列客户端
382
+ ├── example_service.py # 使用示例
383
+ ├── example_config.json # 示例配置
384
+ ├── README.md # 本文档
385
+ ├── USER_GUIDE.md # 用户介入手册
386
+ ├── QUICKSTART.md # 快速开始指南
387
+ └── pyproject.toml # 项目配置
388
+ ```
389
+
390
+ ## 开发指南
391
+
392
+ ### 创建自定义服务
393
+
394
+ 1. 继承 `BaseService` 类
395
+ 2. 实现 `process` 方法
396
+ 3. (可选)重写 `pre_process`、`post_process` 方法
397
+
398
+ ### 日志使用
399
+
400
+ 基类提供了两种使用日志的方式:
401
+
402
+ #### 方式1:使用全局 logger(推荐)
403
+
404
+ 直接导入全局 logger,使用简单方便:
405
+
406
+ ```python
407
+ from hello_datap_component_base import logger
408
+
409
+ # 在服务初始化后,全局 logger 会自动包含服务名称和版本信息
410
+ logger.info("处理请求", extra={"data": data})
411
+ logger.error("处理失败", extra={"error": str(e)})
412
+ ```
413
+
414
+ #### 方式2:使用服务实例的 logger
415
+
416
+ 在服务类内部,可以使用 `self.logger`:
417
+
418
+ ```python
419
+ class YourService(BaseService):
420
+ async def process(self, data: dict) -> dict:
421
+ self.logger.info("处理请求", extra={"data": data})
422
+ return {"result": "success"}
423
+ ```
424
+
425
+ **注意**:
426
+ - 所有日志都会自动包含服务名称和版本信息
427
+ - 日志系统兼容Ray分布式计算框架,在Ray环境中日志会输出到stdout/stderr,Ray会自动收集
428
+ - 在非Ray环境中,日志会同时输出到控制台和文件
429
+ - 推荐使用全局 logger,可以在服务类外部(如工具函数、辅助模块)使用
430
+
431
+ ### 环境变量
432
+
433
+ 通过配置文件中的 `runtime_env.env_vars` 设置环境变量,这些变量会在服务初始化时自动设置。
434
+
435
+ ### 动态安装依赖包
436
+
437
+ 通过配置文件中的 `runtime_env.pip` 指定需要安装的Python包,服务启动前会自动安装:
438
+
439
+ ```json
440
+ {
441
+ "runtime_env": {
442
+ "pip": ["emoji==2.15.0", "requests>=2.25.0"]
443
+ }
444
+ }
445
+ ```
446
+
447
+ **注意**:如果服务类文件在导入时需要这些包(如 `import emoji`),建议将导入改为可选,避免 `list` 命令失败。
448
+
449
+ ### MNS 队列集成
450
+
451
+ 如果配置了 MNS 相关环境变量,处理结果会自动发送到阿里云 MNS 队列:
452
+
453
+ **配置方式:**
454
+ 在配置文件的 `runtime_env.env_vars` 中设置:
455
+ ```json
456
+ {
457
+ "runtime_env": {
458
+ "env_vars": {
459
+ "MNS_ENDPOINT": "https://123456789.mns.cn-shanghai.aliyuncs.com",
460
+ "MNS_ACCESS_KEY_ID": "your-access-key-id",
461
+ "MNS_ACCESS_KEY_SECRET": "your-access-key-secret",
462
+ "MNS_QUEUE_NAME": "aiinfra-data-process-component-result-queue"
463
+ }
464
+ }
465
+ }
466
+ ```
467
+
468
+ **功能特性:**
469
+ - ✅ 自动发送处理结果到队列(正常和异常情况)
470
+ - ✅ 结果格式统一封装(包含 work_flow_id、work_flow_instance_id、task_id)
471
+ - ✅ 如果 MNS 未配置或发送失败,不会影响主流程,只记录警告日志
472
+ - ✅ **自动重试机制**:网络异常时自动重试,确保消息发送成功
473
+ - 默认重试 3 次,使用指数退避策略(1秒、2秒、4秒)
474
+ - 仅对网络异常进行重试(如连接重置、超时等)
475
+ - 可通过环境变量自定义重试参数
476
+
477
+ ## 常见问题
478
+
479
+ **Q: 如何支持HTTP远程配置?**
480
+
481
+ A: 支持三种方式:
482
+
483
+ **方式1:直接使用 URL(简单 URL)**
484
+ ```bash
485
+ component_manager start http://example.com/config.json
486
+ ```
487
+
488
+ **方式2:使用 base64 编码的 URL(推荐,避免 shell 解析问题)**
489
+ ```bash
490
+ # 先对 URL 进行 base64 编码
491
+ python3 -c "import base64; print(base64.b64encode('https://example.com/config.json?key=value&token=abc'.encode()).decode())"
492
+
493
+ # 使用编码后的字符串(不需要引号,避免 shell 解析问题)
494
+ component_manager start aHR0cHM6Ly9leGFtcGxlLmNvbS9jb25maWcuanNvbj9rZXk9dmFsdWUm dG9rZW49YWJj
495
+ ```
496
+
497
+ **方式3:使用引号包裹 URL(包含特殊字符时)**
498
+ ```bash
499
+ # URL 包含特殊字符(必须用引号)
500
+ component_manager start "https://example.com/config.json?key=value&token=abc"
501
+ # 或使用单引号
502
+ component_manager start 'https://example.com/config.json?key=value&token=abc'
503
+ ```
504
+
505
+ **推荐使用 base64 编码方式**,因为:
506
+ - 避免 shell 解析问题(不需要引号)
507
+ - 避免特殊字符转义
508
+ - 更安全可靠
509
+
510
+ **Q: HTTPS 远程配置报 SSL 证书验证失败?**
511
+
512
+ A: 如果使用的是内部服务(如 OSS、内网服务),SSL 证书可能无法验证。可以通过环境变量跳过 SSL 验证:
513
+
514
+ ```bash
515
+ # 临时设置(仅当前会话有效)
516
+ export SKIP_SSL_VERIFY=true
517
+ component_manager start 'https://example.com/config.json'
518
+
519
+ # 或使用 base64 编码的 URL(推荐,避免引号问题)
520
+ export SKIP_SSL_VERIFY=true
521
+ component_manager start aHR0cHM6Ly9leGFtcGxlLmNvbS9jb25maWcuanNvbg==
522
+
523
+ # 或使用 Python 模块方式
524
+ SKIP_SSL_VERIFY=true python -m hello_datap_component_base.cli start 'https://example.com/config.json'
525
+ ```
526
+
527
+ **注意**:
528
+ - 仅在内部服务或测试环境使用 `SKIP_SSL_VERIFY=true`
529
+ - 生产环境建议安装正确的 CA 证书
530
+ - 如果安全要求不高,可以使用 HTTP 代替 HTTPS
531
+ - 使用 base64 编码的 URL 可以避免引号和特殊字符问题
532
+
533
+ **Q: 服务可以独立运行吗?**
534
+
535
+ A: 是的,服务可以独立运行,不依赖任何集群环境。可以直接在代码中创建服务实例并调用。
536
+
537
+ **Q: 如何处理错误?**
538
+
539
+ A: 在 `process` 方法中抛出异常,框架会自动记录错误日志。你也可以在 `pre_process` 或 `post_process` 中进行错误处理。
540
+
541
+ **Q: 输入数据从哪里来?**
542
+
543
+ A: 输入数据来自配置文件的 `params` 字段,整个 `params` 字典会作为输入数据传递给 `process` 方法。示例:
544
+ ```json
545
+ {
546
+ "params": {
547
+ "field1": "value1",
548
+ "field2": 100
549
+ }
550
+ }
551
+ ```
552
+
553
+ **Q: 如何动态安装Python包?**
554
+
555
+ A: 在配置文件的 `runtime_env.pip` 中指定需要安装的包列表,服务启动前会自动安装。示例:
556
+ ```json
557
+ {
558
+ "runtime_env": {
559
+ "pip": ["emoji==2.15.0", "requests>=2.25.0"]
560
+ }
561
+ }
562
+ ```
563
+
564
+ **Q: 如何配置 MNS 队列发送结果?**
565
+
566
+ A: 在配置文件的 `runtime_env.env_vars` 中设置 MNS 相关环境变量:
567
+ ```json
568
+ {
569
+ "runtime_env": {
570
+ "env_vars": {
571
+ "MNS_ENDPOINT": "https://123456789.mns.cn-shanghai.aliyuncs.com",
572
+ "MNS_ACCESS_KEY_ID": "your-access-key-id",
573
+ "MNS_ACCESS_KEY_SECRET": "your-access-key-secret",
574
+ "MNS_QUEUE_NAME": "aiinfra-data-process-component-result-queue"
575
+ }
576
+ }
577
+ }
578
+ ```
579
+
580
+ 配置后,处理结果会自动发送到队列。如果未配置或发送失败,不会影响主流程。
581
+
582
+ **Q: 返回结果格式是什么?**
583
+
584
+ A: `handle_request` 方法会自动封装返回结果:
585
+ - 正常情况:`code=0, message="success", data.out_put=用户程序返回结果`
586
+ - 异常情况:`code=-1, message=错误消息, data.out_put=null`
587
+ - 所有结果都包含 `work_flow_id`、`work_flow_instance_id`、`task_id`
588
+
589
+ ## 许可证
590
+
591
+ MIT License
592
+
593
+ ## 作者
594
+
595
+ zhaohaidong (zhaohaidong389@hellobike.com)
596
+