feat: Multi-Instanz-Support via systemd Template-Unit (v0.2.0)

- pdf-ocr-hotfolder@<name>.service mit Config pro Instanz
- install.sh als Instanz-Manager: erkennt bestehende, fragt nach weiteren
- Optional eigener Service-User pro Instanz (systemd drop-in)
- update.sh stoppt/startet alle aktiven Instanzen automatisch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-08 14:31:58 +02:00
parent 76c3a991df
commit 985a33d3f9
7 changed files with 358 additions and 169 deletions
+40 -18
View File
@@ -2,6 +2,10 @@
#
# PDF OCR Hotfolder — Update-Script
#
# Aktualisiert Code und venv unter /opt/pdf-ocr-hotfolder/ sowie die
# systemd Template-Unit. Danach werden alle laufenden Instanzen neu gestartet.
# Config-Dateien unter /etc/pdf-ocr-hotfolder/ bleiben unverändert.
#
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
@@ -15,7 +19,8 @@ if [ "${EUID}" -ne 0 ]; then
fi
INSTALL_DIR="/opt/pdf-ocr-hotfolder"
SERVICE_NAME="pdf-ocr-hotfolder"
CONFIG_DIR="/etc/pdf-ocr-hotfolder"
SERVICE_TEMPLATE="pdf-ocr-hotfolder@.service"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "$SCRIPT_DIR/pdf_ocr_hotfolder/__init__.py" ]; then
@@ -42,12 +47,18 @@ log_info "Install: $INSTALL_DIR"
log_info "Version: $OLD_VERSION$NEW_VERSION"
echo
# Service-User aus systemd-Unit lesen
SERVICE_USER="$(awk -F= '/^User=/{print $2}' /etc/systemd/system/${SERVICE_NAME}.service 2>/dev/null || echo pdfocr)"
SERVICE_GROUP="$(awk -F= '/^Group=/{print $2}' /etc/systemd/system/${SERVICE_NAME}.service 2>/dev/null || echo pdfocr)"
# Laufende Instanzen ermitteln
mapfile -t RUNNING < <(systemctl list-units --no-legend --state=active 'pdf-ocr-hotfolder@*.service' 2>/dev/null | awk '{print $1}')
if [ "${#RUNNING[@]}" -gt 0 ]; then
log_info "Laufende Instanzen: ${RUNNING[*]}"
else
log_info "Keine laufenden Instanzen."
fi
log_info "Stoppe Service..."
systemctl stop "${SERVICE_NAME}.service" 2>/dev/null || true
log_info "Stoppe laufende Instanzen..."
for unit in "${RUNNING[@]}"; do
systemctl stop "$unit" || true
done
log_info "Backup erstellen..."
BACKUP_DIR="/var/backups/pdf-ocr-hotfolder"
@@ -60,29 +71,40 @@ rm -rf "$INSTALL_DIR/pdf_ocr_hotfolder"
cp -r "$REPO_DIR/pdf_ocr_hotfolder" "$INSTALL_DIR/"
cp "$REPO_DIR/requirements.txt" "$INSTALL_DIR/"
cp "$REPO_DIR/VERSION" "$INSTALL_DIR/"
cp "$REPO_DIR/config.example.toml" "$INSTALL_DIR/"
echo "$REPO_DIR" > "$INSTALL_DIR/.repo_path"
log_info "Dependencies aktualisieren..."
"$INSTALL_DIR/venv/bin/pip" install --upgrade pip -q
"$INSTALL_DIR/venv/bin/pip" install --upgrade -r "$INSTALL_DIR/requirements.txt" -q
log_info "systemd-Unit aktualisieren..."
sed -e "s|__SERVICE_USER__|$SERVICE_USER|g" \
-e "s|__SERVICE_GROUP__|$SERVICE_GROUP|g" \
"$REPO_DIR/systemd/pdf-ocr-hotfolder.service" \
> "/etc/systemd/system/${SERVICE_NAME}.service"
log_info "systemd Template-Unit aktualisieren..."
cp "$REPO_DIR/systemd/$SERVICE_TEMPLATE" "/etc/systemd/system/$SERVICE_TEMPLATE"
systemctl daemon-reload
log_info "Berechtigungen setzen..."
chown -R "$SERVICE_USER:$SERVICE_GROUP" "$INSTALL_DIR"
# Eigentümer des Codes bleibt der primäre User (pdfocr); Instanzen laufen
# ggf. als anderer User, lesen aber nur den Code.
PRIMARY_USER="$(stat -c '%U' "$INSTALL_DIR/venv" 2>/dev/null || echo pdfocr)"
chown -R "$PRIMARY_USER":"$PRIMARY_USER" "$INSTALL_DIR"
log_info "Service starten..."
systemctl start "${SERVICE_NAME}.service"
sleep 2
log_info "Starte Instanzen wieder..."
FAIL=0
for unit in "${RUNNING[@]}"; do
systemctl start "$unit" || true
sleep 1
if systemctl is-active --quiet "$unit"; then
log_info "$unit"
else
log_error "$unit — journalctl -u $unit -n 30"
FAIL=1
fi
done
if systemctl is-active --quiet "${SERVICE_NAME}.service"; then
log_info "✅ Service läuft (Version $NEW_VERSION)"
echo
if [ "$FAIL" -eq 0 ]; then
log_info "Update auf $NEW_VERSION abgeschlossen ✓"
else
log_error "Service läuft nicht. journalctl -u $SERVICE_NAME -n 30"
log_warn "Update abgeschlossen, aber mindestens eine Instanz läuft nicht."
exit 1
fi