Перейти к основному содержанию

OwnCloud — долгая синхронизация файлов

Owncloud

Сегодня у нас продолжение истории с синхронизацией файлов в OwnCloud. Для NextCloud тоже подойдёт.

OwnCloud — это свободное и открытое веб-приложение для синхронизации данных и совместной работы с файлами в стиле Dropbox. Замечательный инструмент для создания личного, семейного или корпоративного файлового хранилища.

Ранее я уже решал проблему с синхронизацией файлов:

OwnCloud не синхронизирует файлы

Проблема была решена синхронизацией файлов для всех пользователей через cron:

0  7,19  *  *  * /usr/bin/php -f /var/www/owncloud/occ files:scan --all

Синхронизация перестала работать с ошибкой:

Lost connection to LDAP server

В голову пришла простая идея, получить список пользователей и по каждому из них отдельно запустить синхронизацию.

OwnCloud при синхронизации файлов теряет соединение с LDAP

0  7,19  *  *  * /usr/bin/php -f /var/www/owncloud/occ user:home:list-users /var/www/owncloud/data/ | sed 's/^ *- //' | xargs -I {} /usr/bin/php -f /var/www/owncloud/occ files:scan {}

Какое-то время всё работало. Затем, файлов стало больше и всплыла новая проблема.

Exception during scan: Doctrine\DBAL\Exception\LockWaitTimeoutException: An exception occurred while executing 'UPDATE `oc_filecache` SET `size`=? WHERE (`size` <> ? OR `size` IS NULL) AND `fileid` = ? ' with params [1000025263, 1000025263, "741856865"]:

SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction

Оказалось, что скрипт работал долго и cron запускал второй экземпляр, затем третий. Эти экземпляры создавали нагрузку на БД и конфликтовали друг с другом. Пришлой уйти от однострочника и переделать всё это на bash скрипт.

В кроне под www-data запускаем (у вас свои временные метки, хоть каждый час):

0  7,19  *  *  * /opt/cron/owncloud_scan.sh 2>/var/log/owncloud/cron_errors.log

Для ошибок создаём файл /var/log/owncloud/cron_errors.log, для логов: /var/log/owncloud/owncloud_scan.log. И делаем скрипт /opt/cron/owncloud_scan.sh:

#!/bin/bash

# Конфигурация
LOG_FILE="/var/log/owncloud/owncloud_scan.log"
OWNCLOUD_PATH="/var/www/owncloud"
REQUIRED_USER="www-data"
LOCK_FILE="/tmp/owncloud_scan.lock"

# Функция для логирования с временной меткой
log() {
   echo "$(date '+%Y-%m-%d %H:%M:%S'): $1" >> "$LOG_FILE"
}

# Проверяем, запущен ли скрипт от правильного пользователя
if [ "$(whoami)" != "$REQUIRED_USER" ]; then
   echo "Ошибка: Этот скрипт должен запускаться от пользователя $REQUIRED_USER" >&2
   echo "Используйте: sudo -u $REQUIRED_USER $0" >&2
   exit 1
fi

# Создаем директорию для логов, если её нет
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || {
   echo "Ошибка: Не удалось создать директорию для логов" >&2
   exit 1
}

# ПРОВЕРКА ЧЕРЕЗ LOCK ФАЙЛ
if [ -f "$LOCK_FILE" ]; then
   # Читаем PID из lock файла
   LOCK_PID=$(cat "$LOCK_FILE" 2>/dev/null)

   # Проверяем, существует ли процесс с этим PID
   if [ -n "$LOCK_PID" ] && kill -0 "$LOCK_PID" 2>/dev/null; then
       # Проверяем, что это действительно наш скрипт
       # (проверяем по имени скрипта в командной строке процесса)
       if ps -p "$LOCK_PID" -o cmd= 2>/dev/null | grep -q "owncloud_scan"; then
           log "Скрипт уже запущен (PID: $LOCK_PID). Пропускаем выполнение."
           exit 0
       else
           # Это не наш процесс, удаляем устаревший lock файл
           rm -f "$LOCK_FILE"
       fi
   else
       # Процесс не существует, удаляем устаревший lock файл
       rm -f "$LOCK_FILE"
   fi
fi

# Создаем lock файл с PID текущего процесса
echo $$ > "$LOCK_FILE"

# Функция для очистки lock файла при выходе
cleanup() {
   rm -f "$LOCK_FILE"
}

# Устанавливаем обработчики для гарантированного удаления lock файла
trap cleanup EXIT
trap cleanup INT TERM

log "Начало сканирования"

# Проверяем наличие occ
if [ ! -f "$OWNCLOUD_PATH/occ" ]; then
   log "Ошибка: Файл $OWNCLOUD_PATH/occ не найден"
   exit 1
fi

# Проверяем наличие data директории
if [ ! -d "$OWNCLOUD_PATH/data" ]; then
   log "Ошибка: Директория $OWNCLOUD_PATH/data не найдена"
   exit 1
fi

"/usr/bin/php" -f "$OWNCLOUD_PATH/occ" system:cron

# Получаем список пользователей
#USERS=$("/usr/bin/php" -f "$OWNCLOUD_PATH/occ" user:home:list-users "$OWNCLOUD_PATH/data/" | sed 's/^ *- //' 2>/dev/null)
USERS=$("/usr/bin/php" -f "$OWNCLOUD_PATH/occ" user:list -a enabled -a backend | grep -A2 "backend: LDAP" | grep -B1 "enabled: true" | grep -v "^--$" | grep -v "enabled:" | sed 's/^ *- //' | sed 's/:$//' | grep -vE "исключение1|исключение2|исключение3" 2>/dev/null)

if [ -z "$USERS" ]; then
   log "Не найдено пользователей для сканирования"
   exit 0
fi

# Сканируем файлы каждого пользователя
while read -r user; do
   if [ -n "$user" ]; then
       log "Сканирование пользователя: $user"
       "/usr/bin/php" -f "$OWNCLOUD_PATH/occ" files:scan "$user" >> "$LOG_FILE" 2>&1
       SCAN_RESULT=$?
       if [ $SCAN_RESULT -ne 0 ]; then
           log "Ошибка при сканировании пользователя $user (код: $SCAN_RESULT)"
       fi
   fi
done <<< "$USERS"

log "Сканирование завершено"
exit 0

Неделя — полёт нормальный.

Обновление

Добавил еще один вариант выбора списка пользователей, не заблокированных, только LDAP.

USERS=$("/usr/bin/php" -f "$OWNCLOUD_PATH/occ" user:list -a enabled -a backend | grep -A2 "backend: LDAP" | grep -B1 "enabled: true" | grep -v "^--$" | grep -v "enabled:" | sed 's/^ *- //' | sed 's/:$//' | grep -vE "исключение1|исключение2|исключение3" 2>/dev/null)

Теги

 

Похожие материалы

OwnCloud при синхронизации файлов теряет соединение с LDAP

Столкнулся с проблемой, OwnCloud при синхронизации файлов из внешнего хранилища, подключенного по SMB из Windows сервера, получает ошибку: Lost connection to LDAP server.

Теги