fastapi-process-restarter 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.
- fastapi_process_restarter-0.1.0/PKG-INFO +105 -0
- fastapi_process_restarter-0.1.0/README.md +92 -0
- fastapi_process_restarter-0.1.0/fastapi_process_restarter.egg-info/PKG-INFO +105 -0
- fastapi_process_restarter-0.1.0/fastapi_process_restarter.egg-info/SOURCES.txt +12 -0
- fastapi_process_restarter-0.1.0/fastapi_process_restarter.egg-info/dependency_links.txt +1 -0
- fastapi_process_restarter-0.1.0/fastapi_process_restarter.egg-info/entry_points.txt +2 -0
- fastapi_process_restarter-0.1.0/fastapi_process_restarter.egg-info/requires.txt +2 -0
- fastapi_process_restarter-0.1.0/fastapi_process_restarter.egg-info/top_level.txt +1 -0
- fastapi_process_restarter-0.1.0/process_restarter/__init__.py +4 -0
- fastapi_process_restarter-0.1.0/process_restarter/api.py +29 -0
- fastapi_process_restarter-0.1.0/process_restarter/cli.py +27 -0
- fastapi_process_restarter-0.1.0/process_restarter/manager.py +62 -0
- fastapi_process_restarter-0.1.0/pyproject.toml +25 -0
- fastapi_process_restarter-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastapi-process-restarter
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A FastAPI based wrapper to auto-run and API-restart any terminal command.
|
|
5
|
+
Author-email: Developer <dev@example.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.7
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: fastapi>=0.90.0
|
|
12
|
+
Requires-Dist: uvicorn>=0.20.0
|
|
13
|
+
|
|
14
|
+
# FastAPI Process Restarter
|
|
15
|
+
|
|
16
|
+
一个基于 FastAPI 的通用进程管理和重启工具,支持跨平台(Linux/macOS/Windows)。
|
|
17
|
+
|
|
18
|
+
## 功能特性
|
|
19
|
+
|
|
20
|
+
- 🚀 **一键重启**: 通过 HTTP API 重启任何命令/脚本
|
|
21
|
+
- 🖥️ **跨平台支持**: 原生兼容 Linux、macOS 和 Windows
|
|
22
|
+
- 📊 **状态监控**: 实时查看进程运行状态和 PID
|
|
23
|
+
- 🧩 **易于集成**: 可作为子应用挂载到现有 FastAPI 项目
|
|
24
|
+
- 🔧 **CLI 工具**: 提供命令行工具,开箱即用
|
|
25
|
+
|
|
26
|
+
## 安装
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install fastapi-process-restarter
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 使用方法
|
|
33
|
+
|
|
34
|
+
### 方式一:命令行工具 (CLI)
|
|
35
|
+
|
|
36
|
+
安装后,直接在终端使用 `restarter` 命令:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# 基本用法
|
|
40
|
+
restarter --cmd "python main.py"
|
|
41
|
+
|
|
42
|
+
# 指定端口
|
|
43
|
+
restarter --cmd "python main.py" --port 9000
|
|
44
|
+
|
|
45
|
+
# 指定监听地址
|
|
46
|
+
restarter --cmd "node server.js" --host 127.0.0.1 --port 8080
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
API 端点:
|
|
50
|
+
- `POST /restart` - 重启进程
|
|
51
|
+
- `GET /status` - 获取进程状态
|
|
52
|
+
|
|
53
|
+
示例:
|
|
54
|
+
```bash
|
|
55
|
+
# 重启进程
|
|
56
|
+
curl -X POST http://localhost:8080/restart
|
|
57
|
+
|
|
58
|
+
# 查看状态
|
|
59
|
+
curl http://localhost:8080/status
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 方式二:Python API 集成
|
|
63
|
+
|
|
64
|
+
在现有 FastAPI 项目中作为子应用挂载:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from fastapi import FastAPI
|
|
68
|
+
from process_restarter import create_app
|
|
69
|
+
|
|
70
|
+
# 你的主应用
|
|
71
|
+
main_app = FastAPI()
|
|
72
|
+
|
|
73
|
+
@main_app.get("/")
|
|
74
|
+
def home():
|
|
75
|
+
return {"message": "Hello World"}
|
|
76
|
+
|
|
77
|
+
# 挂载进程重启器
|
|
78
|
+
cmd_app = create_app(cmd="node server.js")
|
|
79
|
+
main_app.mount("/subsystem", cmd_app)
|
|
80
|
+
|
|
81
|
+
# 现在可以通过 POST /subsystem/restart 重启 node server.js
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
也可以直接使用 `ProcessManager`:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from process_restarter import ProcessManager
|
|
88
|
+
|
|
89
|
+
manager = ProcessManager(cmd="python worker.py")
|
|
90
|
+
manager.start() # 启动进程
|
|
91
|
+
manager.restart() # 重启进程
|
|
92
|
+
manager.stop() # 停止进程
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 技术细节
|
|
96
|
+
|
|
97
|
+
- **跨平台进程管理**:
|
|
98
|
+
- Linux/macOS: 使用 `os.setsid` 创建进程组
|
|
99
|
+
- Windows: 使用 `CREATE_NEW_PROCESS_GROUP` 创建进程组
|
|
100
|
+
- **生命周期管理**: 使用 FastAPI `@asynccontextmanager` 确保程序退出时子进程被清理
|
|
101
|
+
- **日志桥接**: 子进程输出实时转发到主进程 stdout
|
|
102
|
+
|
|
103
|
+
## 许可证
|
|
104
|
+
|
|
105
|
+
MIT License
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# FastAPI Process Restarter
|
|
2
|
+
|
|
3
|
+
一个基于 FastAPI 的通用进程管理和重启工具,支持跨平台(Linux/macOS/Windows)。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- 🚀 **一键重启**: 通过 HTTP API 重启任何命令/脚本
|
|
8
|
+
- 🖥️ **跨平台支持**: 原生兼容 Linux、macOS 和 Windows
|
|
9
|
+
- 📊 **状态监控**: 实时查看进程运行状态和 PID
|
|
10
|
+
- 🧩 **易于集成**: 可作为子应用挂载到现有 FastAPI 项目
|
|
11
|
+
- 🔧 **CLI 工具**: 提供命令行工具,开箱即用
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install fastapi-process-restarter
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 使用方法
|
|
20
|
+
|
|
21
|
+
### 方式一:命令行工具 (CLI)
|
|
22
|
+
|
|
23
|
+
安装后,直接在终端使用 `restarter` 命令:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# 基本用法
|
|
27
|
+
restarter --cmd "python main.py"
|
|
28
|
+
|
|
29
|
+
# 指定端口
|
|
30
|
+
restarter --cmd "python main.py" --port 9000
|
|
31
|
+
|
|
32
|
+
# 指定监听地址
|
|
33
|
+
restarter --cmd "node server.js" --host 127.0.0.1 --port 8080
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
API 端点:
|
|
37
|
+
- `POST /restart` - 重启进程
|
|
38
|
+
- `GET /status` - 获取进程状态
|
|
39
|
+
|
|
40
|
+
示例:
|
|
41
|
+
```bash
|
|
42
|
+
# 重启进程
|
|
43
|
+
curl -X POST http://localhost:8080/restart
|
|
44
|
+
|
|
45
|
+
# 查看状态
|
|
46
|
+
curl http://localhost:8080/status
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 方式二:Python API 集成
|
|
50
|
+
|
|
51
|
+
在现有 FastAPI 项目中作为子应用挂载:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from fastapi import FastAPI
|
|
55
|
+
from process_restarter import create_app
|
|
56
|
+
|
|
57
|
+
# 你的主应用
|
|
58
|
+
main_app = FastAPI()
|
|
59
|
+
|
|
60
|
+
@main_app.get("/")
|
|
61
|
+
def home():
|
|
62
|
+
return {"message": "Hello World"}
|
|
63
|
+
|
|
64
|
+
# 挂载进程重启器
|
|
65
|
+
cmd_app = create_app(cmd="node server.js")
|
|
66
|
+
main_app.mount("/subsystem", cmd_app)
|
|
67
|
+
|
|
68
|
+
# 现在可以通过 POST /subsystem/restart 重启 node server.js
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
也可以直接使用 `ProcessManager`:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from process_restarter import ProcessManager
|
|
75
|
+
|
|
76
|
+
manager = ProcessManager(cmd="python worker.py")
|
|
77
|
+
manager.start() # 启动进程
|
|
78
|
+
manager.restart() # 重启进程
|
|
79
|
+
manager.stop() # 停止进程
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 技术细节
|
|
83
|
+
|
|
84
|
+
- **跨平台进程管理**:
|
|
85
|
+
- Linux/macOS: 使用 `os.setsid` 创建进程组
|
|
86
|
+
- Windows: 使用 `CREATE_NEW_PROCESS_GROUP` 创建进程组
|
|
87
|
+
- **生命周期管理**: 使用 FastAPI `@asynccontextmanager` 确保程序退出时子进程被清理
|
|
88
|
+
- **日志桥接**: 子进程输出实时转发到主进程 stdout
|
|
89
|
+
|
|
90
|
+
## 许可证
|
|
91
|
+
|
|
92
|
+
MIT License
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastapi-process-restarter
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A FastAPI based wrapper to auto-run and API-restart any terminal command.
|
|
5
|
+
Author-email: Developer <dev@example.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.7
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: fastapi>=0.90.0
|
|
12
|
+
Requires-Dist: uvicorn>=0.20.0
|
|
13
|
+
|
|
14
|
+
# FastAPI Process Restarter
|
|
15
|
+
|
|
16
|
+
一个基于 FastAPI 的通用进程管理和重启工具,支持跨平台(Linux/macOS/Windows)。
|
|
17
|
+
|
|
18
|
+
## 功能特性
|
|
19
|
+
|
|
20
|
+
- 🚀 **一键重启**: 通过 HTTP API 重启任何命令/脚本
|
|
21
|
+
- 🖥️ **跨平台支持**: 原生兼容 Linux、macOS 和 Windows
|
|
22
|
+
- 📊 **状态监控**: 实时查看进程运行状态和 PID
|
|
23
|
+
- 🧩 **易于集成**: 可作为子应用挂载到现有 FastAPI 项目
|
|
24
|
+
- 🔧 **CLI 工具**: 提供命令行工具,开箱即用
|
|
25
|
+
|
|
26
|
+
## 安装
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install fastapi-process-restarter
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 使用方法
|
|
33
|
+
|
|
34
|
+
### 方式一:命令行工具 (CLI)
|
|
35
|
+
|
|
36
|
+
安装后,直接在终端使用 `restarter` 命令:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# 基本用法
|
|
40
|
+
restarter --cmd "python main.py"
|
|
41
|
+
|
|
42
|
+
# 指定端口
|
|
43
|
+
restarter --cmd "python main.py" --port 9000
|
|
44
|
+
|
|
45
|
+
# 指定监听地址
|
|
46
|
+
restarter --cmd "node server.js" --host 127.0.0.1 --port 8080
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
API 端点:
|
|
50
|
+
- `POST /restart` - 重启进程
|
|
51
|
+
- `GET /status` - 获取进程状态
|
|
52
|
+
|
|
53
|
+
示例:
|
|
54
|
+
```bash
|
|
55
|
+
# 重启进程
|
|
56
|
+
curl -X POST http://localhost:8080/restart
|
|
57
|
+
|
|
58
|
+
# 查看状态
|
|
59
|
+
curl http://localhost:8080/status
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 方式二:Python API 集成
|
|
63
|
+
|
|
64
|
+
在现有 FastAPI 项目中作为子应用挂载:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from fastapi import FastAPI
|
|
68
|
+
from process_restarter import create_app
|
|
69
|
+
|
|
70
|
+
# 你的主应用
|
|
71
|
+
main_app = FastAPI()
|
|
72
|
+
|
|
73
|
+
@main_app.get("/")
|
|
74
|
+
def home():
|
|
75
|
+
return {"message": "Hello World"}
|
|
76
|
+
|
|
77
|
+
# 挂载进程重启器
|
|
78
|
+
cmd_app = create_app(cmd="node server.js")
|
|
79
|
+
main_app.mount("/subsystem", cmd_app)
|
|
80
|
+
|
|
81
|
+
# 现在可以通过 POST /subsystem/restart 重启 node server.js
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
也可以直接使用 `ProcessManager`:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from process_restarter import ProcessManager
|
|
88
|
+
|
|
89
|
+
manager = ProcessManager(cmd="python worker.py")
|
|
90
|
+
manager.start() # 启动进程
|
|
91
|
+
manager.restart() # 重启进程
|
|
92
|
+
manager.stop() # 停止进程
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 技术细节
|
|
96
|
+
|
|
97
|
+
- **跨平台进程管理**:
|
|
98
|
+
- Linux/macOS: 使用 `os.setsid` 创建进程组
|
|
99
|
+
- Windows: 使用 `CREATE_NEW_PROCESS_GROUP` 创建进程组
|
|
100
|
+
- **生命周期管理**: 使用 FastAPI `@asynccontextmanager` 确保程序退出时子进程被清理
|
|
101
|
+
- **日志桥接**: 子进程输出实时转发到主进程 stdout
|
|
102
|
+
|
|
103
|
+
## 许可证
|
|
104
|
+
|
|
105
|
+
MIT License
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
fastapi_process_restarter.egg-info/PKG-INFO
|
|
4
|
+
fastapi_process_restarter.egg-info/SOURCES.txt
|
|
5
|
+
fastapi_process_restarter.egg-info/dependency_links.txt
|
|
6
|
+
fastapi_process_restarter.egg-info/entry_points.txt
|
|
7
|
+
fastapi_process_restarter.egg-info/requires.txt
|
|
8
|
+
fastapi_process_restarter.egg-info/top_level.txt
|
|
9
|
+
process_restarter/__init__.py
|
|
10
|
+
process_restarter/api.py
|
|
11
|
+
process_restarter/cli.py
|
|
12
|
+
process_restarter/manager.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
process_restarter
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from contextlib import asynccontextmanager
|
|
2
|
+
from fastapi import FastAPI
|
|
3
|
+
from .manager import ProcessManager
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def create_app(cmd: str) -> FastAPI:
|
|
7
|
+
manager = ProcessManager(cmd)
|
|
8
|
+
|
|
9
|
+
# FastAPI 现代生命周期管理
|
|
10
|
+
@asynccontextmanager
|
|
11
|
+
async def lifespan(app: FastAPI):
|
|
12
|
+
manager.start() # 启动时运行
|
|
13
|
+
yield
|
|
14
|
+
manager.stop() # 退出时清理
|
|
15
|
+
|
|
16
|
+
app = FastAPI(title="Process Restarter API", lifespan=lifespan)
|
|
17
|
+
|
|
18
|
+
@app.post("/restart")
|
|
19
|
+
async def restart():
|
|
20
|
+
manager.restart()
|
|
21
|
+
return {"status": "restarting", "cmd": cmd, "new_pid": manager.proc.pid}
|
|
22
|
+
|
|
23
|
+
@app.get("/status")
|
|
24
|
+
async def status():
|
|
25
|
+
is_running = manager.proc is not None and manager.proc.poll() is None
|
|
26
|
+
pid = manager.proc.pid if is_running else None
|
|
27
|
+
return {"running": is_running, "pid": pid}
|
|
28
|
+
|
|
29
|
+
return app
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import uvicorn
|
|
3
|
+
from .api import create_app
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
parser = argparse.ArgumentParser(
|
|
8
|
+
description="Run a command with a FastAPI restart endpoint."
|
|
9
|
+
)
|
|
10
|
+
parser.add_argument(
|
|
11
|
+
"-c", "--cmd", required=True, help="The command to run (e.g., 'python main.py')"
|
|
12
|
+
)
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
"--host", default="0.0.0.0", help="API Host (default: 0.0.0.0)"
|
|
15
|
+
)
|
|
16
|
+
parser.add_argument(
|
|
17
|
+
"-p", "--port", type=int, default=8080, help="API Port (default: 8080)"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
args = parser.parse_args()
|
|
21
|
+
|
|
22
|
+
app = create_app(args.cmd)
|
|
23
|
+
uvicorn.run(app, host=args.host, port=args.port)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
if __name__ == "__main__":
|
|
27
|
+
main()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
import threading
|
|
5
|
+
import signal
|
|
6
|
+
import platform
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ProcessManager:
|
|
10
|
+
def __init__(self, cmd: str):
|
|
11
|
+
self.cmd = cmd
|
|
12
|
+
self.proc = None
|
|
13
|
+
|
|
14
|
+
def log_bridge(self, pipe):
|
|
15
|
+
"""实时将子进程日志写到主进程的 stdout"""
|
|
16
|
+
if not pipe:
|
|
17
|
+
return
|
|
18
|
+
for line in iter(pipe.readline, b""):
|
|
19
|
+
sys.stdout.buffer.write(line)
|
|
20
|
+
sys.stdout.buffer.flush()
|
|
21
|
+
|
|
22
|
+
def start(self):
|
|
23
|
+
print(f"[@] Starting command: {self.cmd}")
|
|
24
|
+
kwargs = {
|
|
25
|
+
"shell": True,
|
|
26
|
+
"stdout": subprocess.PIPE,
|
|
27
|
+
"stderr": subprocess.STDOUT,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# 跨平台进程组处理
|
|
31
|
+
if platform.system() != "Windows":
|
|
32
|
+
kwargs["preexec_fn"] = os.setsid
|
|
33
|
+
else:
|
|
34
|
+
kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP
|
|
35
|
+
|
|
36
|
+
self.proc = subprocess.Popen(self.cmd, **kwargs)
|
|
37
|
+
|
|
38
|
+
# 异步读取日志
|
|
39
|
+
threading.Thread(
|
|
40
|
+
target=self.log_bridge, args=(self.proc.stdout,), daemon=True
|
|
41
|
+
).start()
|
|
42
|
+
|
|
43
|
+
def stop(self):
|
|
44
|
+
if self.proc:
|
|
45
|
+
print("[!] Stopping process...")
|
|
46
|
+
try:
|
|
47
|
+
if platform.system() != "Windows":
|
|
48
|
+
os.killpg(os.getpgid(self.proc.pid), signal.SIGKILL)
|
|
49
|
+
else:
|
|
50
|
+
# Windows 下彻底杀死进程树
|
|
51
|
+
subprocess.run(
|
|
52
|
+
["taskkill", "/F", "/T", "/PID", str(self.proc.pid)],
|
|
53
|
+
stdout=subprocess.DEVNULL,
|
|
54
|
+
stderr=subprocess.DEVNULL,
|
|
55
|
+
)
|
|
56
|
+
except Exception as e:
|
|
57
|
+
print(f"[x] Error stopping process: {e}")
|
|
58
|
+
self.proc = None
|
|
59
|
+
|
|
60
|
+
def restart(self):
|
|
61
|
+
self.stop()
|
|
62
|
+
self.start()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "fastapi-process-restarter"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Developer", email="dev@example.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "A FastAPI based wrapper to auto-run and API-restart any terminal command."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.7"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"fastapi>=0.90.0",
|
|
21
|
+
"uvicorn>=0.20.0"
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.scripts]
|
|
25
|
+
restarter = "process_restarter.cli:main"
|