You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
0.3.1: sync locking, dry-run API, env var interpolation
- Per-KB asyncio.Lock prevents overlapping syncs from scheduler,
webhook, and API triggers running simultaneously
- POST /sync/{id}?dry_run=true previews changes without uploading
- ${VAR} and ${VAR:-default} interpolation in all .oikb.yaml strings
for GitOps workflows where secrets come from the runtime
Copy file name to clipboardExpand all lines: CHANGELOG.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
4
4
5
5
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
7
+
## [0.3.1] - 2025-05-21
8
+
9
+
### Added
10
+
11
+
- Per-KB sync locking — prevents overlapping syncs to the same Knowledge Base. If a webhook fires while a scheduled sync is running, the duplicate is skipped with a log message.
12
+
- Dry-run via API — `POST /sync/{id}?dry_run=true` previews changes without uploading, returns added/modified/deleted counts.
13
+
- Environment variable interpolation in `.oikb.yaml` — `${VAR}` and `${VAR:-default}` syntax in all string values. Enables GitOps workflows where secrets come from the runtime.
Copy file name to clipboardExpand all lines: src/oikb/daemon.py
+42-6Lines changed: 42 additions & 6 deletions
Original file line number
Diff line number
Diff line change
@@ -40,11 +40,12 @@ async def verify_api_key(
40
40
app=FastAPI(
41
41
title="oikb",
42
42
description="Sync engine for Open WebUI Knowledge Bases. Trigger syncs, check status, and query history.",
43
-
version="0.3.0",
43
+
version="0.3.1",
44
44
)
45
45
46
46
# Runtime state populated by start_daemon().
47
47
_scheduler_state: dict[str, dict[str, Any]] = {}
48
+
_sync_locks: dict[str, asyncio.Lock] = {}
48
49
_history: SyncHistory|None=None
49
50
_entries: list[dict] = []
50
51
_shutdown_event: asyncio.Event|None=None
@@ -128,10 +129,13 @@ async def history_endpoint(
128
129
summary="Trigger an immediate sync by alias or KB ID",
129
130
dependencies=[Depends(verify_api_key)],
130
131
)
131
-
asyncdeftrigger_sync(identifier: str):
132
-
"""Triggers an immediate sync matching the given alias or Knowledge Base ID. The sync runs asynchronously in the background. Use get_sync_status to check progress."""
"""Triggers an immediate sync matching the given alias or Knowledge Base ID. The sync runs asynchronously in the background. Use get_sync_status to check progress. Set dry_run=true to preview changes without uploading."""
0 commit comments