fixed duplicates and slskd crashes, implemented autoheal if containers hangs

This commit is contained in:
2026-07-07 13:58:45 +02:00
parent e7b01dfadd
commit 938da40a45
2 changed files with 81 additions and 34 deletions
+35 -14
View File
@@ -27,6 +27,7 @@ No Spotify. No YouTube Music. No ads. Just your music, your server, your rules.
| **Pangolin** | Reverse proxy — exposes Navidrome securely to the internet |
| **Gluetun** | VPN gateway container — all Soulseek traffic exits via ProtonVPN |
| **slskd** | Soulseek client — searches and downloads music from the P2P network |
| **autoheal** | Watches slskd/gluetun health status and force-restarts them if they hang |
| **Explo** | Discovery engine — connects ListenBrainz recommendations to slskd |
| **ListenBrainz** | Open-source scrobbler + recommendation engine |
| **Last.fm** | Secondary scrobbler for stats and social features |
@@ -55,7 +56,7 @@ No Spotify. No YouTube Music. No ads. Just your music, your server, your rules.
│ └── slskd.yml ← slskd config (copy from repo)
└── explo/
├── .env ← Explo config (copy from .env.example)
└── docker-compose.yml ← Full stack compose file (copy from repo)
└── config/ ← Explo's playlist cache + cover art (auto-populated, must persist)
/mnt/user/data/media/music/
├── incomplete/ ← In-progress downloads (Navidrome ignores these)
@@ -99,7 +100,7 @@ Fill in your ListenBrainz username, Navidrome URL/credentials, and slskd API key
### 3. Create required folders
```bash
mkdir -p /mnt/user/appdata/{gluetun,slskd,explo}
mkdir -p /mnt/user/appdata/{gluetun,slskd,explo/config}
mkdir -p /mnt/user/data/media/music/{explo,incomplete}
```
@@ -134,21 +135,15 @@ Add these environment variables in the Navidrome container template:
| `ND_LASTFM_ENABLED` | `true` |
| `ND_SCANSCHEDULE` | `1m` |
### 7. Set up automation via Unraid User Scripts
### 7. Start Explo and autoheal
Install the **User Scripts** plugin from Community Apps, then add two scripts:
**Weekly Exploration** — Cron: `15 0 * * 2`
```bash
#!/bin/bash
docker compose -f /mnt/user/appdata/explo/docker-compose.yml up explo-weekly
docker compose up -d explo autoheal
```
**Daily Jams** — Cron: `15 0 * * *`
```bash
#!/bin/bash
docker compose -f /mnt/user/appdata/explo/docker-compose.yml up explo-daily
```
Unlike the rest of the stack, Explo doesn't need any external scheduler (no Unraid User Scripts, no cron). It runs continuously and schedules Weekly Exploration and Daily Jams itself via `WEEKLY_EXPLORATION_SCHEDULE` / `DAILY_JAMS_SCHEDULE` in `docker-compose.yml`, and `EXECUTE_ON_START=false` means restarting or updating the container never triggers an extra, out-of-schedule run. This is what keeps it from downloading the same week twice — see [Troubleshooting](#troubleshooting) below for the full explanation.
`autoheal` also just runs continuously in the background; it watches slskd and gluetun and restarts either one automatically if Docker marks it unhealthy.
---
@@ -176,6 +171,32 @@ You discover new music 🎵
---
## Troubleshooting
### slskd hangs and needs a manual restart every ~24h
This was almost always one of two things, both addressed in the current compose file:
- **slskd itself getting stuck** (memory pressure / stuck transfers) — fixed by pinning `slskd/slskd:0.25.1`, which bundles a round of upstream fixes for stuck and failing transfers.
- **gluetun's tunnel silently hanging** — since slskd runs inside gluetun's network namespace, a frozen gluetun looks identical to a frozen slskd. Fixed by pinning `qmcgaw/gluetun:v3.41.1`, which resolves a healthcheck race condition that could make gluetun hang completely.
Both containers already ship a Docker healthcheck, but **Docker does not restart a container just because it's unhealthy** — that gap is why a manual restart was needed. The new `autoheal` service closes it: it watches both containers (via the `autoheal=true` label) and force-restarts whichever one goes unhealthy, with no manual intervention.
If slskd still misbehaves after this, check `docker ps` for its health status and `docker logs slskd`/`docker logs gluetun` before restarting manually.
### Weekly Exploration downloaded multiple times
The old setup ran two one-shot `explo-weekly` / `explo-daily` containers (`restart: "no"`, `EXECUTE_ON_START=true`) that were triggered by an external Unraid User Scripts cron. That design had two compounding problems:
1. Every container restart (a host reboot, a Docker update, the scheduler firing slightly out of sync) re-ran Explo immediately because of `EXECUTE_ON_START=true`, regardless of whether that week's playlist already existed.
2. Explo's playlist cache had nowhere to persist between runs (no `/opt/explo/config` volume), so each fresh container had no memory of "I already built this week's playlist" and would build it again.
The current compose runs a single, always-on `explo` container with its own internal cron (`WEEKLY_EXPLORATION_SCHEDULE` / `DAILY_JAMS_SCHEDULE`), `EXECUTE_ON_START=false`, and a persistent `/opt/explo/config` volume, plus the newer `v1.1.0` image which includes further upstream fixes for scheduled-job bugs. Together this means Explo only ever runs on its own schedule, and remembers what it already did across restarts.
**One-time cleanup:** this fix prevents *future* duplicates, but it won't retroactively merge the duplicate `Weekly-Exploration-2026-WeekXX` playlists already sitting in Navidrome. Delete the extras once, manually, from the Navidrome UI (or via its API) — new runs going forward should stay to one playlist per period.
---
## Tips
- **ListenBrainz needs time** — it takes a few weeks of scrobbling before Weekly Exploration playlists are generated. Speed this up by importing your Google Takeout YouTube Music watch history via [ytm-extractor](https://community.metabrainz.org/t/ytm-extractor-import-youtube-music-listens-to-listenbrainz/707619).
@@ -189,4 +210,4 @@ You discover new music 🎵
## License
MIT — do whatever you want with it.
MIT — do whatever you want with it.
+46 -20
View File
@@ -1,7 +1,6 @@
services:
gluetun:
image: qmcgaw/gluetun:latest
image: qmcgaw/gluetun:v3.41.1
container_name: gluetun
cap_add:
- NET_ADMIN
@@ -14,14 +13,20 @@ services:
- WIREGUARD_ADDRESSES=${WIREGUARD_ADDRESSES}
- SERVER_COUNTRIES=${VPN_COUNTRY:-Switzerland}
- TZ=${TZ:-Europe/Zurich}
- VPN_PORT_FORWARDING=${VPN_PORT_FORWARDING:-off}
- VPN_PORT_FORWARDING_PROVIDER=protonvpn
- PORT_FORWARD_ONLY=${VPN_PORT_FORWARDING:-off}
- VPN_PORT_FORWARDING_STATUS_FILE=/gluetun/forwarded_port
ports:
- 5030:5030
- 8000:8000
volumes:
- ${APPDATA_PATH}/gluetun:/gluetun
restart: unless-stopped
labels:
- autoheal=true
slskd:
image: slskd/slskd:latest
image: slskd/slskd:0.25.1
container_name: slskd
network_mode: "service:gluetun"
depends_on:
@@ -34,27 +39,48 @@ services:
- ${MUSIC_PATH}:/downloads
- ${MUSIC_PATH}:/music:ro
restart: unless-stopped
explo-weekly:
image: ghcr.io/lumepart/explo:latest
container_name: explo-weekly
labels:
- autoheal=true
autoheal:
image: willfarrell/autoheal:latest
container_name: autoheal
restart: unless-stopped
environment:
- EXECUTE_ON_START=true
- AUTOHEAL_CONTAINER_LABEL=autoheal
- AUTOHEAL_INTERVAL=30
- AUTOHEAL_START_PERIOD=120
- AUTOHEAL_DEFAULT_STOP_TIMEOUT=30
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
explo:
image: ghcr.io/lumepart/explo:v1.1.0
container_name: explo
environment:
- TZ=${TZ:-Europe/Zurich}
- WEB_UI=false
- EXECUTE_ON_START=false
- WEEKLY_EXPLORATION_SCHEDULE=15 0 * * 2
- WEEKLY_EXPLORATION_FLAGS=--playlist=weekly-exploration --persist
- WEEKLY_JAMS_SCHEDULE=30 0 * * 1
- WEEKLY_JAMS_FLAGS=--playlist=weekly-jams --persist
- DAILY_JAMS_SCHEDULE=15 1 * * *
- DAILY_JAMS_FLAGS=--playlist=daily-jams --persist
volumes:
- ${APPDATA_PATH}/explo/.env:/opt/explo/.env
- ${APPDATA_PATH}/explo/config:/opt/explo/config
- ${MUSIC_PATH}/explo:/data
- ${MUSIC_PATH}:/slskd
restart: "no"
explo-daily:
image: ghcr.io/lumepart/explo:latest
container_name: explo-daily
restart: unless-stopped
lidarr:
image: lscr.io/linuxserver/lidarr:latest
container_name: lidarr
environment:
- EXECUTE_ON_START=true
- DAILY_JAMS_FLAGS=--playlist=daily-jams --download-mode=skip
- PUID=${PUID:-99}
- PGID=${PGID:-100}
- TZ=${TZ:-Europe/Zurich}
volumes:
- ${APPDATA_PATH}/explo/.env:/opt/explo/.env
- ${MUSIC_PATH}/explo:/data
- ${MUSIC_PATH}:/slskd
restart: "no"
- ${APPDATA_PATH}/lidarr:/config
- ${MUSIC_PATH}:/music
ports:
- 8686:8686
restart: unless-stopped