fixed reADME AND USER SCRIPT PLUGIN
This commit is contained in:
@@ -21,6 +21,42 @@ Orchestrators solve this by making a set of related scripts into a single schedu
|
||||
|
||||
## Scripts
|
||||
|
||||
### `transcode_management.sh`
|
||||
|
||||
Runs `transcode_cleanup.sh` then `transcode_manager.sh` in the correct order every 3 minutes. Replaces two separate cron entries with one.
|
||||
|
||||
```bash
|
||||
# Scheduled as: */3 * * * *
|
||||
/mnt/user/appdata/unraid_scripts/Orchestrators/transcode_management.sh
|
||||
```
|
||||
|
||||
**Why cleanup must run before manager:**
|
||||
|
||||
If the manager runs first it may see inflated ramdisk usage from stale segment files left by ended sessions — and trigger an unnecessary flip to SSD. Cleanup runs first to clear those files, then the manager makes its threshold decision based on real active session usage.
|
||||
|
||||
```
|
||||
Without correct order:
|
||||
Manager checks usage → 6.8GB (includes stale files) → flips to SSD
|
||||
Cleanup runs → removes stale files → actual usage 2.1GB
|
||||
Manager was wrong — unnecessary flip
|
||||
|
||||
With correct order:
|
||||
Cleanup runs → removes stale files → actual usage 2.1GB
|
||||
Manager checks usage → 2.1GB → stays on ramdisk ✅
|
||||
```
|
||||
|
||||
**Daily statistics tracking:**
|
||||
|
||||
Every cycle `transcode_management.sh` records stats to `/boot/config/transcode_daily.db`:
|
||||
- Peak ramdisk usage for the day
|
||||
- Total flip count for the day
|
||||
- Ramdisk vs SSD session counts
|
||||
- Files cleaned
|
||||
|
||||
`weekly_health_digest.sh` reads this log for the weekly transcode summary. The log is bounded to `TRANSCODE_LOG_RETENTION` days — auto-purges on every write.
|
||||
|
||||
---
|
||||
|
||||
### `daily_sync.sh`
|
||||
|
||||
Syncs all bulk media shares to the remote server sequentially. Scheduled once daily.
|
||||
@@ -177,8 +213,9 @@ This pattern means:
|
||||
|
||||
```bash
|
||||
# Recommended schedule
|
||||
0 1 * * * daily_sync.sh # 1am — media shares to remote
|
||||
0 2 * * * media_management.sh # 2am — after sync completes
|
||||
*/3 * * * * transcode_management.sh # cleanup then manager — every 3 minutes
|
||||
0 1 * * * daily_sync.sh # 1am — media shares to remote
|
||||
0 2 * * * media_management.sh # 2am — after sync completes
|
||||
```
|
||||
|
||||
The 1 hour gap between them is intentional. `daily_sync.sh` can take 30-60 minutes on a large library. Starting `media_management.sh` before it finishes risks permission and cleanup operations running on files that are mid-transfer.
|
||||
|
||||
@@ -22,83 +22,88 @@ Before this ecosystem existed, the same problems were solved by 60+ standalone s
|
||||
## The Servers
|
||||
|
||||
```
|
||||
HOST1 — unRAID-Gmer4Lfe (Primary)
|
||||
HOST1 — unRAID-Gmer4Lfe
|
||||
Hardware: Threadripper 1950X, 128GB RAM
|
||||
Storage: Multiple ZFS pools + cache
|
||||
Role: Primary services, full media stack, all Docker containers
|
||||
Domain: Gmer4Lfe.com
|
||||
Runs: Full media stack, auth, live TV, arrs, downloaders
|
||||
arr master — source of truth for shared library
|
||||
|
||||
HOST2 — unRAID-Jayred365 (Secondary / Buddy server)
|
||||
HOST2 — unRAID-Jayred365 (Buddy server)
|
||||
Hardware: Intel i5 10th gen — completely different hardware
|
||||
Storage: Different disk count, different pool layout
|
||||
Location: Remote — 50 miles from HOST1
|
||||
Role: Mirror, failover coverage, independent services
|
||||
Domain: Gmer4Lfe.us (his own domain, his own services)
|
||||
Runs: His own independent Emby, his own containers, his own users
|
||||
Access to shared media library via mirrored shares
|
||||
|
||||
Network: Tailscale — encrypted tunnel between both servers
|
||||
Repo: Self-hosted Gitea on HOST1
|
||||
Deployment: git pull on either server → both stay current
|
||||
```
|
||||
|
||||
**The servers do not need to be identical hardware.** This is one of the most important design decisions in the ecosystem. Because everything is accessed through `/mnt/user/` — unRAID's fused share layer — the underlying disk count, pool layout, and hardware generation don't matter. A share called `Movies` on HOST1 is `/mnt/user/Movies`. The same share name on HOST2 is also `/mnt/user/Movies`. rsync syncs between them. Failover containers on HOST2 mount `/mnt/user/Movies` and see the same data. The hardware underneath is completely irrelevant.
|
||||
|
||||
```
|
||||
HOST1: Threadripper, 10 drives across 5 ZFS pools
|
||||
HOST2: i5, 4 drives, completely different layout
|
||||
Both: /mnt/user/Movies — identical path, same data, different everything else
|
||||
```
|
||||
|
||||
**What is actually mirrored:**
|
||||
|
||||
**Share names** — `/mnt/user/Movies` is `/mnt/user/Movies` on both servers. rsync syncs the content nightly. Container volume mounts use the same path. No path translation anywhere.
|
||||
|
||||
**Media shares** — all media is mirrored to HOST2. Since both servers mount the same share names, every container on HOST2 — Emby, the arr stack, everything — has access to the same library HOST1 serves. HOST1 is the source of truth. HOST2 is the mirror. They share the same data pool when failover kicks in — no separate libraries, no separate metadata, no separate databases for media.
|
||||
|
||||
```
|
||||
HOST1 /mnt/user/Movies → rsync nightly → HOST2 /mnt/user/Movies
|
||||
HOST1 /mnt/user/Tv_Shows → rsync nightly → HOST2 /mnt/user/Tv_Shows
|
||||
HOST1 /mnt/user/Music → rsync nightly → HOST2 /mnt/user/Music
|
||||
...all media shares mirrored...
|
||||
```
|
||||
|
||||
**Normal operation — HOST2 piggybacks on HOST1:**
|
||||
|
||||
In day-to-day operation HOST2 is essentially passive from HOST1's perspective. HOST1 handles everything — all arrs, all downloads, all transcoding, all active services. HOST2 keeps its mirror current and waits.
|
||||
**This is a genuine mutual failover agreement between two friends, each running a fully independent server.** Both servers are fully active in normal operation — each with their own service stack, their own domain, their own users. HOST2 is not a standby. He runs his own Emby, his own containers, and his own domain while sharing access to the mirrored media library.
|
||||
|
||||
```
|
||||
Normal operation:
|
||||
HOST1 — source of truth, all active services running
|
||||
HOST2 — mirror current, containers ready but stopped
|
||||
no arrs running (would create conflicts with HOST1)
|
||||
no downloaders running
|
||||
just keeping data fresh and ready to take over
|
||||
HOST1 — Gmer4Lfe.com — full stack, live TV, arrs, everything
|
||||
HOST2 — Gmer4Lfe.us — his Emby, his containers, his domain, his users
|
||||
Both independently serving media from the mirrored shared library
|
||||
```
|
||||
|
||||
**Don't run arrs on both servers simultaneously.** The arr stack manages your library — two instances writing to the same share causes conflicts, duplicate downloads, and database corruption. Either designate one server as the arr master (HOST1 in this setup) or split arrs between servers by type. HOST2's arrs only start during Tier 4 failover — when HOST1 has been down 18+ hours and workflow continuity is genuinely needed.
|
||||
|
||||
**Container names** — failover containers on HOST2 must use the same Docker container name as on HOST1. The failover script starts them by name via SSH. Server-specific containers get server-specific names:
|
||||
|
||||
**When HOST2 goes down:**
|
||||
```
|
||||
Shared containers — same name on both servers:
|
||||
Emby ← starts on HOST2 during HOST1 outage
|
||||
uses HOST2's mirrored media, same library
|
||||
NginxProxyManager ← same name, same config, same network
|
||||
Authelia ← same name
|
||||
|
||||
Server-specific containers — unique names:
|
||||
Emby-Gmer4Lfe ← HOST1's own Emby instance, always on HOST1
|
||||
Emby-Jayred365 ← HOST2's own Emby instance, always on HOST2
|
||||
VaultWarden-Gmer4Lfe ← HOST1's password manager
|
||||
VaultWarden-Jayred365← HOST2's password manager
|
||||
HOST1 detects HOST2 unreachable + internet up
|
||||
→ Starts HOST2's DDNS (Gmer4Lfe.us) on HOST1 — his domain stays live
|
||||
→ Starts HOST2's specific containers — his services keep running on HOST1
|
||||
→ HOST1's own services keep running unaffected — failover is additive
|
||||
→ Waits for HOST2 to come back stable (FAILOVER_HANDBACK_STRIKES checks)
|
||||
→ Hands everything back — his containers, his DDNS — returns to NORMAL
|
||||
```
|
||||
|
||||
**Docker custom networks** — containers communicate by container name within a custom network, not by IP address. When a container restarts and gets a new IP, NginxProxyManager still reaches it by name. Failover containers on HOST2 join the same named custom networks and are immediately reachable by NPM without any IP reconfiguration required.
|
||||
**When HOST1 goes down:**
|
||||
```
|
||||
HOST2 detects HOST1 unreachable + internet up
|
||||
→ Starts HOST1's DDNS (Gmer4Lfe.com) on HOST2 — my domain stays live
|
||||
→ Starts HOST1's Tier 1 containers — Emby, auth, live TV immediately
|
||||
→ Tiers 2/3/4 escalate if outage extends beyond configured delays
|
||||
→ HOST2's own services keep running unaffected — failover is additive
|
||||
→ Waits for HOST1 to come back stable and hands everything back
|
||||
```
|
||||
|
||||
**The hardware doesn't need to match.** `/mnt/user/` abstracts everything. A share called `Movies` is `/mnt/user/Movies` on both servers regardless of what drives or pools back it. rsync syncs the content. Container mounts use the same path. The hardware underneath is irrelevant.
|
||||
|
||||
**The shared media library:**
|
||||
|
||||
All media syncs from HOST1 to HOST2 nightly. HOST1 is the arr master and source of truth — all downloads, all library management happens there. HOST2 accesses the mirrored library with his own Emby instance in normal operation, and serves it via HOST1's failover Emby when HOST1 is down.
|
||||
|
||||
```
|
||||
Custom network: high-availability
|
||||
NginxProxyManager → Authelia (by name — IP changes are invisible)
|
||||
NginxProxyManager → Emby (by name)
|
||||
NginxProxyManager → NextCloud (by name)
|
||||
HOST1 /mnt/user/Movies → rsync nightly → HOST2 /mnt/user/Movies
|
||||
|
||||
HOST1's Emby → /mnt/user/Movies ← always
|
||||
HOST2's Emby → /mnt/user/Movies ← his own instance, same library
|
||||
Failover Emby → /mnt/user/Movies ← HOST1's Emby running on HOST2 during outage
|
||||
```
|
||||
|
||||
Don't run arrs on both simultaneously — two instances writing to the same share causes conflicts. HOST2's arrs only start at Tier 4 (18hr+ outage) when full workflow continuity is genuinely needed.
|
||||
|
||||
**Container naming convention:**
|
||||
|
||||
```
|
||||
Server-specific containers — always on their own server, unique names:
|
||||
Emby-Gmer4Lfe ← HOST1's personal Emby, always on HOST1
|
||||
Emby-Jayred365 ← HOST2's personal Emby, always on HOST2
|
||||
VaultWarden-Gmer4Lfe ← HOST1's password manager
|
||||
VaultWarden-Jayred365 ← HOST2's password manager
|
||||
|
||||
Shared failover containers — same name on both servers:
|
||||
Emby ← HOST1's main Emby, starts on HOST2 during HOST1 outage
|
||||
NginxProxyManager ← same name, same proxy rules, same networks
|
||||
Authelia ← same name
|
||||
```
|
||||
|
||||
**Docker custom networks** — containers communicate by name within custom networks, not by IP. When a container restarts and gets a new IP, NPM still reaches it by name. Failover containers join the same named networks on either server — no proxy rule changes, no IP reconfiguration, no downtime from IP drift.
|
||||
|
||||
**Personal shares — backup without failover:**
|
||||
|
||||
Beyond the shared media library, each user can sync personal shares to the other server purely for offsite backup — no failover container involvement, just data protection.
|
||||
@@ -235,7 +240,8 @@ Unraid_Scripts/
|
||||
├── Orchestrators/ # Sequential job runners
|
||||
│ ├── README-Orchestrators.md
|
||||
│ ├── daily_sync.sh # All media shares synced nightly
|
||||
│ └── media_management.sh # Permissions + cleaners + arr cleanup
|
||||
│ ├── media_management.sh # Permissions + cleaners + arr cleanup
|
||||
│ └── transcode_management.sh # Cleanup then manager every 3min + daily stats
|
||||
│
|
||||
├── Rsync/ # Core sync engine
|
||||
│ ├── README-Rsync.md
|
||||
@@ -274,7 +280,7 @@ Unraid_Scripts/
|
||||
│ └── zfs_pool_scrub.sh # Trigger ZFS scrub with completion report
|
||||
│
|
||||
└── unRAID_Essentials/ # Server-level system management
|
||||
├── README-unRAID_Essentials.md
|
||||
├── README-Unraid_Essentials.md
|
||||
├── system_watchdog.sh # Last line of defense — controlled reboot
|
||||
├── webgui_restart.sh # WebGUI nginx + emhttp auto-restart
|
||||
├── docker_syslog_filter.sh # Suppress Docker veth noise from syslog
|
||||
@@ -283,7 +289,7 @@ Unraid_Scripts/
|
||||
├── mover_stop.sh # Graceful mover termination
|
||||
├── rsync_stop.sh # Stop rsync + recover containers
|
||||
├── server_reboot.sh # Graceful reboot with user warning
|
||||
└── user_script_stop.sh # Stop all running User Scripts jobs
|
||||
└── user_scripts_stop.sh # Stop all running User Scripts jobs
|
||||
```
|
||||
|
||||
---
|
||||
@@ -338,8 +344,7 @@ php_fpm_max_children.sh
|
||||
docker_network_connect.sh
|
||||
|
||||
# ━━━ Frequent ━━━
|
||||
*/3 * * * * transcode_manager.sh
|
||||
*/5 * * * * transcode_cleanup.sh
|
||||
*/3 * * * * transcode_management.sh # replaces separate manager + cleanup entries
|
||||
*/10 * * * * webgui_restart.sh
|
||||
*/15 * * * * docker_watchdog.sh
|
||||
*/15 * * * * system_watchdog.sh
|
||||
@@ -377,7 +382,7 @@ Each folder has a detailed README covering setup, configuration, usage, and the
|
||||
| [README-Media.md](Media/README-Media.md) | Execution order, cleaner profiles, arr cleanup safety procedure |
|
||||
| [README-Transcoding.md](Transcodes/README-Transcoding.md) | Symlink indirection design, Docker mount warning, mode switching, sizing |
|
||||
| [README-Tools.md](Tools/README-Tools.md) | All utility scripts, when to use each, how to add new tools |
|
||||
| [README-unRAID_Essentials.md](unRAID_Essentials/README-unRAID_Essentials.md) | system_watchdog tiers, startup sequence, scheduled maintenance |
|
||||
| [README-Unraid_Essentials.md](unRAID_Essentials/README-Unraid_Essentials.md) | system_watchdog tiers, startup sequence, scheduled maintenance |
|
||||
|
||||
---
|
||||
|
||||
|
||||
+138
-144
@@ -36,14 +36,35 @@ This is a symlink. Emby doesn't know or care what's on the other end — it just
|
||||
|
||||
This is what makes the fallback seamless. Users never experience a glitch.
|
||||
|
||||
### Why Not Just Use the SSD Directly?
|
||||
---
|
||||
|
||||
You could point Emby directly at the SSD and skip the ramdisk entirely. Many setups do this. The ramdisk approach gives you:
|
||||
## Docker Mount — Critical
|
||||
|
||||
1. **Faster performance** — RAM is orders of magnitude faster than SSD for small random writes
|
||||
2. **Zero SSD wear** — transcode segments are written and deleted constantly. On a busy server this adds up to significant SSD wear over months and years
|
||||
3. **Automatic cleanup** — tmpfs is released back to the system when files are deleted. No fragmentation, no stale files surviving a crash
|
||||
4. **Session isolation** — each session's files disappear completely when the session ends
|
||||
**This must be configured correctly or the symlink system will not work.**
|
||||
|
||||
Emby must be configured using `--mount` in Extra Parameters — **not** as a standard path mapping in the unRAID template.
|
||||
|
||||
**In Emby Extra Parameters:**
|
||||
```
|
||||
--mount type=bind,source=/mnt/ram-transcode,target=/ext-ram-transcode,bind-propagation=shared
|
||||
```
|
||||
|
||||
**Why `shared` propagation is required:**
|
||||
|
||||
Standard bind mounts in unRAID use `rprivate` propagation by default. With `rprivate`, Docker resolves the symlink target once — at the moment of the first mount change — and locks that inode for the lifetime of the container. When the symlink flips from ramdisk to SSD, Docker takes a private copy of that SSD binding. When the symlink later flips back to ramdisk, the container ignores it — it already has a private SSD binding locked in. All new sessions land on SSD permanently until Emby restarts.
|
||||
|
||||
With `shared` propagation, host mount changes propagate into the container in real time. Symlink flips on the host are immediately visible inside the container. The system works as designed.
|
||||
|
||||
**Verify the mount is configured correctly:**
|
||||
```bash
|
||||
docker inspect Emby | grep -A4 "ext-ram"
|
||||
# Should show: "Propagation": "shared"
|
||||
# NOT: "Propagation": "rprivate"
|
||||
```
|
||||
|
||||
**Do NOT add a static SSD transcode path as a second mount.** If the SSD path is mounted inside the container, Emby can see it as an accessible transcode location and will route sessions there independently of the symlink — completely bypassing the management system.
|
||||
|
||||
> **Both of these issues were discovered in production.** The static SSD mount caused sessions to bypass the symlink. The rprivate propagation caused sessions to lock onto SSD after the first flip. Both are now fixed in the correct configuration.
|
||||
|
||||
---
|
||||
|
||||
@@ -52,38 +73,55 @@ You could point Emby directly at the SSD and skip the ramdisk entirely. Many set
|
||||
### `ramdisk_setup.sh`
|
||||
**Run at array start. Run once.**
|
||||
|
||||
Creates the tmpfs ramdisk, the SSD fallback directory, and the symlink. If the ramdisk is already mounted it reports status and exits cleanly — safe to run multiple times.
|
||||
Creates the tmpfs ramdisk, the SSD fallback directory, the symlink, and — critically — the `transcoding-temp` subdirectory on the ramdisk.
|
||||
|
||||
```bash
|
||||
# Scheduled as: At Startup of Array
|
||||
/mnt/user/appdata/unraid_scripts/Transcodes/ramdisk_setup.sh
|
||||
```
|
||||
|
||||
**Why `transcoding-temp` must be pre-created:**
|
||||
|
||||
Emby creates a `transcoding-temp` subdirectory inside its configured transcode path when it first needs to write. If `transcoding-temp` doesn't exist on the ramdisk, Emby may find and use an existing one on the SSD fallback path instead — locking all sessions onto SSD until Emby restarts.
|
||||
|
||||
`ramdisk_setup.sh` creates `transcoding-temp` on the ramdisk at mount time so Emby always finds it there first.
|
||||
|
||||
What it creates:
|
||||
```
|
||||
/mnt/ramdisk_transcodes/ ← tmpfs mount (RAMDISK_SIZE ceiling)
|
||||
/mnt/ram-transcode ← symlink pointing at ramdisk
|
||||
/mnt/cache/Temp_Storage/Emby/Transcodes/ ← SSD fallback directory
|
||||
/mnt/ramdisk_transcodes/ ← tmpfs mount (RAMDISK_SIZE ceiling)
|
||||
/mnt/ramdisk_transcodes/transcoding-temp ← pre-created so Emby uses ramdisk
|
||||
/mnt/ram-transcode ← symlink pointing at ramdisk
|
||||
/mnt/cache/Temp_Storage/Emby/Transcodes/ ← SSD fallback directory
|
||||
```
|
||||
|
||||
After running, verify:
|
||||
```bash
|
||||
mountpoint /mnt/ramdisk_transcodes # should say "is a mountpoint"
|
||||
readlink /mnt/ram-transcode # should show /mnt/ramdisk_transcodes
|
||||
mountpoint /mnt/ramdisk_transcodes # should say "is a mountpoint"
|
||||
readlink /mnt/ram-transcode # should show /mnt/ramdisk_transcodes
|
||||
ls /mnt/ramdisk_transcodes/ # should show transcoding-temp/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `transcode_manager.sh`
|
||||
**Run every 3 minutes via cron.**
|
||||
### `transcode_management.sh` (Orchestrators/)
|
||||
**Run every 3 minutes via cron. Replaces separate manager and cleanup cron entries.**
|
||||
|
||||
Monitors ramdisk usage and manages the symlink direction. The main brain of the system.
|
||||
Runs `transcode_cleanup.sh` first then `transcode_manager.sh` in the correct order. Cleanup runs first so the manager sees accurate post-cleanup usage before making threshold decisions.
|
||||
|
||||
```bash
|
||||
# Scheduled as: */3 * * * *
|
||||
/mnt/user/appdata/unraid_scripts/Transcodes/transcode_manager.sh
|
||||
/mnt/user/appdata/unraid_scripts/Orchestrators/transcode_management.sh
|
||||
```
|
||||
|
||||
Also tracks daily transcode statistics to `/boot/config/transcode_daily.db` — read by `weekly_health_digest.sh` for the weekly report.
|
||||
|
||||
---
|
||||
|
||||
### `transcode_manager.sh`
|
||||
**Called by `transcode_management.sh` — not scheduled directly.**
|
||||
|
||||
Monitors ramdisk usage and manages the symlink direction.
|
||||
|
||||
#### Operating Modes
|
||||
|
||||
Set `TRANSCODE_MANAGER_MODE` in `Master.conf`:
|
||||
@@ -92,22 +130,22 @@ Set `TRANSCODE_MANAGER_MODE` in `Master.conf`:
|
||||
|------|----------|----------|
|
||||
| `smart` | Auto-flips between ramdisk and SSD based on thresholds | Normal operation — default |
|
||||
| `ramdisk` | Always uses ramdisk, never flips to SSD | Light load, guaranteed RAM performance |
|
||||
| `ssd` | Always uses SSD, never uses ramdisk | Ramdisk maintenance, post-flip drain |
|
||||
| `ssd` | Always uses SSD, never uses ramdisk | Maintenance, post-flip drain |
|
||||
|
||||
#### Smart Mode — How the Flip Works
|
||||
|
||||
```
|
||||
Ramdisk usage rises above RAMDISK_WARN_GB (6.8GB)
|
||||
Ramdisk usage rises above RAMDISK_WARN_GB (8.8GB)
|
||||
→ Symlink flips to SSD
|
||||
→ New sessions land on SSD
|
||||
→ Existing sessions continue on ramdisk until they end
|
||||
|
||||
Ramdisk usage drops below RAMDISK_LOW_GB (5.5GB)
|
||||
Ramdisk usage drops below RAMDISK_LOW_GB (6.5GB)
|
||||
→ Symlink flips back to ramdisk
|
||||
→ New sessions land on ramdisk again
|
||||
```
|
||||
|
||||
The gap between `RAMDISK_WARN_GB` and `RAMDISK_LOW_GB` (1.3GB) is the **hysteresis gap**. It prevents the symlink from flip-flopping when usage hovers near the threshold. Without this gap you'd get constant flipping on a busy system.
|
||||
The 2.3GB gap between `RAMDISK_WARN_GB` and `RAMDISK_LOW_GB` is the **hysteresis gap**. It prevents the symlink from flip-flopping when usage hovers near the threshold.
|
||||
|
||||
#### Safety Checks
|
||||
|
||||
@@ -115,11 +153,12 @@ Every run, regardless of mode:
|
||||
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| Ramdisk not mounted | Flip symlink to SSD immediately, notify warning |
|
||||
| SSD path missing | Disable fallback, notify warning. If mode is `ssd` — exit |
|
||||
| Ramdisk not mounted | Flip to SSD immediately, notify warning |
|
||||
| SSD path missing | Disable fallback, notify warning |
|
||||
| Symlink missing | Recreate pointing at ramdisk, notify |
|
||||
| Symlink target gone | Reset to ramdisk, notify |
|
||||
| Permissions drift | Fix silently — `chmod` and `chown` applied every run |
|
||||
| `transcoding-temp` missing from ramdisk | Create it — prevents Emby falling back to SSD |
|
||||
| Permissions drift | Fix silently every run |
|
||||
| Emby not running | Skip threshold checks, verify symlink only |
|
||||
|
||||
#### Session Display
|
||||
@@ -128,163 +167,91 @@ Each run queries the Emby API and shows active streams:
|
||||
|
||||
```
|
||||
━━━ 🎬 Active Emby Sessions ━━━
|
||||
🎬 Total: 7 | 💨 Live TV: 5 | 🔄 Transcoding: 5 | 🏁 Direct: 2
|
||||
🎬 Total: 7 | 💨 Live TV: 5 | 🔄 Transcoding: 5 | 🏁 Direct: 2
|
||||
🔗 Storage: 💨 ramdisk
|
||||
|
||||
🔗 Storage: 💨 ramdisk
|
||||
|
||||
🎬 Gmer4Lfe — MLB: Pirates vs Nationals — Live TV — Transcode
|
||||
🎬 Rebecca — MLB: Pirates vs Nationals — Live TV — Transcode
|
||||
🎬 Sunny — AT&T Sportsnet Pittsburgh — Live TV — Transcode
|
||||
🎬 jaden — TNT — Live TV — Transcode
|
||||
🎬 Mama Bear — Con-Text — TV Show — Direct Stream
|
||||
🎬 Sunny — ABC (WTAE) — Live TV — Transcode
|
||||
🎬 Mama Bear — Cinemax — Live TV — Transcode
|
||||
🎬 Gmer4Lfe — WAN Show — TV Show — Transcode
|
||||
```
|
||||
|
||||
**Split state** is detected and displayed when sessions exist on both ramdisk and SSD simultaneously — this happens naturally when the symlink flips while sessions are in progress:
|
||||
**Split state** is detected and displayed when sessions exist on both ramdisk and SSD simultaneously — normal during a symlink flip:
|
||||
|
||||
```
|
||||
⚠️ Split state — 4 folder(s) on ramdisk / 2 on SSD
|
||||
⚠️ Older sessions remain on original location until they end naturally
|
||||
🔗 Storage: 💨 ramdisk (4) + 💾 SSD (2)
|
||||
```
|
||||
|
||||
> **Why per-session location isn't shown:** Emby's internal transcode folder names don't match the session IDs returned by the API — there is no reliable way to map a specific user to a specific folder. The folder count on each location gives you the picture you need at a glance without false precision.
|
||||
|
||||
#### Flip Frequency Warning
|
||||
|
||||
If the symlink flips `TRANSCODE_FLIP_WARN` or more times in one hour, a notification is sent. This is a signal that `RAMDISK_SIZE` may need to be increased. Real production data from this setup:
|
||||
|
||||
```
|
||||
Normal load (2-3 streams) → ~1.5-2.0GB
|
||||
Busy evening (5-6 streams) → ~3.5-4.5GB
|
||||
Peak (8 streams, live TV) → ~5.2GB
|
||||
Threshold trigger → 6.8GB
|
||||
⚠️ Split state — 4 folder(s) on ramdisk / 2 on SSD
|
||||
🔗 Storage: 💨 ramdisk (4) + 💾 SSD (2)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `transcode_cleanup.sh`
|
||||
**Run every 5 minutes via cron.**
|
||||
**Called by `transcode_management.sh` — not scheduled directly.**
|
||||
|
||||
Removes old inactive transcode files from both ramdisk and SSD. Never deletes files that are currently open by any process.
|
||||
|
||||
```bash
|
||||
# Scheduled as: */5 * * * *
|
||||
/mnt/user/appdata/unraid_scripts/Transcodes/transcode_cleanup.sh
|
||||
```
|
||||
|
||||
#### Deletion Rules
|
||||
|
||||
A file is eligible for deletion only when **all** of these are true:
|
||||
|
||||
1. Older than `TRANSCODE_MAX_AGE` minutes (default: 20 min)
|
||||
**Deletion rules — a file is eligible only when ALL are true:**
|
||||
1. Older than `TRANSCODE_MAX_AGE` minutes
|
||||
2. Not currently open by any process
|
||||
|
||||
#### Performance Design
|
||||
**`transcoding-temp` directory is protected from deletion.** Even when empty, `transcoding-temp` is never removed by cleanup. Deleting it causes Emby to fall back to the SSD version on next session start — this was the root cause of sessions drifting to SSD after a day of operation.
|
||||
|
||||
`lsof` is called **once per location** to build a complete list of open files — not once per file. This is critical on a busy Live TV system where a single location can have thousands of HLS segment files. A per-file `lsof` approach stalls the system under load.
|
||||
|
||||
---
|
||||
|
||||
## Docker Mount — Critical
|
||||
|
||||
Emby must be configured with **one transcode mount only:**
|
||||
|
||||
```
|
||||
Host path: /mnt/ram-transcode/
|
||||
Container path: /ext-ram-transcode
|
||||
```
|
||||
|
||||
**Do NOT add a static SSD transcode path as a second volume mount.**
|
||||
|
||||
If the SSD path is mounted inside the container, Emby can see it as an accessible transcode location and will route sessions there independently of the symlink — completely bypassing the management system. This is not obvious and causes confusing split behavior that is hard to diagnose.
|
||||
|
||||
The symlink handles all routing. One mount is all that's needed.
|
||||
|
||||
> **This was learned in production.** The system worked correctly once the static SSD mount was removed. The symptom was new sessions landing on SSD even when the symlink pointed at ramdisk.
|
||||
|
||||
#### Emergency Manual Flip
|
||||
|
||||
If you need to manually redirect all new transcodes to SSD:
|
||||
|
||||
```bash
|
||||
ln -sfn /mnt/cache/Temp_Storage/Emby/Transcodes /mnt/ram-transcode
|
||||
```
|
||||
|
||||
To flip back to ramdisk:
|
||||
|
||||
```bash
|
||||
ln -sfn /mnt/ramdisk_transcodes /mnt/ram-transcode
|
||||
```
|
||||
|
||||
Existing sessions are unaffected — only new sessions follow the new target.
|
||||
**Performance design:** `lsof` is called once per location to build a complete open file list — not once per file. On a busy Live TV system with thousands of HLS segments this is critical for performance.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
All configuration in `Master.conf` under the `── TRANSCODES ──` section.
|
||||
All configuration in `Master.conf` under `── TRANSCODES ──`:
|
||||
|
||||
```bash
|
||||
# Paths
|
||||
RAMDISK_PATH="/mnt/ramdisk_transcodes" # tmpfs mount point
|
||||
RAMDISK_SIZE="8G" # ceiling — only uses RAM actually needed
|
||||
TRANSCODE_LINK="/mnt/ram-transcode" # symlink — location never changes
|
||||
RAMDISK_PATH="/mnt/ramdisk_transcodes"
|
||||
RAMDISK_SIZE="10G" # bumped from 8G — peak usage ~5.2GB on busy nights
|
||||
TRANSCODE_LINK="/mnt/ram-transcode"
|
||||
TRANSCODE_SSD="/mnt/cache/Temp_Storage/Emby/Transcodes/"
|
||||
|
||||
# Smart mode thresholds
|
||||
RAMDISK_WARN_GB=6.8 # flip to SSD above this
|
||||
RAMDISK_LOW_GB=5.5 # flip back to ramdisk below this
|
||||
RAMDISK_WARN_GB=8.8 # flip to SSD above this — 1.2GB headroom from ceiling
|
||||
RAMDISK_LOW_GB=6.5 # flip back to ramdisk below this — 2.3GB hysteresis gap
|
||||
RAMDISK_SSD_MIN_GB=20 # minimum SSD free space before allowing flip
|
||||
|
||||
# Cleanup
|
||||
TRANSCODE_MAX_AGE=20 # minutes before file eligible for cleanup
|
||||
TRANSCODE_ORPHAN_AGE=30 # minutes for orphaned files
|
||||
|
||||
# Alerts
|
||||
TRANSCODE_FLIP_WARN=3 # notify if symlink flips this many times per hour
|
||||
|
||||
# Permissions
|
||||
TRANSCODE_OWNER="nobody:users"
|
||||
TRANSCODE_CHMOD="755"
|
||||
|
||||
# Mode
|
||||
TRANSCODE_MANAGER_MODE="smart" # smart | ramdisk | ssd
|
||||
|
||||
# Emby check
|
||||
TRANSCODE_CHECK_EMBY=true
|
||||
TRANSCODE_EMBY_CONTAINER="Emby"
|
||||
|
||||
TRANSCODE_DAILY_LOG="/boot/config/transcode_daily.db"
|
||||
TRANSCODE_LOG_RETENTION=90
|
||||
```
|
||||
|
||||
### Sizing the Ramdisk
|
||||
|
||||
The ramdisk is a `tmpfs` — it only uses RAM that is actually needed. `RAMDISK_SIZE` is a ceiling, not a reservation. An 8GB ramdisk that holds 2GB of files only uses 2GB of RAM.
|
||||
`tmpfs` only uses RAM actually needed — `RAMDISK_SIZE` is a ceiling, not a reservation.
|
||||
|
||||
**Rule of thumb for sizing:**
|
||||
- Count your maximum expected concurrent transcoding streams
|
||||
- Multiply by ~0.5-1GB per stream (Live TV HLS streams use more than standard transcodes)
|
||||
- Add 20-30% headroom above your threshold
|
||||
**Production data from this setup:**
|
||||
```
|
||||
Normal load (2-3 streams) → ~1.5-2.0GB
|
||||
Busy evening (5-6 streams) → ~3.5-4.5GB
|
||||
Peak (8 streams, live TV) → ~5.2GB
|
||||
Current ramdisk → 10G with 8.8GB threshold
|
||||
```
|
||||
|
||||
**From production data on this setup:**
|
||||
- 5 Live TV streams + 2 standard = ~4.5GB
|
||||
- 8 streams peak = ~5.2GB
|
||||
- Current ramdisk = 8GB with 6.8GB threshold — comfortable headroom
|
||||
### Sizing Thresholds
|
||||
|
||||
If you regularly hit `TRANSCODE_FLIP_WARN` or see 3+ flips per hour, increase `RAMDISK_SIZE` by 2GB and adjust thresholds accordingly.
|
||||
|
||||
---
|
||||
|
||||
## Sizing Thresholds
|
||||
|
||||
When adjusting `RAMDISK_SIZE`, adjust thresholds to match:
|
||||
When adjusting `RAMDISK_SIZE`, adjust thresholds to match. Keep a 1.5-2.5GB hysteresis gap between WARN and LOW:
|
||||
|
||||
| Ramdisk Size | RAMDISK_WARN_GB | RAMDISK_LOW_GB |
|
||||
|-------------|-----------------|----------------|
|
||||
| 6G | 4.8 | 3.5 |
|
||||
| 8G | 6.8 | 5.5 |
|
||||
| 10G | 8.5 | 7.0 |
|
||||
| 12G | 10.0 | 8.5 |
|
||||
|
||||
Keep a 1.0-1.5GB hysteresis gap between WARN and LOW. A gap smaller than this causes flip-flop behavior near the threshold.
|
||||
| 10G | 8.8 | 6.5 |
|
||||
| 12G | 10.5 | 8.5 |
|
||||
|
||||
---
|
||||
|
||||
@@ -292,26 +259,53 @@ Keep a 1.0-1.5GB hysteresis gap between WARN and LOW. A gap smaller than this ca
|
||||
|
||||
| Script | Schedule | Purpose |
|
||||
|--------|----------|---------|
|
||||
| `ramdisk_setup.sh` | At Startup of Array | Create ramdisk and symlink |
|
||||
| `transcode_manager.sh` | `*/3 * * * *` | Monitor usage, manage symlink, display sessions |
|
||||
| `transcode_cleanup.sh` | `*/5 * * * *` | Remove old inactive files |
|
||||
| `ramdisk_setup.sh` | At Startup of Array | Create ramdisk, symlink, transcoding-temp |
|
||||
| `transcode_management.sh` | `*/3 * * * *` | Cleanup then manager — correct order, daily stats |
|
||||
|
||||
`transcode_manager.sh` and `transcode_cleanup.sh` are called by `transcode_management.sh` — do not schedule them separately.
|
||||
|
||||
---
|
||||
|
||||
## Version 2 Roadmap
|
||||
## Troubleshooting
|
||||
|
||||
A future `advanced` mode is planned that allows per-media-type storage routing:
|
||||
**Sessions landing on SSD despite symlink pointing at ramdisk:**
|
||||
|
||||
1. Check Docker mount propagation:
|
||||
```bash
|
||||
docker inspect Emby | grep Propagation
|
||||
# Must show: "shared" not "rprivate"
|
||||
```
|
||||
Fix: Add `--mount type=bind,source=/mnt/ram-transcode,target=/ext-ram-transcode,bind-propagation=shared` to Extra Parameters and restart Emby.
|
||||
|
||||
2. Check `transcoding-temp` exists on ramdisk:
|
||||
```bash
|
||||
ls /mnt/ramdisk_transcodes/
|
||||
# Must show: transcoding-temp/
|
||||
```
|
||||
Fix: `mkdir -p /mnt/ramdisk_transcodes/transcoding-temp && chown nobody:users /mnt/ramdisk_transcodes/transcoding-temp`
|
||||
|
||||
3. Check for duplicate SSD mount in Emby template — remove any static SSD transcode path mapping.
|
||||
|
||||
**`[LOG] Permissions fixed` on every run:**
|
||||
|
||||
Permissions are applied every run regardless — this is by design. If it logs every cycle it means Emby is resetting permissions on write. Not harmful — just informational.
|
||||
|
||||
**Flip count high — 3+ per hour:**
|
||||
|
||||
Ramdisk filling up regularly. Consider increasing `RAMDISK_SIZE` by 2GB and adjusting thresholds accordingly.
|
||||
|
||||
---
|
||||
|
||||
## Emergency Manual Flip
|
||||
|
||||
If you need to manually redirect all new transcodes to SSD:
|
||||
```bash
|
||||
TRANSCODE_MANAGER_MODE="advanced"
|
||||
|
||||
TRANSCODE_FORCE_RAMDISK=(
|
||||
"LiveTv" # always ramdisk — buffering is latency sensitive
|
||||
)
|
||||
TRANSCODE_FORCE_SSD=(
|
||||
"Audio" # music downloads — no benefit from ramdisk
|
||||
)
|
||||
# Everything else follows smart threshold behavior
|
||||
ln -sfn /mnt/cache/Temp_Storage/Emby/Transcodes /mnt/ram-transcode
|
||||
```
|
||||
|
||||
This requires the Emby API to expose media type at session start — the groundwork (session display and media type parsing) is already in place. Target: this fall.
|
||||
To flip back to ramdisk:
|
||||
```bash
|
||||
ln -sfn /mnt/ramdisk_transcodes /mnt/ram-transcode
|
||||
```
|
||||
|
||||
Existing sessions are unaffected. Only new sessions follow the new target.
|
||||
+103
-49
@@ -27,6 +27,15 @@
|
||||
# weekly_health_digest.sh, emby_session_report.sh added
|
||||
# ZFS memory snapshot moved to Monitors/ — informational only
|
||||
# Directory tree updated to reflect full ecosystem
|
||||
# v1.9 — transcode_management.sh added to Orchestrators/
|
||||
# replaces separate transcode_manager and transcode_cleanup cron entries
|
||||
# Tools/ folder expanded with all utility scripts
|
||||
# Docker watchdog — two-tier monitoring, startup grace, dependency ordering
|
||||
# Failover — tiered failover, DDNS management, handback sequence
|
||||
# Emby Docker mount fix — bind-propagation=shared required in Extra Parameters
|
||||
# transcode_cleanup.sh — transcoding-temp protected from directory deletion
|
||||
# ramdisk_setup.sh — creates transcoding-temp on ramdisk at array start
|
||||
# RAMDISK_SIZE bumped to 10G, thresholds updated
|
||||
# ==============================================================================================
|
||||
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
@@ -37,50 +46,64 @@
|
||||
# ├── Master.conf # All user configuration — edit this file only
|
||||
# ├── common.sh # Shared library — functions used by all scripts
|
||||
# ├── README.md # Project overview and quick start
|
||||
# ├── User_Script_Template.sh # This file — copy into User Scripts plugin
|
||||
# ├── user_script_plug-in.sh # This file — copy into User Scripts plugin
|
||||
# ├── git_pull_execute.sh # Pulls latest scripts from Gitea repo
|
||||
# │
|
||||
# ├── Failover/
|
||||
# │ ├── failover.sh # Mutual container failover — runs continuously
|
||||
# │ └── failover_test.sh # Controlled failover simulation — run manually
|
||||
# │ ├── failover_test.sh # Controlled failover simulation — run manually
|
||||
# │ └── README-Failover.md
|
||||
# │
|
||||
# ├── Monitors/
|
||||
# │ ├── backup_verify.sh # Random sample checksum verification vs remote
|
||||
# │ ├── bandwidth_monitor.sh # Daily transfer logging + weekly summary
|
||||
# │ ├── cert_monitor.sh # SSL certificate expiry — direct openssl check
|
||||
# │ ├── emby_session_report.sh # Weekly Emby usage statistics via API
|
||||
# │ ├── smart_health.sh # Drive SMART attribute monitoring
|
||||
# │ ├── bandwidth_monitor.sh # Daily transfer logging + weekly summary
|
||||
# │ ├── weekly_health_digest.sh # Aggregated system health — always/smart/weekly
|
||||
# │ └── zfs_memory_snapshot.sh # Weekly ZFS health and memory diagnostic report
|
||||
# │ ├── zfs_memory_snapshot.sh # Weekly ZFS health and memory diagnostic report
|
||||
# │ └── README-Monitors.md
|
||||
# │
|
||||
# ├── Orchestrators/
|
||||
# │ ├── daily_sync.sh # Runs all daily media share syncs sequentially
|
||||
# │ └── media_management.sh # Runs permissions + cleaners + arr cleanup sequentially
|
||||
# │ ├── media_management.sh # Runs permissions + cleaners + arr cleanup
|
||||
# │ ├── transcode_management.sh # Runs cleanup then manager every 3min + daily stats
|
||||
# │ └── README-Orchestrators.md
|
||||
# │
|
||||
# ├── Rsync/
|
||||
# │ ├── rsync.sh # Core rsync script — called per share or profile
|
||||
# │ └── README_Rsync_Setup.md # Rsync-specific setup guide
|
||||
# │ └── README-Rsync_Setup.md # Rsync-specific setup guide
|
||||
# │
|
||||
# ├── Docker_Essentials/
|
||||
# │ ├── docker_watchdog.sh # Container health monitor — memory, CPU, HTTP, stops
|
||||
# │ ├── docker_watchdog.sh # Two-tier container health monitor — self-healing
|
||||
# │ ├── docker_daily_restart.sh # Restarts configured containers daily
|
||||
# │ ├── docker_weekly_restart.sh # Restarts configured containers weekly
|
||||
# │ └── docker_network_connect.sh # Connects containers to extra networks on boot
|
||||
# │ ├── docker_network_connect.sh # Connects containers to extra networks on boot
|
||||
# │ └── README-Docker_Essentials.md
|
||||
# │
|
||||
# ├── Media/
|
||||
# │ ├── media_shares_permissions.sh # Applies permissions to all media shares
|
||||
# │ ├── media_cleaner.sh # Removes junk files — profiles: anime, media
|
||||
# │ ├── lidarr_cleanup.sh # Removes orphaned music files via Lidarr API
|
||||
# │ ├── sonarr_cleanup.sh # Removes orphaned TV files via Sonarr API
|
||||
# │ └── radarr_cleanup.sh # Removes orphaned movie files via Radarr API
|
||||
# │ ├── radarr_cleanup.sh # Removes orphaned movie files via Radarr API
|
||||
# │ └── README-Media.md
|
||||
# │
|
||||
# ├── Transcodes/
|
||||
# │ ├── ramdisk_setup.sh # Creates ramdisk and transcode symlink
|
||||
# │ ├── ramdisk_setup.sh # Creates ramdisk, symlink, and transcoding-temp
|
||||
# │ ├── transcode_manager.sh # Monitors ramdisk usage, manages symlink
|
||||
# │ └── transcode_cleanup.sh # Removes old inactive transcode files
|
||||
# │ ├── transcode_cleanup.sh # Removes old inactive transcode files
|
||||
# │ └── README-Transcoding.md
|
||||
# │
|
||||
# ├── Tools/
|
||||
# │ └── recreate_shares.sh # Recreates share dirs from .cfg files after incident
|
||||
# │ ├── bulk_permissions_repair.sh # Targeted permission repair for one share
|
||||
# │ ├── container_data_export.sh # Export container appdata to tar archive
|
||||
# │ ├── emby_database_repair.sh # SQLite integrity check on Emby databases
|
||||
# │ ├── failover_state_reset.sh # Reset failover state file to NORMAL
|
||||
# │ ├── recreate_shares.sh # Recreates share dirs from .cfg files after incident
|
||||
# │ ├── watchdog_skip_list_manager.sh # Manage container watchdog skip lists
|
||||
# │ ├── zfs_pool_scrub.sh # Trigger ZFS scrub with completion report
|
||||
# │ └── README-Tools.md
|
||||
# │
|
||||
# └── unRAID_Essentials/
|
||||
# ├── clear_logs.sh # Clears unRAID system and Docker log files
|
||||
@@ -91,14 +114,30 @@
|
||||
# ├── server_reboot.sh # Graceful server reboot with user warning
|
||||
# ├── system_watchdog.sh # System health monitor — last line of defense
|
||||
# ├── user_scripts_stop.sh # Stops running User Scripts plugin jobs
|
||||
# └── webgui_restart.sh # WebGUI watchdog — nginx + emhttp restart
|
||||
# ├── webgui_restart.sh # WebGUI watchdog — nginx + emhttp restart
|
||||
# └── README-Unraid_Essentials.md
|
||||
#
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
# ━━━ ⚠️ Critical Setup Notes ━━━
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#
|
||||
# EMBY TRANSCODE DOCKER MOUNT — MUST USE EXTRA PARAMETERS:
|
||||
# Do NOT add /mnt/ram-transcode as a standard path mapping in the Emby template.
|
||||
# Standard bind mounts use rprivate propagation — Docker locks the mount inode on
|
||||
# the first symlink flip and new sessions land on SSD permanently for that run.
|
||||
#
|
||||
# In Emby Extra Parameters add:
|
||||
# --mount type=bind,source=/mnt/ram-transcode,target=/ext-ram-transcode,bind-propagation=shared
|
||||
#
|
||||
# shared propagation means host symlink changes are visible inside the container
|
||||
# in real time — symlink flips work correctly for the lifetime of the container.
|
||||
#
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
# ━━━ 🚀 Script Commands — Uncomment the one you want to run ━━━
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#
|
||||
# ━━━ Failover (README) ━━━
|
||||
# Runs continuously as background task — set "At Startup of Array" as background task.
|
||||
# ━━━ Failover ━━━
|
||||
# Runs continuously as background task — set schedule to "At Startup of Array (Background)".
|
||||
# Both servers must have this running for mutual failover to work.
|
||||
#
|
||||
#/mnt/user/appdata/unraid_scripts/Failover/failover.sh
|
||||
@@ -106,23 +145,23 @@
|
||||
# ━━━ Failover Test ━━━
|
||||
# Run manually during a maintenance window — starts and stops real containers.
|
||||
# Always --dry-run first to walk through phases without making changes.
|
||||
# Both servers must have failover.sh running before testing.
|
||||
#
|
||||
#/mnt/user/appdata/unraid_scripts/Failover/failover_test.sh --dry-run
|
||||
#/mnt/user/appdata/unraid_scripts/Failover/failover_test.sh
|
||||
#
|
||||
# ━━━ Monitors ━━━
|
||||
#/mnt/user/appdata/unraid_scripts/Monitors/backup_verify.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Monitors/bandwidth_monitor.sh --report
|
||||
#/mnt/user/appdata/unraid_scripts/Monitors/cert_monitor.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Monitors/emby_session_report.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Monitors/smart_health.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Monitors/bandwidth_monitor.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Monitors/weekly_health_digest.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Monitors/zfs_memory_snapshot.sh
|
||||
#
|
||||
# ━━━ Orchestrators ━━━
|
||||
#/mnt/user/appdata/unraid_scripts/Orchestrators/daily_sync.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Orchestrators/media_management.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Orchestrators/transcode_management.sh
|
||||
#
|
||||
# ━━━ Rsync — Appdata Profiles ━━━
|
||||
#/mnt/user/appdata/unraid_scripts/Rsync/rsync.sh /mnt/user/appdata-Failover/Arrs_Stack
|
||||
@@ -153,12 +192,23 @@
|
||||
#/mnt/user/appdata/unraid_scripts/Docker_Essentials/docker_network_connect.sh
|
||||
#
|
||||
# ━━━ Transcodes ━━━
|
||||
# transcode_management.sh replaces separate manager and cleanup cron entries.
|
||||
# ramdisk_setup.sh runs once at array start — separate User Script entry.
|
||||
#
|
||||
#/mnt/user/appdata/unraid_scripts/Transcodes/ramdisk_setup.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Transcodes/transcode_manager.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Transcodes/transcode_cleanup.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Orchestrators/transcode_management.sh
|
||||
#
|
||||
# ━━━ Tools ━━━
|
||||
#/mnt/user/appdata/unraid_scripts/Tools/bulk_permissions_repair.sh /mnt/user/ShareName
|
||||
#/mnt/user/appdata/unraid_scripts/Tools/container_data_export.sh ContainerName /path/to/appdata /path/to/output
|
||||
#/mnt/user/appdata/unraid_scripts/Tools/emby_database_repair.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Tools/failover_state_reset.sh --status
|
||||
#/mnt/user/appdata/unraid_scripts/Tools/failover_state_reset.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Tools/recreate_shares.sh
|
||||
#/mnt/user/appdata/unraid_scripts/Tools/watchdog_skip_list_manager.sh --status
|
||||
#/mnt/user/appdata/unraid_scripts/Tools/watchdog_skip_list_manager.sh --clear ContainerName
|
||||
#/mnt/user/appdata/unraid_scripts/Tools/watchdog_skip_list_manager.sh --clear-all
|
||||
#/mnt/user/appdata/unraid_scripts/Tools/zfs_pool_scrub.sh
|
||||
#
|
||||
# ━━━ unRAID Essentials ━━━
|
||||
#/mnt/user/appdata/unraid_scripts/unRAID_Essentials/clear_logs.sh
|
||||
@@ -187,51 +237,55 @@
|
||||
# KEY=VALUE Override any Master.conf variable for this run only
|
||||
#
|
||||
# ━━━ Special arguments ━━━
|
||||
# failover.sh --status — check current state without restarting loop
|
||||
# failover.sh --dry-run --log — test logic without touching containers
|
||||
# media_cleaner.sh anime --dry-run — profile required as first argument
|
||||
# bandwidth_monitor.sh --report — generate weekly summary report
|
||||
# lidarr/sonarr/radarr --dry-run --log — always test arr cleanup first
|
||||
# failover.sh --status — check current state without restarting loop
|
||||
# failover.sh --dry-run --log — test logic without touching containers
|
||||
# media_cleaner.sh anime --dry-run — profile required as first argument
|
||||
# bandwidth_monitor.sh --report — generate weekly summary report
|
||||
# lidarr/sonarr/radarr --dry-run --log — always test arr cleanup before running live
|
||||
# transcode_management.sh --dry-run — passes through to both child scripts
|
||||
# watchdog_skip_list_manager.sh --status — view skip list and restart history
|
||||
# watchdog_skip_list_manager.sh --clear Name — clear specific container
|
||||
# failover_state_reset.sh --status — view current failover state file
|
||||
#
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
# ━━━ 📋 Recommended Schedules ━━━
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#
|
||||
# ━━━ At Startup of Array ━━━
|
||||
# failover.sh — background task
|
||||
# ramdisk_setup.sh
|
||||
# docker_network_connect.sh
|
||||
# docker_syslog_filter.sh
|
||||
# php_fpm_max_children.sh
|
||||
# failover.sh — background task (continuous loop)
|
||||
# ramdisk_setup.sh — creates ramdisk before Emby starts
|
||||
# docker_network_connect.sh — connect containers to extra networks
|
||||
# docker_syslog_filter.sh — suppress veth noise before logs fill
|
||||
# php_fpm_max_children.sh — WebGUI performance tuning
|
||||
#
|
||||
# ━━━ Frequent (every few minutes) ━━━
|
||||
# */3 * * * * transcode_manager.sh
|
||||
# */5 * * * * transcode_cleanup.sh
|
||||
# */10 * * * * webgui_restart.sh
|
||||
# */15 * * * * docker_watchdog.sh
|
||||
# */15 * * * * system_watchdog.sh
|
||||
# ━━━ Frequent (cron) ━━━
|
||||
# */3 * * * * transcode_management.sh (replaces separate manager + cleanup entries)
|
||||
# */10 * * * * webgui_restart.sh
|
||||
# */15 * * * * docker_watchdog.sh
|
||||
# */15 * * * * system_watchdog.sh
|
||||
#
|
||||
# ━━━ Daily ━━━
|
||||
# 0 1 * * * daily_sync.sh
|
||||
# 0 2 * * * media_management.sh
|
||||
# 0 3 * * * docker_daily_restart.sh
|
||||
# 0 8 * * * weekly_health_digest.sh (profile controls if it sends)
|
||||
# 0 1 * * * daily_sync.sh
|
||||
# 0 2 * * * media_management.sh
|
||||
# 0 3 * * * docker_daily_restart.sh
|
||||
# 0 8 * * * weekly_health_digest.sh (profile controls if it sends)
|
||||
#
|
||||
# ━━━ Weekly — Sunday morning block ━━━
|
||||
# 0 3 * * 0 docker_weekly_restart.sh
|
||||
# 0 5 * * 0 clear_logs.sh
|
||||
# 0 6 * * 0 zfs_memory_snapshot.sh
|
||||
# 0 7 * * 0 smart_health.sh
|
||||
# 0 8 * * 0 weekly_health_digest.sh (weekly profile sends today)
|
||||
# 0 9 * * 0 cert_monitor.sh
|
||||
# 0 10 * * 0 backup_verify.sh
|
||||
# 0 11 * * 0 emby_session_report.sh
|
||||
# 0 3 * * 0 docker_weekly_restart.sh
|
||||
# 0 5 * * 0 clear_logs.sh
|
||||
# 0 6 * * 0 zfs_memory_snapshot.sh
|
||||
# 0 7 * * 0 smart_health.sh
|
||||
# 0 8 * * 0 weekly_health_digest.sh (weekly profile sends today)
|
||||
# 0 9 * * 0 cert_monitor.sh
|
||||
# 0 10 * * 0 backup_verify.sh
|
||||
# 0 11 * * 0 emby_session_report.sh
|
||||
# 0 11 * * 0 bandwidth_monitor.sh --report
|
||||
#
|
||||
# ━━━ Rsync profiles ━━━
|
||||
# Schedule individually as needed
|
||||
# Schedule individually based on how frequently appdata needs syncing
|
||||
#
|
||||
# ━━━ Bandwidth monitor ━━━
|
||||
# bandwidth_monitor.sh --log-transfer is called automatically by rsync.sh
|
||||
# bandwidth_monitor.sh --log-transfer called automatically by rsync.sh
|
||||
# bandwidth_monitor.sh --report runs standalone for weekly summary
|
||||
#
|
||||
# ==============================================================================================
|
||||
Reference in New Issue
Block a user