1. きっかけ
先日、株式会社Cominkaの西奥様のこのX投稿を目にしました。
Dify はデータベース上の古いログやストレージ上の未使用のファイルの自動的な削除は 行いません。代わりに、インスタンスの管理者が古いログや未使用のファイルを 手動で 削除できるように、いくつかのコマンドが用意されています。
・・・あら💦そうだったのですね。。
これはイザという時に困るやつだと思い。
とりあえずこの手順をスイスイと実行できるように準備をしておこうと思いました。
2. シェルスクリプトの準備
最近のいつもの如くプロンプトを用意して生成AIに書いてもらいました。
-
対話メニューと、引数で指定すればcrontabにも登録できるようにしました。
-
sudo bash Dify_Delete_old_logs.sh
で実行。 -
Difyのデフォルトのデータベースへのログイン情報(docker-compose.yaml, .env.example)はこちらで確認できます。
2025.7.12版
#!/bin/bash
# =============================================================================
#Dify Log Management Script
# =============================================================================
#初期設定項目
DIFY_DOCKER_PATH="/home/$SUDO_USER/dify/docker"
DAYS=30
BATCH=100
DB_USERNAME="[postgresqlユーザー名]"
DB_PASSWORD="[postgresqlパスワード]"
DB_DATABASE="[postgresqlデータベース名]"
# Docker コマンドの設定(sudo が必要な環境を考慮)
if [ "$EUID" -eq 0 ]; then
DOCKER_CMD="docker"
else
DOCKER_CMD="sudo docker"
fi
# =============================================================================
# 関数定義
# =============================================================================
# テナントIDを取得する関数
get_tenant_ids() {
cd "$DIFY_DOCKER_PATH" || { echo "Error: $DIFY_DOCKER_PATHに移動できません"; exit 1; }
local tenant_output
# 実行時にタイムラグを考慮して2秒待機
sleep 2
tenant_output=$($DOCKER_CMD exec docker-api-1 bash -c "echo 'from models import Tenant; print(db.session.query(Tenant.id, Tenant.name).all()); quit()' | flask shell" 2>/dev/null | grep "('" | awk -F"'" '{print $2}')
if [ -z "$tenant_output" ]; then
echo "Error:テナントIDを取得できませんでした"
exit 1
fi
echo "$tenant_output"
}
# 古いログを削除する関数
delete_old_logs() {
echo "=== 古いログを削除しています ==="
# テナントIDを1回のみ変数へ格納
tenant_ids=$(get_tenant_ids | head -n 1)
if [ -z "$tenant_ids" ]; then
echo "Error: テナントIDが取得できませんでした"
return 1
fi
cd "$DIFY_DOCKER_PATH" || { echo "Error:$DIFY_DOCKER_PATH に移動できません"; exit 1; }
echo "実行コマンド: $DOCKER_CMD exec docker-api-1 flask clear-free-plan-tenant-expired-logs --days $DAYS --batch $BATCH --tenant_ids $tenant_ids"
$DOCKER_CMD exec docker-api-1 flask clear-free-plan-tenant-expired-logs --days "$DAYS" --batch "$BATCH" --tenant_ids "$tenant_ids"
if [ $? -eq 0 ]; then
echo "古いログの削除が完了しました"
else
echo "Error: 古いログの削除に失敗しました"
return 1
fi
}
# データベースをVACUUMする関数
vacuum_database(){
echo "=== データベースをVACUUMしています ==="
cd "$DIFY_DOCKER_PATH" || { echo "Error: $DIFY_DOCKER_PATH に移動できません"; exit 1; }
echo "実行コマンド: $DOCKER_CMD exec docker-db-1 bash -c \"PGPASSWORD=$DB_PASSWORD psql -U $DB_USERNAME -d $DB_DATABASE -c 'VACUUM VERBOSE;'\""
$DOCKER_CMD exec docker-db-1 bash -c "PGPASSWORD=$DB_PASSWORD psql -U $DB_USERNAME -d $DB_DATABASE -c 'VACUUM VERBOSE;'"
if [ $? -eq 0 ]; then
echo "データベースのVACUUMが完了しました"
else
echo "Error: データベースのVACUUMに失敗しました"
return 1
fi
}
# Difyを再起動する関数
restart_dify() {
echo "=== Difyを再起動しています ==="
cd "$DIFY_DOCKER_PATH" || { echo "Error: $DIFY_DOCKER_PATH に移動できません"; exit 1; }
echo "Difyを停止中..."
$DOCKER_CMD compose down
if [ $? -eq 0 ]; then
echo "Difyを開始中..."
$DOCKER_CMD compose up -d
if [ $? -eq 0 ]; then
echo "Difyの再起動が完了しました"
else
echo "Error: Difyの開始に失敗しました"
return 1
fi
else
echo "Error: Difyの停止に失敗しました"
return 1
fi
}
# メニューを表示する関数
show_menu() {
echo "=== Difyログ管理メニュー ==="
echo "1. 古いログを削除する"
echo "2. データベース(postgresql)をVACCUMする"
echo "3. Difyの再起動"
echo "4. 終了"
echo
echo -n "選択してください (1-4): "
}
# =============================================================================
# メイン処理
# =============================================================================
# 引数で直接実行する場合
if [ $# -eq 1 ];then
case $1 in
1)
delete_old_logs
;;
2)
vacuum_database
;;
3)
restart_dify
;;
*)
echo "Usage: $0 [1|2|3]"
echo " 1: 古いログを削除する"
echo " 2: データベース(postgresql)をVACCUMする"
echo " 3: Difyの再起動"
exit 1
;;
esac
exit 0
fi
# 対話メニューモード
while true; do
show_menu
read -r choice
case $choice in
1)
delete_old_logs
echo
;;
2)
vacuum_database
echo
;;
3)
restart_dify
echo
;;
4)
echo "終了します"
exit 0
;;
*)
echo "無効な選択です。1-4の数字を入力してください。"
echo
;;
esac
done
3. 動作の様子
実行前には必ずDify環境のバックアップ等を行っておいてください!
※動作の保証は致しかねます。
※ご利用は自己責任でお願いします。
以上です。