Celery × Django × PostgreSQL統合運用の実践:エラー解析から本番サービス化までの完全ガイド

New Challenge

本記事では、Djangoアプリケーションにおけるバックグラウンド処理基盤として、
Celery・Redis・PostgreSQLを統合し、最終的にsystemdによる本番運用レベルの常駐サービス化に至るまでの一連の流れを、
実際のエラーログとともに詳細に解説します。

単なるチュートリアルではなく、
「なぜそのエラーが起きたのか」「なぜその修正が正しいのか」
という設計思想まで踏み込んで整理します。


1. Celery連携は成功しているのに動かない?エラーの本質を見抜く

Celery・Redis・Djangoの連携はすでに完成していた

まず重要なのは、ログから読み取れる事実です。

Task greeting.tasks.crawl_task[...] received

これはつまり、

  • Django → Celery へのタスク送信成功
  • Redis がブローカーとして機能
  • Worker がタスクを受信

という非同期処理基盤の核心部分が完全に動作していることを意味します。

つまり問題は「非同期処理」ではなく、
データベースとの整合性</strongにあります。

エラーの正体:カラム不一致

ProgrammingError: column "url" of relation "crawled_pages" does not exist

このエラーは極めて重要です。

一見単純な「カラムがない」問題ですが、
本質はもっと深く、

  • Django側の設計
  • Rails由来のDB構造
  • クローラー実装

この3つの設計思想がズレている</strongことに起因しています。


2. RailsとDjangoの衝突:データモデルの非対称性

実際のテーブル構造

あなたのDB構造は以下の通りでした:

  • page_url
  • page_title
  • content
  • visited_at
  • scope
  • created_at
  • updated_at

これは典型的なRails的設計</strongです。

Djangoクローラーとのズレ

一方、crawler.pyは以下を前提としていました:

  • url
  • title
  • http_status
  • depth

つまり、

完全に別のデータモデルを前提にしていた

この時点で、いくらCeleryが正常でも、
DB書き込みは絶対に成功しません。

なぜこの問題が起きるのか

この問題は、以下のような「現実的な開発環境」でよく発生します:

    • Railsで作られた既存DB
    • Djangoで追加機能を実装

<li両者をPostgreSQLで統合

この構成は非常に強力ですが、
ORMの前提が違うため衝突が発生する</strongのです。


3. 正しい修正戦略:DBに合わせるか、コードに合わせるか

選択肢は2つ

この問題の解決方法は2つあります:

  • ① DBを変更する
  • ② コードを変更する

なぜ「コード修正」が正解なのか

今回のケースでは明確に:

crawler.pyを修正するのが正解

理由は以下です:

  • 既存データを破壊しない
  • Rails側との整合性を保つ
  • 運用コストが低い

修正後のINSERT文

INSERT INTO crawled_pages (
    page_url,
    page_title,
    content,
    visited_at,
    scope,
    created_at,
    updated_at
)
VALUES (%s, %s, %s, NOW(), %s, NOW(), NOW());

この修正により、

  • url → page_url
  • title → page_title
  • body → content

というマッピングが成立</strongします。


4. crawler.pyの最終完成形と設計思想

重要なのは「動くコード」ではなく「整合性」

最終的なcrawler.pyは以下の構造になります:

# DB保存
with connection.cursor() as cursor:
    cursor.execute("""
        INSERT INTO crawled_pages (
            page_url,
            page_title,
            content,
            visited_at,
            scope,
            created_at,
            updated_at
        )
        VALUES (%s, %s, %s, NOW(), %s, NOW(), NOW());
    """, [url, title, html, allowed_domain])

count += 1

ここで重要な設計ポイント

  • トランザクションはDjangoが管理
  • SQLは最小限にする
  • Railsの命名規則に従う

つまり、

「フレームワークに合わせる」のではなく「DBに合わせる」

という発想が重要です。


5. Celeryの本番運用:systemdによる常駐化

なぜ手動起動はダメなのか

従来の運用:

celery -A sharedsite worker --loglevel=info

この方法には問題があります:

  • 毎回手動起動が必要
  • サーバー再起動で停止
  • 運用ミスが起きやすい

systemdによる解決

systemdにより、

  • 自動起動
  • 自動再起動
  • ログ管理

が可能になります。

サービスファイルの本質

[Service]
WorkingDirectory=/home/testuser/PJ_django_260319
ExecStart=/home/testuser/PJ_django_260319/.venv/bin/celery -A sharedsite worker --loglevel=info
Restart=always

ここで重要なのは:

  • 仮想環境のパス
  • Djangoプロジェクトのルート
  • 再起動設定

6. systemctl status celery の読み方と評価

理想状態の例

Active: active (running)
Loaded: enabled
Main PID: 37921

あなたの状態の評価

今回の結果は:

完全に理想状態

  • active (running) → 正常稼働
  • enabled → 自動起動OK
  • 複数プロセス → 並列処理OK
  • エラーなし → 安定稼働

これは単なる成功ではなく、

「本番運用レベルの完成状態」

です。


7. 実際に何が完成したのか(全体像)

あなたの環境は今、以下を満たしています:

  • Django(Webアプリ)
  • Celery(非同期処理)
  • Redis(メッセージキュー)
  • PostgreSQL(永続化)
  • systemd(自動運用)

これはつまり:

分散処理対応のバックエンド基盤

が完成したということです。


8. 次に進むべきステップ(発展)

① 定期クロール(Celery Beat)

毎日自動でクローリング

② Flower

タスクの可視化

③ LlamaIndex連携

クロール → ベクトルDB → AI検索

④ 並列最適化

CPUコア数に応じた高速化


まとめ:これは「ただの修正」ではない

今回の一連の流れは、
単なるバグ修正ではありません。

  • 異なるフレームワークの統合
  • データモデルの調整
  • 非同期処理の確立
  • 本番運用化

これらをすべて通過しています。

つまりあなたは今、

「AI・データ収集基盤のコア部分」を構築した

と言えます。

ここから先は、
単なる開発ではなく「システム運用と拡張」のフェーズです。

〆最後に〆

以上、間違い・ご意見は
以下アドレスまでお願いします。
全て返信できていませんが 見ています。
適時、改定をします。

nowkouji226@gmail.com

全体の纏め記事に戻る

タイトルとURLをコピーしました