Redash のクエリー結果が自動的にクリーンアップされない場合があるので調査しました
きっかけはこちらの投稿です。フォーラムへの投稿ありがとうございます!
遅くなってしまいましたが、私の理解も改めるきっかけになったので調査結果を残しておきます。
現象
Redash のクエリーが自動的にクリーンアップされる設定をしているにも関わらず、ディスク容量が開放されないとのことでした。
当初の私は、一度にクリーンアップする結果の数を指定する QUERY_RESULTS_CLEANUP_COUNT
と、クリーンアップ対象の結果のオフセット(日単位)を指定する QUERY_RESULTS_CLEANUP_MAX_AGE
の設定によっては、クリーンアップが遅れたり、自動実行されているクエリーが大量に存在する場合は、クリーンアップが追いつかずに結果が溜まってしまうのかと思っていましたが、どうやら違う原因もあるようでした。
調査内容
調査には安定版の v8.0.0
を使用しました。
クリーンアップに関わるコードを追っていく
クエリー結果のクリーンアップは Celery のタスクで実行されており、以下にタスクが定義されています。
https://github.com/getredash/redash/blob/v8.0.0/redash/tasks/queries.py#L235
クリーンアップ対象のクエリー結果は、以下のコードで取得しています。
unused_query_results = models.QueryResult.unused(settings.QUERY_RESULTS_CLEANUP_MAX_AGE).limit(settings.QUERY_RESULTS_CLEANUP_COUNT)
ここで呼び出されている models.QueryResult
クラスの unused
メソッドは以下のように定義されています。
Redash のコードやメタデータの定義に詳しい方は、このコードを見た時点で気になることが見つかるかもしれません。
https://github.com/getredash/redash/blob/v8.0.0/redash/models/__init__.py#L266
unused メソッドの中で実行されている SQL
unused
メソッドで実行されている SQL を見てみると、以下のようになっていました。
SELECT query_results.id AS query_results_id FROM query_results LEFT OUTER JOIN queries ON query_results.id = queries.latest_query_data_id WHERE queries.id IS NULL AND query_results.retrieved_at < %(retrieved_at_1)s LIMIT %(param_1)s
参考として、Redash のメタデータの queries
と query_results
のテーブル定義を紹介しておきます。
Table "public.queries" Column | Type | Modifiers ----------------------+--------------------------+------------------------------------------------------ updated_at | timestamp with time zone | not null created_at | timestamp with time zone | not null id | integer | not null default nextval('queries_id_seq'::regclass) version | integer | not null org_id | integer | not null data_source_id | integer | latest_query_data_id | integer | name | character varying(255) | not null description | character varying(4096) | query | text | not null query_hash | character varying(32) | not null api_key | character varying(40) | not null user_id | integer | not null last_modified_by_id | integer | is_archived | boolean | not null is_draft | boolean | not null schedule | text | schedule_failures | integer | not null options | text | not null search_vector | tsvector | tags | character varying[] | Table "public.query_results" Column | Type | Modifiers ----------------+--------------------------+------------------------------------------------------------ id | integer | not null default nextval('query_results_id_seq'::regclass) org_id | integer | not null data_source_id | integer | not null query_hash | character varying(32) | not null query | text | not null data | text | not null runtime | double precision | not null retrieved_at | timestamp with time zone | not null
SQL とテーブル定義を読み解くと。queries
テーブルの last_modified_by_id
で参照されていない、かつ、retrieved_at
が指定の日時(現在時刻 - 環境変数で指定したオフセット)より古い query_results
の id
を抽出しているということがわかります。
ここだけ見ると、クリーンアップ対象となるクエリーを抽出できていそうにみえますが、この SQL ではクリーンアップ対象として取得できないクエリー結果が残ってしまいます。
どんなクエリー結果が残ってしまうのか
前述の SQL でクリーンアップ対象として取得できないクエリー結果は「アーカイブされたクエリーのクエリー結果」となります。
Redash のクエリーはアーカイブという状態をもっており、queries
テーブルの is_archived
が true
のものはアーカイブ状態として扱われています。
ここで先程のクエリーを見直してみると、latest_query_data_id
の関連やクエリー結果の取得日時は条件として指定されていますが、クエリーがアーカイブされているものは考慮されていないため、アーカイブされたクエリーが最後に取得した結果 はクリーンアップされず延々と残ってしまいます。
この挙動が意図的なものかどうかはわかりませんが、アーカイブされたクエリー結果もクリーンアップするためには、クエリーのアーカイブ処理やクリーンアップ処理周りの修正が必要になると思われます。
残ってしまったクエリー結果をどうするか
アーカイブしたクエリー結果が残ってしまった場合、設定などで簡単に回避できるものではないため、運用に影響がない場合はそのままにするのが良いと考えています。