357 lines
8.7 KiB
Markdown
357 lines
8.7 KiB
Markdown
# 🔄 Deployment Scripts Update Mechanism
|
||
|
||
## Core Answer
|
||
|
||
✅ **Yes, re-deploying automatically updates the plugin!**
|
||
|
||
The deployment script uses a **smart two-stage strategy**:
|
||
|
||
1. 🔄 **Try UPDATE First** (if plugin exists)
|
||
2. 📝 **Auto CREATE** (if update fails — plugin doesn't exist)
|
||
|
||
## Workflow Diagram
|
||
|
||
```
|
||
Run deploy script
|
||
↓
|
||
Read local code and metadata
|
||
↓
|
||
Send UPDATE request to OpenWebUI
|
||
↓
|
||
├─ HTTP 200 ✅
|
||
│ └─ Plugin exists → Update successful!
|
||
│
|
||
└─ Other status codes (404, 400, etc.)
|
||
└─ Plugin doesn't exist or update failed
|
||
↓
|
||
Send CREATE request
|
||
↓
|
||
├─ HTTP 200 ✅
|
||
│ └─ Creation successful!
|
||
│
|
||
└─ Failed
|
||
└─ Display error message
|
||
```
|
||
|
||
## Detailed Step-by-step
|
||
|
||
### Step 1️⃣: Try UPDATE First
|
||
|
||
```python
|
||
# Code location: deploy_filter.py line 220-230
|
||
|
||
update_url = "http://localhost:3000/api/v1/functions/id/{filter_id}/update"
|
||
|
||
response = requests.post(
|
||
update_url,
|
||
headers=headers,
|
||
data=json.dumps(payload),
|
||
timeout=10,
|
||
)
|
||
|
||
if response.status_code == 200:
|
||
print(f"✅ Successfully updated '{title}' filter!")
|
||
return True
|
||
```
|
||
|
||
**What Happens**:
|
||
|
||
- Send **POST** to `/api/v1/functions/id/{filter_id}/update`
|
||
- If returns **HTTP 200**, plugin exists and update succeeded
|
||
- Includes:
|
||
- Complete latest code
|
||
- Metadata (title, version, author, description, etc.)
|
||
- Manifest information
|
||
|
||
### Step 2️⃣: If UPDATE Fails, Try CREATE
|
||
|
||
```python
|
||
# Code location: deploy_filter.py line 231-245
|
||
|
||
if response.status_code != 200:
|
||
print(f"⚠️ Update failed with status {response.status_code}, "
|
||
"attempting to create instead...")
|
||
|
||
create_url = "http://localhost:3000/api/v1/functions/create"
|
||
res_create = requests.post(
|
||
create_url,
|
||
headers=headers,
|
||
data=json.dumps(payload),
|
||
timeout=10,
|
||
)
|
||
|
||
if res_create.status_code == 200:
|
||
print(f"✅ Successfully created '{title}' filter!")
|
||
return True
|
||
```
|
||
|
||
**What Happens**:
|
||
|
||
- If update fails (HTTP ≠ 200), auto-attempt create
|
||
- Send **POST** to `/api/v1/functions/create`
|
||
- Uses **same payload** (code, metadata identical)
|
||
- If creation succeeds, first deployment to OpenWebUI
|
||
|
||
## Real-world Scenarios
|
||
|
||
### Scenario A: First Deployment
|
||
|
||
```bash
|
||
$ python deploy_async_context_compression.py
|
||
|
||
📦 Deploying filter 'Async Context Compression' (version 1.3.0)...
|
||
File: .../async_context_compression.py
|
||
⚠️ Update failed with status 404, attempting to create instead... ← First time, plugin doesn't exist
|
||
✅ Successfully created 'Async Context Compression' filter! ← Creation succeeds
|
||
```
|
||
|
||
**What Happens**:
|
||
|
||
1. Try UPDATE → fails (HTTP 404 — plugin doesn't exist)
|
||
2. Auto-try CREATE → succeeds (HTTP 200)
|
||
3. Plugin created in OpenWebUI
|
||
|
||
---
|
||
|
||
### Scenario B: Re-deploy After Code Changes
|
||
|
||
```bash
|
||
# Made first code change, deploying again
|
||
$ python deploy_async_context_compression.py
|
||
|
||
📦 Deploying filter 'Async Context Compression' (version 1.3.1)...
|
||
File: .../async_context_compression.py
|
||
✅ Successfully updated 'Async Context Compression' filter! ← Direct update!
|
||
```
|
||
|
||
**What Happens**:
|
||
|
||
1. Read modified code
|
||
2. Try UPDATE → succeeds (HTTP 200 — plugin exists)
|
||
3. Plugin in OpenWebUI updated to latest code
|
||
4. **No need to restart OpenWebUI**, takes effect immediately!
|
||
|
||
---
|
||
|
||
### Scenario C: Multiple Fast Iterations
|
||
|
||
```bash
|
||
# 1st change
|
||
$ python deploy_async_context_compression.py
|
||
✅ Successfully updated 'Async Context Compression' filter!
|
||
|
||
# 2nd change
|
||
$ python deploy_async_context_compression.py
|
||
✅ Successfully updated 'Async Context Compression' filter!
|
||
|
||
# 3rd change
|
||
$ python deploy_async_context_compression.py
|
||
✅ Successfully updated 'Async Context Compression' filter!
|
||
|
||
# ... repeat infinitely ...
|
||
```
|
||
|
||
**Characteristics**:
|
||
|
||
- 🚀 Each update takes only 5 seconds
|
||
- 📝 Each is an incremental update
|
||
- ✅ No need to restart OpenWebUI
|
||
- 🔄 Can repeat indefinitely
|
||
|
||
## What Gets Updated
|
||
|
||
Each deployment updates the following:
|
||
|
||
✅ **Code** — All latest Python code
|
||
✅ **Version** — Auto-extracted from docstring
|
||
✅ **Title** — Plugin display name
|
||
✅ **Author Info** — author, author_url
|
||
✅ **Description** — Plugin description
|
||
✅ **Metadata** — funding_url, openwebui_id, etc.
|
||
|
||
❌ **Configuration NOT Overwritten** — User's Valves settings in OpenWebUI stay unchanged
|
||
|
||
## Version Number Management
|
||
|
||
### Does Version Change on Update?
|
||
|
||
✅ **Yes!**
|
||
|
||
```python
|
||
# docstring in async_context_compression.py
|
||
|
||
"""
|
||
title: Async Context Compression
|
||
version: 1.3.0
|
||
"""
|
||
```
|
||
|
||
**Each deployment**:
|
||
|
||
1. Script reads version from docstring
|
||
2. Sends this version in manifest to OpenWebUI
|
||
3. If you change version in code, deployment updates to new version
|
||
|
||
**Best Practice**:
|
||
|
||
```bash
|
||
# 1. Modify code
|
||
vim async_context_compression.py
|
||
|
||
# 2. Update version (in docstring)
|
||
# version: 1.3.0 → 1.3.1
|
||
|
||
# 3. Deploy
|
||
python deploy_async_context_compression.py
|
||
|
||
# Result: OpenWebUI shows version 1.3.1
|
||
```
|
||
|
||
## Deployment Failure Cases
|
||
|
||
### Case 1: Network Error
|
||
|
||
```bash
|
||
❌ Connection error: Could not reach OpenWebUI at localhost:3000
|
||
Make sure OpenWebUI is running and accessible.
|
||
```
|
||
|
||
**Cause**: OpenWebUI not running or wrong port
|
||
**Solution**: Check if OpenWebUI is running
|
||
|
||
### Case 2: Invalid API Key
|
||
|
||
```bash
|
||
❌ Failed to update or create. Status: 401
|
||
Error: {"error": "Unauthorized"}
|
||
```
|
||
|
||
**Cause**: API key in .env is invalid or expired
|
||
**Solution**: Update api_key in `.env` file
|
||
|
||
### Case 3: Server Error
|
||
|
||
```bash
|
||
❌ Failed to update or create. Status: 500
|
||
Error: Internal server error
|
||
```
|
||
|
||
**Cause**: OpenWebUI server internal error
|
||
**Solution**: Check OpenWebUI logs
|
||
|
||
## Setting Version Numbers — Best Practices
|
||
|
||
### Semantic Versioning
|
||
|
||
Follow `MAJOR.MINOR.PATCH` format:
|
||
|
||
```python
|
||
"""
|
||
version: 1.3.0
|
||
│ │ │
|
||
│ │ └─ PATCH: Bug fixes (1.3.0 → 1.3.1)
|
||
│ └────── MINOR: New features (1.3.0 → 1.4.0)
|
||
└───────── MAJOR: Breaking changes (1.3.0 → 2.0.0)
|
||
"""
|
||
```
|
||
|
||
**Examples**:
|
||
|
||
```python
|
||
# Bug fix (PATCH)
|
||
version: 1.3.0 → 1.3.1
|
||
|
||
# New feature (MINOR)
|
||
version: 1.3.0 → 1.4.0
|
||
|
||
# Major update (MAJOR)
|
||
version: 1.3.0 → 2.0.0
|
||
```
|
||
|
||
## Complete Iteration Workflow
|
||
|
||
```bash
|
||
# 1. First deployment
|
||
cd scripts
|
||
python deploy_async_context_compression.py
|
||
# Result: Plugin created (first time)
|
||
|
||
# 2. Modify code
|
||
vim ../plugins/filters/async-context-compression/async_context_compression.py
|
||
# Edit code...
|
||
|
||
# 3. Deploy again (auto-update)
|
||
python deploy_async_context_compression.py
|
||
# Result: Plugin updated (takes effect immediately, no OpenWebUI restart)
|
||
|
||
# 4. Repeat steps 2-3 indefinitely
|
||
# Modify → Deploy → Test → Improve → Repeat
|
||
```
|
||
|
||
## Benefits of Auto-update
|
||
|
||
| Benefit | Details |
|
||
|---------|---------|
|
||
| ⚡ **Fast Iteration** | Code change → Deploy (5s) → Test, no waiting |
|
||
| 🔄 **Auto-detection** | No manual decision between create/update |
|
||
| 📝 **Version Management** | Version auto-extracted from code |
|
||
| ✅ **No Restart Needed** | OpenWebUI runs continuously, config stays same |
|
||
| 🛡️ **Safe Updates** | User settings (Valves) never overwritten |
|
||
|
||
## Disable Auto-update? ❌
|
||
|
||
Usually **not needed** because:
|
||
|
||
1. ✅ Updates are idempotent (same code deployed multiple times = no change)
|
||
2. ✅ User configuration not modified
|
||
3. ✅ Version numbers auto-managed
|
||
4. ✅ Failures auto-rollback
|
||
|
||
但如果真的需要控制,可以:
|
||
|
||
- 手动修改脚本 (修改 `deploy_filter.py`)
|
||
- 或分别使用 UPDATE/CREATE 的具体 API 端点
|
||
|
||
## 常见问题
|
||
|
||
### Q: 更新是否会丢失用户的配置?
|
||
|
||
❌ **不会!**
|
||
用户在 OpenWebUI 中设置的 Valves (参数配置) 会被保留。
|
||
|
||
### Q: 是否可以回到旧版本?
|
||
|
||
✅ **可以!**
|
||
修改代码中的 `version` 号为旧版本,然后重新部署。
|
||
|
||
### Q: 更新需要多长时间?
|
||
|
||
⚡ **约 5 秒**
|
||
包括: 读文件 (1s) + 发送请求 (3s) + 响应 (1s)
|
||
|
||
### Q: 可以同时部署多个插件吗?
|
||
|
||
✅ **可以!**
|
||
|
||
```bash
|
||
python deploy_filter.py async-context-compression
|
||
python deploy_filter.py folder-memory
|
||
python deploy_filter.py context_enhancement_filter
|
||
```
|
||
|
||
### Q: 部署失败了会怎样?
|
||
|
||
✅ **OpenWebUI 中的插件保持不变**
|
||
失败不会修改已部署的插件。
|
||
|
||
---
|
||
|
||
**总结**: 部署脚本的更新机制完全自动化,开发者只需修改代码,每次运行 `deploy_async_context_compression.py` 就会自动:
|
||
|
||
1. ✅ 创建(第一次)或更新(后续)插件
|
||
2. ✅ 从代码提取最新的元数据和版本号
|
||
3. ✅ 立即生效,无需重启 OpenWebUI
|
||
4. ✅ 保留用户的配置不变
|
||
|
||
这使得本地开发和快速迭代变得极其流畅!🚀
|