# 任务退避重试、调度框架
[](https://www.python.org/)
[](LICENSE)
一个基于Redis的分布式任务退避重试、调度框架,支持多种退避策略和并发执行。
## ✨ 核心特性
- 🔄 **多种退避策略**: 固定间隔、指数退避、线性退避
- 🚀 **高并发执行**: 支持线程池/进程池并发处理
- 📊 **任务优先级**: 支持任务优先级管理
- ⏱️ **超时控制**: 任务执行超时和失败处理
- 📈 **状态监控**: 完整的任务状态管理和监控
- 🎯 **灵活调度**: 可配置的定时调度间隔
- 🔒 **分布式锁**: 基于Redis的分布式任务队列
- 💾 **存储方式**: 目前只支持 Redis,后续会增加MySQL、达梦数据库等支持
## 📚设计思路
### 业务架构设计

### 退避工具内部组件设计

### 设计类图

### 调用时序图
用户提交task

调度执行task

## 📦 安装
```bash
pip install maas-task-backoff-framework
```
## 🚀 快速开始
### 使用示例
```python
from backoff.scheduler.backoff_scheduler import (
TaskBackoffScheduler,
TaskBackoffConfig,
TaskEntity,
TaskConfig,
StorageConfig,
ThreadPoolConfig,
SchedulerConfig,
ResultEntity,
)
# 1. 创建配置
config = TaskBackoffConfig()
# Redis存储配置
config.storage = StorageConfig(
type="redis",
host="localhost",
port=6379,
database=0,
password=""
)
# 任务配置
config.task = TaskConfig(
biz_prefix="my_service",
batch_size=10,
max_retry_count=3,
backoff_strategy="exponential",
backoff_interval=30,
backoff_multiplier=2.0,
min_gpu_memory_gb=0.5,
min_gpu_utilization=10
)
# 线程池配置
config.threadpool = ThreadPoolConfig(
concurrency=5,
exec_timeout=300,
proc_mode="process"
)
# 调度器配置
config.scheduler = SchedulerConfig(interval=10)
# 2. 创建调度器
scheduler = TaskBackoffScheduler(config)
# 3. 定义任务处理器
def task_handler(task: TaskEntity):
# 您的业务逻辑
print(f"处理任务: {task.task_id}")
return ResultEntity.ok(
result={"status": "success", "data": "处理完成"},
task_id=task.task_id,
)
def exception_handler(task: TaskEntity):
# 异常处理逻辑
return ResultEntity.fail(
code=-1,
message="任务执行失败",
task_id=task.task_id,
)
# 4. 注册处理器
scheduler.set_custom_task_handler(task_handler)
scheduler.set_custom_task_exception_handler(exception_handler)
# 5. 启动调度器(如果不需要启动调度器,请忽略此步骤,只提供基础的Task API操作)
scheduler.start()
```
## 💻 Task任务数据结构
```python
{
"task_id": "task_5775520148",
"process": 0,
"status": "pending",
"result": "",
"param": "{\"index\": 111, \"data\": \"test_data\"}",
"retry_count": 0,
"next_execution_time": 0,
"create_time": 1756695076,
"update_time": 1756695076,
"max_retry_count": 5,
"backoff_strategy": "fixed",
"backoff_interval": 60,
"backoff_multiplier": 2.0,
"min_gpu_memory_gb": 0,
"min_gpu_utilization": 0.0,
"biz_prefix": "custom_scheduling_example"
}
```
结果字段说明
|字段 | 类型 | 说明 |
|----------|--------|----------------|
| task_id | string | 任务唯一id |
| biz_prefix | string | 任务的业务前缀 |
| process | int | 任务进度 |
| status | string | 任务状态 |
| result | string | 任务的执行结果 |
| param | string | 任务的参数 |
| retry_count | int | 重试次数 |
| next_execution_time | int | 下次执行时间 |
| create_time | int | 创建时间 |
| update_time | int | 更新时间 |
| max_retry_count | int | 最大重试次数 |
| backoff_strategy | string | 退避类型 |
| backoff_interval | int | 退避间隔 |
| backoff_multiplier | int | 退避倍数 |
| min_gpu_memory_gb | int | 需要的最小GPU内存 |
| min_gpu_utilization | int | 需要的最小GPU使用率 |
## 📚 API 参考
### 任务管理
#### 1.创建任务
创建任务可选权重值 `score` , 不传默认会以为当前时间为权重值先进先出;`score` 越小越先执行
```python
scheduler.create_task(
task_params={"key": "value"},
task_id="unique_task_id",
score=100
) -> Tuple[bool, message: str]
```
参数字段说明
| 字段 | 类型 | 必填 | 说明 |
|----------|--------|--------|----------------|
| task_params |是| dict | 任务的业务参数 |
| task_id | 是 |string | 自定义的任务id |
| score |否| int | 权重值(不传默认会以为当前时间为权重值先进先出;越小越先执行) |
#### 2.查询任务
```python
scheduler.get_task(task_id) -> TaskEntity
```
#### 3.撤销任务
- 线程模式下撤销任务仅会变更任务状态为 `canceled`,等待任务执行完成
- 进程模式下会直接取消正在运行中的任务并变更任务状态
```python
scheduler.cancel_task(task_id) -> Tuple[bool, str]:
```
#### 4.获取队列统计
```python
scheduler.get_queue_statistics() -> Dict[str, int]:
```
队列统计结构返回结果示例
```python
{
"system_status": {
"update_time": "2025-09-01 15:30:13"
},
"tasks": {
"pending": {
"total": 34,
"queue": [
"task_2728059290",
"task_2829088805"
]
},
"processing": {
"total": 0,
"queue": []
},
"completed": {
"total": 0,
"queue": []
},
"failed": {
"total": 0,
"queue": []
}
}
}
```
字段说明
| 字段 | 类型 | 说明 |
|----------|--------|----------------|
| update_time | string | 请求时间 |
| tasks | object | 任务队列统计 |
| pending | object | 等待队列 |
| processing | object | 处理中队列 |
| completed | object | 已完成队列 |
| failed | object | 失败队列 |
| total | int | 任务队列成员总数 |
| queue | list | 任务成员列表 |
### 5.更任务状态
```python
# 标记任务完成
scheduler.mark_task_completed(task_id, "执行结果") -> bool
# 标记任务失败
scheduler.mark_task_failed(task_id, "失败原因") -> bool
# 标记任务处理中
scheduler.mark_task_processing(task_id) -> bool
```
### 6.更新任务进度
```python
# 更新任务进度
scheduler.update_task_progress(task_id, 75) -> bool # 75%
```
### 7.调度器控制
如果不显示执行 `scheduler.start()` 则不会启动定时调度,只提供 Task API 的基础操作
```python
# 启动调度器
scheduler.start()
# 关闭调度器
scheduler.shutdown()
```
### 8.处理器管理
- 任务处理器 ( `set_custom_task_handler` ): 可选设置,处理正常的业务逻辑
- 异常处理器 ( `set_custom_task_exception_handler` ): 可选设置,处理任务执行过程中的异常情况
```python
# 注册任务处理器(可选)
scheduler.set_custom_task_handler(task_handler)
# 注册异常处理器(可选)
scheduler.set_custom_task_exception_handler(exception_handler)
```
**处理器函数签名**
处理器参数必须为 `TaskEntity` ,响应类型必须为 `ResultEntity`
```python
from backoff.scheduler.backoff_scheduler import (
TaskEntity,
ResultEntity,
)
def task_handler(task: TaskEntity) -> ResultEntity:
# 您的业务逻辑
pass
def exception_handler(task: TaskEntity) -> ResultEntity:
# 异常处理逻辑
pass
```
#### 返回值示例
**成功处理:**
```python
return ResultEntity.ok(
result={"status": "success", "data": "处理结果"},
task_id=task.task_id,
)
```
**失败处理:**
```python
return ResultEntity.fail(
code=-1,
message="任务执行失败",
result={"error": "具体错误信息"},
task_id=task.task_id,
)
```
## ⚙️ 配置详解
### StorageConfig (存储配置)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|----------|--------|------|-----------|----------------|
| type | string | 是 | redis | 存储类型,目前仅支持Redis |
| host | string | 是 | localhost| Redis主机地址 |
| port | int | 是 | 6379 | Redis端口 |
| database | int | 否 | 0 | Redis数据库 |
| password | string | 否 | "" | Redis密码 |
**type 存储类型:**
- `redis` : 默认
- `mysql` : 暂未支持
- `达梦` : 暂未支持
### TaskConfig (任务配置)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---------------------|--------|------|---------------|-------------------------|
| biz_prefix | string | **是** | - | 业务唯一标识 |
| max_retry_count | int | 否 | 3 | 最大重试次数 |
| backoff_strategy | string | 否 | exponential | 退避策略 |
| backoff_interval | int | 否 | 30 | 初始退避间隔(秒) |
| backoff_multiplier | float | 否 | 2.0 | 退避倍数 |
| batch_size | int | 否 | 100 | 批次大小 |
| min_gpu_memory_gb | float | 否 | 0 | 最小GPU内存(GB) |
| min_gpu_utilization | int | 否 | 0 | 最小GPU利用率(%) |
**backoff_strategy 退避策略说明:**
- `exponential` : 指数退避 (默认)
- `fixed` : 固定间隔重试
- `linear` : 线性退避
### ThreadPoolConfig (线程池配置)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---------------|--------|------|--------|-------------------------|
| concurrency | int | 否 | 10 | 并发线程/进程数 |
| proc_mode | string | 否 | process | 执行模式 |
| exec_timeout | int | 否 | 300 | 任务超时时间(秒) |
**proc_mode 执行模式说明:**
- `thread` : 线程池模式
- `process` : 进程池模式 (默认)
线程池模式,一旦线程启动后,线程将会持续运行,直到执行完毕,线程将被回收。
进程池模式,如果进程内业务异常或者超时等待,进程将被收回。
### SchedulerConfig (调度器配置)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|----------|------|------|--------|----------------|
| interval | int | 否 | 10 | 轮询间隔(秒) |
Raw data
{
"_id": null,
"home_page": "https://github.com/xiaofucoding/maas-task-backoff-framework.git/",
"name": "maas-task-backoff-framework",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "task retry backoff redis queue",
"author": "xinzf",
"author_email": "515361725@qq.com",
"download_url": "https://files.pythonhosted.org/packages/10/bb/a7fd7419691dac1b3da57ed13f4d9a1c1619f818e0824ee0821428e55d0a/maas-task-backoff-framework-1.0.3.tar.gz",
"platform": null,
"description": "# \u4efb\u52a1\u9000\u907f\u91cd\u8bd5\u3001\u8c03\u5ea6\u6846\u67b6\n\n[](https://www.python.org/)\n[](LICENSE)\n\n\u4e00\u4e2a\u57fa\u4e8eRedis\u7684\u5206\u5e03\u5f0f\u4efb\u52a1\u9000\u907f\u91cd\u8bd5\u3001\u8c03\u5ea6\u6846\u67b6\uff0c\u652f\u6301\u591a\u79cd\u9000\u907f\u7b56\u7565\u548c\u5e76\u53d1\u6267\u884c\u3002\n\n## \u2728 \u6838\u5fc3\u7279\u6027\n\n- \ud83d\udd04 **\u591a\u79cd\u9000\u907f\u7b56\u7565**: \u56fa\u5b9a\u95f4\u9694\u3001\u6307\u6570\u9000\u907f\u3001\u7ebf\u6027\u9000\u907f\n- \ud83d\ude80 **\u9ad8\u5e76\u53d1\u6267\u884c**: \u652f\u6301\u7ebf\u7a0b\u6c60/\u8fdb\u7a0b\u6c60\u5e76\u53d1\u5904\u7406\n- \ud83d\udcca **\u4efb\u52a1\u4f18\u5148\u7ea7**: \u652f\u6301\u4efb\u52a1\u4f18\u5148\u7ea7\u7ba1\u7406\n- \u23f1\ufe0f **\u8d85\u65f6\u63a7\u5236**: \u4efb\u52a1\u6267\u884c\u8d85\u65f6\u548c\u5931\u8d25\u5904\u7406\n- \ud83d\udcc8 **\u72b6\u6001\u76d1\u63a7**: \u5b8c\u6574\u7684\u4efb\u52a1\u72b6\u6001\u7ba1\u7406\u548c\u76d1\u63a7\n- \ud83c\udfaf **\u7075\u6d3b\u8c03\u5ea6**: \u53ef\u914d\u7f6e\u7684\u5b9a\u65f6\u8c03\u5ea6\u95f4\u9694\n- \ud83d\udd12 **\u5206\u5e03\u5f0f\u9501**: \u57fa\u4e8eRedis\u7684\u5206\u5e03\u5f0f\u4efb\u52a1\u961f\u5217\n- \ud83d\udcbe **\u5b58\u50a8\u65b9\u5f0f**: \u76ee\u524d\u53ea\u652f\u6301 Redis\uff0c\u540e\u7eed\u4f1a\u589e\u52a0MySQL\u3001\u8fbe\u68a6\u6570\u636e\u5e93\u7b49\u652f\u6301\n\n## \ud83d\udcda\u8bbe\u8ba1\u601d\u8def\n\n\n### \u4e1a\u52a1\u67b6\u6784\u8bbe\u8ba1\n\n\n\n### \u9000\u907f\u5de5\u5177\u5185\u90e8\u7ec4\u4ef6\u8bbe\u8ba1\n\n\n\n\n### \u8bbe\u8ba1\u7c7b\u56fe\n\n\n\n### \u8c03\u7528\u65f6\u5e8f\u56fe\n\n\u7528\u6237\u63d0\u4ea4task\n\n\n\n\u8c03\u5ea6\u6267\u884ctask\n\n\n\n## \ud83d\udce6 \u5b89\u88c5\n\n```bash\npip install maas-task-backoff-framework\n```\n\n## \ud83d\ude80 \u5feb\u901f\u5f00\u59cb\n\n### \u4f7f\u7528\u793a\u4f8b\n\n```python\nfrom backoff.scheduler.backoff_scheduler import (\n TaskBackoffScheduler,\n TaskBackoffConfig,\n TaskEntity,\n TaskConfig,\n StorageConfig,\n ThreadPoolConfig,\n SchedulerConfig,\n ResultEntity,\n)\n\n# 1. \u521b\u5efa\u914d\u7f6e\nconfig = TaskBackoffConfig()\n\n# Redis\u5b58\u50a8\u914d\u7f6e\nconfig.storage = StorageConfig(\n type=\"redis\", \n host=\"localhost\", \n port=6379, \n database=0, \n password=\"\"\n)\n\n# \u4efb\u52a1\u914d\u7f6e\nconfig.task = TaskConfig(\n biz_prefix=\"my_service\",\n batch_size=10,\n max_retry_count=3,\n backoff_strategy=\"exponential\",\n backoff_interval=30,\n backoff_multiplier=2.0,\n min_gpu_memory_gb=0.5,\n min_gpu_utilization=10\n)\n\n# \u7ebf\u7a0b\u6c60\u914d\u7f6e\nconfig.threadpool = ThreadPoolConfig(\n concurrency=5, \n exec_timeout=300, \n proc_mode=\"process\"\n)\n\n# \u8c03\u5ea6\u5668\u914d\u7f6e\nconfig.scheduler = SchedulerConfig(interval=10)\n\n# 2. \u521b\u5efa\u8c03\u5ea6\u5668\nscheduler = TaskBackoffScheduler(config)\n\n# 3. \u5b9a\u4e49\u4efb\u52a1\u5904\u7406\u5668\ndef task_handler(task: TaskEntity):\n # \u60a8\u7684\u4e1a\u52a1\u903b\u8f91\n print(f\"\u5904\u7406\u4efb\u52a1: {task.task_id}\")\n return ResultEntity.ok(\n result={\"status\": \"success\", \"data\": \"\u5904\u7406\u5b8c\u6210\"},\n task_id=task.task_id,\n )\n\ndef exception_handler(task: TaskEntity):\n # \u5f02\u5e38\u5904\u7406\u903b\u8f91\n return ResultEntity.fail(\n code=-1,\n message=\"\u4efb\u52a1\u6267\u884c\u5931\u8d25\",\n task_id=task.task_id,\n )\n\n# 4. \u6ce8\u518c\u5904\u7406\u5668\nscheduler.set_custom_task_handler(task_handler)\n\nscheduler.set_custom_task_exception_handler(exception_handler)\n\n# 5. \u542f\u52a8\u8c03\u5ea6\u5668\uff08\u5982\u679c\u4e0d\u9700\u8981\u542f\u52a8\u8c03\u5ea6\u5668\uff0c\u8bf7\u5ffd\u7565\u6b64\u6b65\u9aa4\uff0c\u53ea\u63d0\u4f9b\u57fa\u7840\u7684Task API\u64cd\u4f5c\uff09\nscheduler.start()\n```\n\n## \ud83d\udcbb Task\u4efb\u52a1\u6570\u636e\u7ed3\u6784\n\n```python\n{\n \"task_id\": \"task_5775520148\",\n \"process\": 0,\n \"status\": \"pending\",\n \"result\": \"\",\n \"param\": \"{\\\"index\\\": 111, \\\"data\\\": \\\"test_data\\\"}\",\n \"retry_count\": 0,\n \"next_execution_time\": 0,\n \"create_time\": 1756695076,\n \"update_time\": 1756695076,\n \"max_retry_count\": 5,\n \"backoff_strategy\": \"fixed\",\n \"backoff_interval\": 60,\n \"backoff_multiplier\": 2.0,\n \"min_gpu_memory_gb\": 0,\n \"min_gpu_utilization\": 0.0,\n \"biz_prefix\": \"custom_scheduling_example\"\n}\n```\n\n\u7ed3\u679c\u5b57\u6bb5\u8bf4\u660e\n\n|\u5b57\u6bb5 | \u7c7b\u578b | \u8bf4\u660e |\n|----------|--------|----------------|\n| task_id | string | \u4efb\u52a1\u552f\u4e00id |\n| biz_prefix | string | \u4efb\u52a1\u7684\u4e1a\u52a1\u524d\u7f00 |\n| process | int | \u4efb\u52a1\u8fdb\u5ea6 |\n| status | string | \u4efb\u52a1\u72b6\u6001 |\n| result | string | \u4efb\u52a1\u7684\u6267\u884c\u7ed3\u679c |\n| param | string | \u4efb\u52a1\u7684\u53c2\u6570 |\n| retry_count | int | \u91cd\u8bd5\u6b21\u6570 |\n| next_execution_time | int | \u4e0b\u6b21\u6267\u884c\u65f6\u95f4 |\n| create_time | int | \u521b\u5efa\u65f6\u95f4 |\n| update_time | int | \u66f4\u65b0\u65f6\u95f4 |\n| max_retry_count | int | \u6700\u5927\u91cd\u8bd5\u6b21\u6570 |\n| backoff_strategy | string | \u9000\u907f\u7c7b\u578b |\n| backoff_interval | int | \u9000\u907f\u95f4\u9694 |\n| backoff_multiplier | int | \u9000\u907f\u500d\u6570 |\n| min_gpu_memory_gb | int | \u9700\u8981\u7684\u6700\u5c0fGPU\u5185\u5b58 |\n| min_gpu_utilization | int | \u9700\u8981\u7684\u6700\u5c0fGPU\u4f7f\u7528\u7387 |\n\n\n## \ud83d\udcda API \u53c2\u8003\n\n### \u4efb\u52a1\u7ba1\u7406\n\n#### 1.\u521b\u5efa\u4efb\u52a1\n\n\u521b\u5efa\u4efb\u52a1\u53ef\u9009\u6743\u91cd\u503c `score` , \u4e0d\u4f20\u9ed8\u8ba4\u4f1a\u4ee5\u4e3a\u5f53\u524d\u65f6\u95f4\u4e3a\u6743\u91cd\u503c\u5148\u8fdb\u5148\u51fa\uff1b`score` \u8d8a\u5c0f\u8d8a\u5148\u6267\u884c\n\n```python\nscheduler.create_task(\n task_params={\"key\": \"value\"},\n task_id=\"unique_task_id\",\n score=100\n) -> Tuple[bool, message: str]\n```\n\n\u53c2\u6570\u5b57\u6bb5\u8bf4\u660e\n| \u5b57\u6bb5 | \u7c7b\u578b | \u5fc5\u586b | \u8bf4\u660e |\n|----------|--------|--------|----------------|\n| task_params |\u662f| dict | \u4efb\u52a1\u7684\u4e1a\u52a1\u53c2\u6570 |\n| task_id | \u662f |string | \u81ea\u5b9a\u4e49\u7684\u4efb\u52a1id |\n| score |\u5426| int | \u6743\u91cd\u503c\uff08\u4e0d\u4f20\u9ed8\u8ba4\u4f1a\u4ee5\u4e3a\u5f53\u524d\u65f6\u95f4\u4e3a\u6743\u91cd\u503c\u5148\u8fdb\u5148\u51fa\uff1b\u8d8a\u5c0f\u8d8a\u5148\u6267\u884c\uff09 |\n\n\n#### 2.\u67e5\u8be2\u4efb\u52a1\n\n```python\nscheduler.get_task(task_id) -> TaskEntity\n```\n\n#### 3.\u64a4\u9500\u4efb\u52a1\n\n- \u7ebf\u7a0b\u6a21\u5f0f\u4e0b\u64a4\u9500\u4efb\u52a1\u4ec5\u4f1a\u53d8\u66f4\u4efb\u52a1\u72b6\u6001\u4e3a `canceled`\uff0c\u7b49\u5f85\u4efb\u52a1\u6267\u884c\u5b8c\u6210\n\n- \u8fdb\u7a0b\u6a21\u5f0f\u4e0b\u4f1a\u76f4\u63a5\u53d6\u6d88\u6b63\u5728\u8fd0\u884c\u4e2d\u7684\u4efb\u52a1\u5e76\u53d8\u66f4\u4efb\u52a1\u72b6\u6001\n\n```python\nscheduler.cancel_task(task_id) -> Tuple[bool, str]:\n```\n\n#### 4.\u83b7\u53d6\u961f\u5217\u7edf\u8ba1\n\n```python\nscheduler.get_queue_statistics() -> Dict[str, int]:\n```\n\n\u961f\u5217\u7edf\u8ba1\u7ed3\u6784\u8fd4\u56de\u7ed3\u679c\u793a\u4f8b\n\n```python\n{\n \"system_status\": {\n \"update_time\": \"2025-09-01 15:30:13\"\n },\n \"tasks\": {\n \"pending\": {\n \"total\": 34,\n \"queue\": [\n \"task_2728059290\",\n \"task_2829088805\"\n ]\n },\n \"processing\": {\n \"total\": 0,\n \"queue\": []\n },\n \"completed\": {\n \"total\": 0,\n \"queue\": []\n },\n \"failed\": {\n \"total\": 0,\n \"queue\": []\n }\n }\n}\n```\n\n\u5b57\u6bb5\u8bf4\u660e\n| \u5b57\u6bb5 | \u7c7b\u578b | \u8bf4\u660e |\n|----------|--------|----------------|\n| update_time | string | \u8bf7\u6c42\u65f6\u95f4 |\n| tasks | object | \u4efb\u52a1\u961f\u5217\u7edf\u8ba1 |\n| pending | object | \u7b49\u5f85\u961f\u5217 |\n| processing | object | \u5904\u7406\u4e2d\u961f\u5217 |\n| completed | object | \u5df2\u5b8c\u6210\u961f\u5217 |\n| failed | object | \u5931\u8d25\u961f\u5217 |\n| total | int | \u4efb\u52a1\u961f\u5217\u6210\u5458\u603b\u6570 | \n| queue | list | \u4efb\u52a1\u6210\u5458\u5217\u8868 |\n\n\n### 5.\u66f4\u4efb\u52a1\u72b6\u6001\n\n```python\n# \u6807\u8bb0\u4efb\u52a1\u5b8c\u6210\nscheduler.mark_task_completed(task_id, \"\u6267\u884c\u7ed3\u679c\") -> bool\n\n# \u6807\u8bb0\u4efb\u52a1\u5931\u8d25\nscheduler.mark_task_failed(task_id, \"\u5931\u8d25\u539f\u56e0\") -> bool\n\n# \u6807\u8bb0\u4efb\u52a1\u5904\u7406\u4e2d\nscheduler.mark_task_processing(task_id) -> bool\n```\n\n### 6.\u66f4\u65b0\u4efb\u52a1\u8fdb\u5ea6\n\n```python\n# \u66f4\u65b0\u4efb\u52a1\u8fdb\u5ea6\nscheduler.update_task_progress(task_id, 75) -> bool # 75%\n```\n\n### 7.\u8c03\u5ea6\u5668\u63a7\u5236\n\n\u5982\u679c\u4e0d\u663e\u793a\u6267\u884c `scheduler.start()` \u5219\u4e0d\u4f1a\u542f\u52a8\u5b9a\u65f6\u8c03\u5ea6\uff0c\u53ea\u63d0\u4f9b Task API \u7684\u57fa\u7840\u64cd\u4f5c\n\n```python\n# \u542f\u52a8\u8c03\u5ea6\u5668\nscheduler.start()\n\n# \u5173\u95ed\u8c03\u5ea6\u5668\nscheduler.shutdown()\n```\n\n### 8.\u5904\u7406\u5668\u7ba1\u7406\n\n- \u4efb\u52a1\u5904\u7406\u5668 ( `set_custom_task_handler` ): \u53ef\u9009\u8bbe\u7f6e\uff0c\u5904\u7406\u6b63\u5e38\u7684\u4e1a\u52a1\u903b\u8f91\n\n- \u5f02\u5e38\u5904\u7406\u5668 ( `set_custom_task_exception_handler` ): \u53ef\u9009\u8bbe\u7f6e\uff0c\u5904\u7406\u4efb\u52a1\u6267\u884c\u8fc7\u7a0b\u4e2d\u7684\u5f02\u5e38\u60c5\u51b5\n\n```python\n# \u6ce8\u518c\u4efb\u52a1\u5904\u7406\u5668\uff08\u53ef\u9009\uff09\nscheduler.set_custom_task_handler(task_handler)\n\n# \u6ce8\u518c\u5f02\u5e38\u5904\u7406\u5668\uff08\u53ef\u9009\uff09\nscheduler.set_custom_task_exception_handler(exception_handler)\n```\n\n**\u5904\u7406\u5668\u51fd\u6570\u7b7e\u540d**\n\n\u5904\u7406\u5668\u53c2\u6570\u5fc5\u987b\u4e3a `TaskEntity` \uff0c\u54cd\u5e94\u7c7b\u578b\u5fc5\u987b\u4e3a `ResultEntity`\n\n```python\nfrom backoff.scheduler.backoff_scheduler import (\n TaskEntity,\n ResultEntity,\n)\ndef task_handler(task: TaskEntity) -> ResultEntity:\n # \u60a8\u7684\u4e1a\u52a1\u903b\u8f91\n pass\n\ndef exception_handler(task: TaskEntity) -> ResultEntity:\n # \u5f02\u5e38\u5904\u7406\u903b\u8f91\n pass\n```\n\n#### \u8fd4\u56de\u503c\u793a\u4f8b\n\n**\u6210\u529f\u5904\u7406:**\n\n```python\nreturn ResultEntity.ok(\n result={\"status\": \"success\", \"data\": \"\u5904\u7406\u7ed3\u679c\"},\n task_id=task.task_id,\n)\n```\n\n**\u5931\u8d25\u5904\u7406:**\n```python\nreturn ResultEntity.fail(\n code=-1,\n message=\"\u4efb\u52a1\u6267\u884c\u5931\u8d25\",\n result={\"error\": \"\u5177\u4f53\u9519\u8bef\u4fe1\u606f\"},\n task_id=task.task_id,\n)\n```\n\n\n## \u2699\ufe0f \u914d\u7f6e\u8be6\u89e3\n\n### StorageConfig (\u5b58\u50a8\u914d\u7f6e)\n\n| \u53c2\u6570 | \u7c7b\u578b | \u5fc5\u586b | \u9ed8\u8ba4\u503c | \u8bf4\u660e |\n|----------|--------|------|-----------|----------------|\n| type | string | \u662f | redis | \u5b58\u50a8\u7c7b\u578b\uff0c\u76ee\u524d\u4ec5\u652f\u6301Redis |\n| host | string | \u662f | localhost| Redis\u4e3b\u673a\u5730\u5740 |\n| port | int | \u662f | 6379 | Redis\u7aef\u53e3 |\n| database | int | \u5426 | 0 | Redis\u6570\u636e\u5e93 |\n| password | string | \u5426 | \"\" | Redis\u5bc6\u7801 |\n\n**type \u5b58\u50a8\u7c7b\u578b:**\n\n- `redis` : \u9ed8\u8ba4\n- `mysql` : \u6682\u672a\u652f\u6301\n- `\u8fbe\u68a6` : \u6682\u672a\u652f\u6301\n\n### TaskConfig (\u4efb\u52a1\u914d\u7f6e)\n\n| \u53c2\u6570 | \u7c7b\u578b | \u5fc5\u586b | \u9ed8\u8ba4\u503c | \u8bf4\u660e |\n|---------------------|--------|------|---------------|-------------------------|\n| biz_prefix | string | **\u662f** | - | \u4e1a\u52a1\u552f\u4e00\u6807\u8bc6 |\n| max_retry_count | int | \u5426 | 3 | \u6700\u5927\u91cd\u8bd5\u6b21\u6570 |\n| backoff_strategy | string | \u5426 | exponential | \u9000\u907f\u7b56\u7565 |\n| backoff_interval | int | \u5426 | 30 | \u521d\u59cb\u9000\u907f\u95f4\u9694(\u79d2) |\n| backoff_multiplier | float | \u5426 | 2.0 | \u9000\u907f\u500d\u6570 |\n| batch_size | int | \u5426 | 100 | \u6279\u6b21\u5927\u5c0f |\n| min_gpu_memory_gb | float | \u5426 | 0 | \u6700\u5c0fGPU\u5185\u5b58(GB) |\n| min_gpu_utilization | int | \u5426 | 0 | \u6700\u5c0fGPU\u5229\u7528\u7387(%) |\n\n**backoff_strategy \u9000\u907f\u7b56\u7565\u8bf4\u660e:**\n\n- `exponential` : \u6307\u6570\u9000\u907f (\u9ed8\u8ba4)\n- `fixed` : \u56fa\u5b9a\u95f4\u9694\u91cd\u8bd5\n- `linear` : \u7ebf\u6027\u9000\u907f\n\n### ThreadPoolConfig (\u7ebf\u7a0b\u6c60\u914d\u7f6e)\n\n| \u53c2\u6570 | \u7c7b\u578b | \u5fc5\u586b | \u9ed8\u8ba4\u503c | \u8bf4\u660e |\n|---------------|--------|------|--------|-------------------------|\n| concurrency | int | \u5426 | 10 | \u5e76\u53d1\u7ebf\u7a0b/\u8fdb\u7a0b\u6570 |\n| proc_mode | string | \u5426 | process | \u6267\u884c\u6a21\u5f0f |\n| exec_timeout | int | \u5426 | 300 | \u4efb\u52a1\u8d85\u65f6\u65f6\u95f4(\u79d2) |\n\n**proc_mode \u6267\u884c\u6a21\u5f0f\u8bf4\u660e:**\n\n- `thread` : \u7ebf\u7a0b\u6c60\u6a21\u5f0f\n- `process` : \u8fdb\u7a0b\u6c60\u6a21\u5f0f (\u9ed8\u8ba4)\n\n\u7ebf\u7a0b\u6c60\u6a21\u5f0f\uff0c\u4e00\u65e6\u7ebf\u7a0b\u542f\u52a8\u540e\uff0c\u7ebf\u7a0b\u5c06\u4f1a\u6301\u7eed\u8fd0\u884c\uff0c\u76f4\u5230\u6267\u884c\u5b8c\u6bd5\uff0c\u7ebf\u7a0b\u5c06\u88ab\u56de\u6536\u3002\n\n\u8fdb\u7a0b\u6c60\u6a21\u5f0f\uff0c\u5982\u679c\u8fdb\u7a0b\u5185\u4e1a\u52a1\u5f02\u5e38\u6216\u8005\u8d85\u65f6\u7b49\u5f85\uff0c\u8fdb\u7a0b\u5c06\u88ab\u6536\u56de\u3002\n\n### SchedulerConfig (\u8c03\u5ea6\u5668\u914d\u7f6e)\n\n| \u53c2\u6570 | \u7c7b\u578b | \u5fc5\u586b | \u9ed8\u8ba4\u503c | \u8bf4\u660e |\n|----------|------|------|--------|----------------|\n| interval | int | \u5426 | 10 | \u8f6e\u8be2\u95f4\u9694(\u79d2) |\n\n\n\n\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "\u57fa\u4e8eRedis\u7684\u4efb\u52a1\u9000\u907f\u91cd\u8bd5\u3001\u8c03\u5ea6\u6846\u67b6\uff0c\u652f\u6301\u591a\u79cd\u9000\u907f\u7b56\u7565",
"version": "1.0.3",
"project_urls": {
"Bug Reports": "https://github.com/yourusername/task-backoff-scheduler/issues",
"Documentation": "https://github.com/yourusername/task-backoff-scheduler#readme",
"Homepage": "https://github.com/xiaofucoding/maas-task-backoff-framework.git/",
"Source": "https://github.com/yourusername/task-backoff-scheduler"
},
"split_keywords": [
"task",
"retry",
"backoff",
"redis",
"queue"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "8b45c81c7b01d414d7916b3f9e5767121befdb35f5c2315f2f3f84b582cb930d",
"md5": "8dada3b3716613c55bb87b3ba1faa141",
"sha256": "ab65065f55f1273bbb72bdedd3cb493b0e90daeacd3e0d96dcb0909c22fab84c"
},
"downloads": -1,
"filename": "maas_task_backoff_framework-1.0.3-py2-none-any.whl",
"has_sig": false,
"md5_digest": "8dada3b3716613c55bb87b3ba1faa141",
"packagetype": "bdist_wheel",
"python_version": "py2",
"requires_python": ">=3.7",
"size": 41212,
"upload_time": "2025-09-09T03:37:58",
"upload_time_iso_8601": "2025-09-09T03:37:58.207665Z",
"url": "https://files.pythonhosted.org/packages/8b/45/c81c7b01d414d7916b3f9e5767121befdb35f5c2315f2f3f84b582cb930d/maas_task_backoff_framework-1.0.3-py2-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "10bba7fd7419691dac1b3da57ed13f4d9a1c1619f818e0824ee0821428e55d0a",
"md5": "2f3b705322608bfdfaba9e7ff0510d4d",
"sha256": "34edb6b6450638a1eae7eff7b0d8f557833aed5c639ca2b12ae92173608c2f9d"
},
"downloads": -1,
"filename": "maas-task-backoff-framework-1.0.3.tar.gz",
"has_sig": false,
"md5_digest": "2f3b705322608bfdfaba9e7ff0510d4d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 29159,
"upload_time": "2025-09-09T03:37:59",
"upload_time_iso_8601": "2025-09-09T03:37:59.771719Z",
"url": "https://files.pythonhosted.org/packages/10/bb/a7fd7419691dac1b3da57ed13f4d9a1c1619f818e0824ee0821428e55d0a/maas-task-backoff-framework-1.0.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-09 03:37:59",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "xiaofucoding",
"github_project": "maas-task-backoff-framework",
"github_not_found": true,
"lcname": "maas-task-backoff-framework"
}