fix(obsidian): enable obsidian-git auto-backup on headless server - #1463
Conversation
The Electron renderer's setTimeout doesn't fire under headless xvfb (futex_wait_queue blocks the event loop pump), so the obsidian-git plugin's periodic backup timer never executes. Fix by adding a systemd timer that triggers the plugin's doAutoCommitAndSync() via Chrome DevTools Protocol every 3 minutes. CDP messages use IPC which bypasses the stuck event loop. Websocket ping-interval keeps the connection alive for 15s to pump the loop while git operations complete. Also fixes Chrome 140 Fontations font indexer crash (NOTREACHED in remote_font_face_source.cc:357) by adding --disable-features=FontationsFontIndexer and installing dejavu_fonts + fontconfig on the headless server. Changes: - Add --remote-debugging-port=9222 and --disable-features=FontationsFontIndexer to obsidian-headless.sh - Add obsidian-git-trigger.sh CDP trigger script - Add obsidian-git-trigger systemd timer (3 min interval) - Add dejavu_fonts and fontconfig packages for headless rendering - Add spec and coverage for new trigger script
|
You do not have enough credits to review this pull request. Please purchase more credits to continue. |
📝 WalkthroughSummary by CodeRabbit
WalkthroughA new automated trigger mechanism for Obsidian's git plugin is introduced using Chrome DevTools Protocol. A systemd timer and service are added to periodically invoke git auto-sync commits. The headless Obsidian wrapper is updated to expose port 9222 for CDP connections, and test coverage validates the new trigger script. Changes
Sequence DiagramsequenceDiagram
participant Timer as systemd Timer
participant Service as obsidian-git-trigger.service
participant Script as obsidian-git-trigger.sh
participant CDP as Chrome DevTools<br/>(localhost:9222)
participant Obsidian as Obsidian App
Timer->>Service: Trigger (OnBootSec + OnUnitActiveSec)
Note over Timer,Service: After obsidian.service
Service->>Script: Execute obsidian-git-trigger
Script->>CDP: GET /json (discover targets)
CDP-->>Script: Return webSocketDebuggerUrl
Script->>CDP: WebSocket Connect
Script->>CDP: Send Runtime.evaluate request
Note over Script,CDP: Call doAutoCommitAndSync()
Script->>Obsidian: Execute plugin method via CDP
Obsidian->>Obsidian: Commit & Sync via obsidian-git
CDP-->>Script: WebSocket response
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly Related PRs
Suggested Labels
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Mesa DescriptionTL;DRFixes obsidian-git plugin's auto-backup on headless Kyber server by adding a CDP-based systemd timer, and addresses Chrome 140 Fontations crash and Electron event loop blocking issues. What changed?
Description generated by Mesa. Update settings |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@home-manager/services/obsidian/obsidian-git-trigger.sh`:
- Around line 18-21: The script masks WebSocket/CDP failures by appending "||
true" to the websocat pipeline; remove the "|| true" so failures propagate to
systemd (or replace it with explicit error handling/logging), i.e. ensure the
websocat invocation line that pipes the JSON payload to `@websocat`@/bin/websocat
--ping-interval 1 "$WS_URL" returns its exit code instead of being ignored so
systemd sees and records delivery failures of the CDP trigger.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: af863916-7f5b-4375-8905-5ec9c056c072
📒 Files selected for processing (5)
home-manager/services/obsidian/default.nixhome-manager/services/obsidian/obsidian-git-trigger.shhome-manager/services/obsidian/obsidian-headless.shspec/coverage_spec.shspec/obsidian_git_trigger_spec.sh
| { | ||
| echo '{"id":1,"method":"Runtime.evaluate","params":{"expression":"app.plugins.plugins['"'"'obsidian-git'"'"']?.automaticsManager?.doAutoCommitAndSync()"}}' | ||
| sleep 15 | ||
| } | @websocat@/bin/websocat --ping-interval 1 "$WS_URL" >/dev/null 2>&1 || true |
There was a problem hiding this comment.
Do not mask CDP/websocket failures.
|| true hides trigger failures and reports success to systemd even when the backup call was never delivered.
Suggested patch
{
echo '{"id":1,"method":"Runtime.evaluate","params":{"expression":"app.plugins.plugins['"'"'obsidian-git'"'"']?.automaticsManager?.doAutoCommitAndSync()"}}'
sleep 15
-} | `@websocat`@/bin/websocat --ping-interval 1 "$WS_URL" >/dev/null 2>&1 || true
+} | `@websocat`@/bin/websocat --ping-interval 1 "$WS_URL" >/dev/null 2>&1📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| { | |
| echo '{"id":1,"method":"Runtime.evaluate","params":{"expression":"app.plugins.plugins['"'"'obsidian-git'"'"']?.automaticsManager?.doAutoCommitAndSync()"}}' | |
| sleep 15 | |
| } | @websocat@/bin/websocat --ping-interval 1 "$WS_URL" >/dev/null 2>&1 || true | |
| { | |
| echo '{"id":1,"method":"Runtime.evaluate","params":{"expression":"app.plugins.plugins['"'"'obsidian-git'"'"']?.automaticsManager?.doAutoCommitAndSync()"}}' | |
| sleep 15 | |
| } | `@websocat`@/bin/websocat --ping-interval 1 "$WS_URL" >/dev/null 2>&1 |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@home-manager/services/obsidian/obsidian-git-trigger.sh` around lines 18 - 21,
The script masks WebSocket/CDP failures by appending "|| true" to the websocat
pipeline; remove the "|| true" so failures propagate to systemd (or replace it
with explicit error handling/logging), i.e. ensure the websocat invocation line
that pipes the JSON payload to `@websocat`@/bin/websocat --ping-interval 1
"$WS_URL" returns its exit code instead of being ignored so systemd sees and
records delivery failures of the CDP trigger.
There was a problem hiding this comment.
Code Review
This pull request introduces an automated mechanism to trigger the obsidian-git plugin's auto-backup feature in headless environments. It adds a new bash script, obsidian-git-trigger.sh, which communicates with Obsidian via the Chrome DevTools Protocol (CDP) to bypass event loop limitations under xvfb. The script is scheduled to run every three minutes via a new systemd user timer. Feedback was provided to improve the robustness of the script's JSON parsing and error handling to ensure cleaner systemd logs when the debugging port is temporarily unreachable.
|
|
||
| CDP="http://localhost:9222" | ||
|
|
||
| WS_URL=$(@curl@/bin/curl -sf "$CDP/json" | @jq@/bin/jq -r '.[0].webSocketDebuggerUrl // empty') |
There was a problem hiding this comment.
The current jq filter will produce a parse error on stderr if curl returns an empty array [] or if the input is empty (e.g., when the debugging port is not yet reachable). Using the optional chaining operator ? and suppressing stderr for these discovery commands will make the script more robust and keep the systemd logs cleaner during service startup or downtime.
| WS_URL=$(@curl@/bin/curl -sf "$CDP/json" | @jq@/bin/jq -r '.[0].webSocketDebuggerUrl // empty') | |
| WS_URL=$(@curl@/bin/curl -sf "$CDP/json" 2>/dev/null | @jq@/bin/jq -r '.[0].webSocketDebuggerUrl? // empty' 2>/dev/null) |
There was a problem hiding this comment.
1 issue found across 5 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="home-manager/services/obsidian/obsidian-git-trigger.sh">
<violation number="1" location="home-manager/services/obsidian/obsidian-git-trigger.sh:21">
P2: `|| true` masks websocat/CDP failures, so systemd always reports success even when the backup trigger wasn't delivered. Since this is a `Type=oneshot` service for backups, failures should propagate so they're visible in `systemctl status` and journal logs. The timer will retry on the next tick regardless.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| { | ||
| echo '{"id":1,"method":"Runtime.evaluate","params":{"expression":"app.plugins.plugins['"'"'obsidian-git'"'"']?.automaticsManager?.doAutoCommitAndSync()"}}' | ||
| sleep 15 | ||
| } | @websocat@/bin/websocat --ping-interval 1 "$WS_URL" >/dev/null 2>&1 || true |
There was a problem hiding this comment.
P2: || true masks websocat/CDP failures, so systemd always reports success even when the backup trigger wasn't delivered. Since this is a Type=oneshot service for backups, failures should propagate so they're visible in systemctl status and journal logs. The timer will retry on the next tick regardless.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/services/obsidian/obsidian-git-trigger.sh, line 21:
<comment>`|| true` masks websocat/CDP failures, so systemd always reports success even when the backup trigger wasn't delivered. Since this is a `Type=oneshot` service for backups, failures should propagate so they're visible in `systemctl status` and journal logs. The timer will retry on the next tick regardless.</comment>
<file context>
@@ -0,0 +1,21 @@
+{
+ echo '{"id":1,"method":"Runtime.evaluate","params":{"expression":"app.plugins.plugins['"'"'obsidian-git'"'"']?.automaticsManager?.doAutoCommitAndSync()"}}'
+ sleep 15
+} | @websocat@/bin/websocat --ping-interval 1 "$WS_URL" >/dev/null 2>&1 || true
</file context>
Summary
--disable-features=FontationsFontIndexerdejavu_fonts,fontconfig) for headless Electron renderingProblem
Three issues prevented obsidian-git from working headlessly:
NOTREACHEDinremote_font_face_source.cc:357when zero system fonts are installed (chromium#442747781)futex_wait_queueunder xvfb, preventingsetTimeoutcallbacks from firingcustomMessageOnAutoBackup: trueopens an interactive modal that hangs headlessly (fixed in wiki repo)Solution
CDP (Chrome DevTools Protocol) messages use IPC which bypasses the stuck event loop. A systemd timer sends a CDP eval to trigger
doAutoCommitAndSync()every 3 minutes, with websocket--ping-intervalkeepalives that pump the event loop for 15s while git operations complete.All git operations still run through the obsidian-git plugin -- the timer just triggers what
setTimeoutcan't.Test plan
make shell-lintpassesmake format-- no changesshellspec-- 1247 examples, 0 failuresSummary by cubic
Enable
obsidian-gitauto-backups on the headless kyber server by triggeringdoAutoCommitAndSync()via CDP on a systemd timer. Also fix the Chrome 140 Fontations crash and add fonts for stable headless Electron rendering.New Features
obsidian-git-trigger.shand a usersystemdservice + timer (every 3 min) to invoke the plugin via CDP on--remote-debugging-port=9222.--ping-intervalfor 15s so git operations complete; all work still runs inside the plugin.Bug Fixes
xvfbby using CDP IPC instead ofsetTimeout.dejavu_fonts+fontconfigto prevent font-related crashes.Written for commit 8d1499f. Summary will update on new commits.