本記事では、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
