Сегодня у нас продолжение истории с синхронизацией файлов в OwnCloud.
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
# Получаем список пользователей
USERS=$("/usr/bin/php" -f "$OWNCLOUD_PATH/occ" user:home:list-users "$OWNCLOUD_PATH/data/" 2>/dev/null | sed 's/^ *- //')
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Неделя — полёт нормальный.
