時間のかかる処理をwebアプリが稼働している裏で行う方法を教えてください。

Djangoでwebアプリを作っています。下記のような機能を実装したいのですが方法がわかりません。

例)サイトマップを自動で生成するwebアプリ
1.ユーザーが「example.comのサイトマップを作れ」とリクエストを送る。
2.サーバーは「リクエストを受け付けました」とレスポンスを返す
3.サイトマップの作成が終わるまで「処理を行っています」という表示を出しておく。
4.裏でexample.comというサイトをスクレイピングしてサイトマップを作る。

仮に、スクレイピングをしてサイトマップを作っていくとしたら膨大な時間がかかると思います。ですので、時間のかかるサイトマップ作成とサイトマップ作成依頼を受領したというレスポンスを切り分けたいと思っています。

また、そのようなリクエストが複数同時に来た場合に、リクエストが来た順に処理したいとも思っています。

自分で調べた限りではCRONの設定をして定期的にサイトマップ作成プログラムを動かすというのが一番近いような気がしますが、リクエストがきたら順次処理していくことを望んでいます。

宜しくお願いします。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2013/07/27 21:52:06
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:TransFreeBSD No.3

回答回数668ベストアンサー獲得回数268

ポイント200pt

プログラムを二つの部分、フロントエンドとバックエンドに分けるという話かと思います。
フロントエンドとバックエンドに分けて処理を行うってのはそれなりにあることですので色々とフレームワークがあります。
djangoだとceleryというのが引っかかりました。
http://celeryproject.org/
http://taichino.com/programming/python-programming/2811
http://yuku-tech.hatenablog.com/entry/20101018/1287391988
タスクキューとかジョブキューってキーワードと検索すると出てきます。

ここまでのものはいらない、使えないということだと簡単なのを自前で作っていく事になると思います。
バックエンドをcronで行うというのもアリですが、cronは分単位ですのでユーザーに待ってもらう処理ではレスポンスが良くないので、この場合、完了通知はメールとかTwitterとかが適していると思います。
あと、フロントエンドとバックエンドの間の通信をどうするかという話もあって、専用のキューサーバというのもありますが、今時ならデータベースを使うのが簡単だと思います。

今回の場合、バックエンドもWebアプリにしていくのもアリでしょう。
ポイントとして、処理はなるべく細切れにしておくといいです。
フロントエンドは処理内容をDBに入れて、ajaxで進捗状況を得ます。
ajaxで進捗状況の問い合わせがある度に細切れの処理を一つこなして何番目の処理が終わったか返します。
必要なデータはセッションと紐つけてDBに入れてやりとりします。
フロントエンドは処理の進捗に合わせてプログレスバーでも表示していきます。
DBアクセスやオーバーヘッドは大きいですが、Webアプリのフレームワークで出来ます。
ただ、処理はセッション毎に平行します。
また、ユーザがページを閉じちゃうと処理は完全に止まります。
そういった不完全なタスクの処理のほか、エラー処理やリカバリ、キャンセル方法なども考えておく必要があります。
#そのあたり、タスクキューで共通の課題だと思います。

id:fenrifja

TransFreeBSDさん

回答ありがとうございます。

django-celeryがまさに期待していたライブラリでした。先ほど動作確認をしまして、特にバグも出ず動いてくれました。まだ使い方がよくわからない部分もありますが、先に進めそうです。

ありがとうございました。

2013/07/27 21:46:34

その他の回答3件)

id:dawakaki No.1

回答回数797ベストアンサー獲得回数122

バックグラウンド処理はJavaサーブレットか何かで処理します。
クライアント側は、Ajaxによる非同期通信で実現できます。
サーバの処理が終わったら、Ajaxでデータを表示すればいいのです。

Ajax 非同期通信して取得したデータを表示する方法。
http://ajax.pgtop.net/article/76993492.html

id:fenrifja

だわかきさん

回答ありがとうございます。

>バックグラウンド処理はJavaサーブレットか何かで処理します。
すみません、わたしの質問の仕方の問題かも知れませんが、曖昧過ぎてわかりません。

2013/07/26 23:17:21
id:dawakaki

サーブレットとJSPの技術的なバックグラウンド
http://otndnld.oracle.co.jp/document/products/ds10g/101202/doc_cd/web/B15632-02/tecbkgnd.html

2013/07/27 10:32:40
id:a-kuma3 No.2

回答回数4973ベストアンサー獲得回数2154

ポイント100pt

cron 云々と言われているので、OS は unix 系ということでよろしい?

Django をよく知らないのですが、外部プロセスの実行は許されているんでしょうか?
もし、許されているなら、at コマンドを使うのがお手軽です。
Man page of AT

at コマンドは、処理をキューイングしてくれます。
時刻の指定ができますが、その時刻に動く保証は無くて、指定された処理を順番に実行します。
例えば、重たい処理をするスクリプト heavy_script.sh があったとして、

% echo "heavy_script.sh A" | at now
% echo "heavy_script.sh B" | at now
% echo "heavy_script.sh C" | at now

と、連続して at コマンドを実行しても、パラメータ A、B、C を渡した処理が順番に実行されます。

他1件のコメントを見る
id:a-kuma3

Ubunts なんですね。

リクエストに応じてシェルスクリプトを実行することはできました。

であれば、ぼくが書いたようなことはできます。

TransFreeBSD さんが書いているように、進行状況やエラーの処理、処理のキャンセルなど、いろいろ考えた方が良いことは多いですが、とりあえずバックグラウンドの処理を、ひとつだけ順番に実行する、ということはできます。
man at を見れば分かりますが、atrm で予約したジョブのキャンセルもできなくはないですが、お世辞にも使い勝手はよくないので、やりたいことに応じて、別のジョブをキューイングできるものを探す、ということになるのかも。

2013/07/27 00:56:19
id:fenrifja

a-kuma3さん

再度の回答ありがとうございます。

今回はTransFreeBSDさんが紹介してくれたライブラリを使うことにしました。平行してシェルスクリプトも勉強している身ですので、a-kuma3さんの回答も参考になりました。

ありがとうございました。

2013/07/27 21:49:59
id:TransFreeBSD No.3

回答回数668ベストアンサー獲得回数268ここでベストアンサー

ポイント200pt

プログラムを二つの部分、フロントエンドとバックエンドに分けるという話かと思います。
フロントエンドとバックエンドに分けて処理を行うってのはそれなりにあることですので色々とフレームワークがあります。
djangoだとceleryというのが引っかかりました。
http://celeryproject.org/
http://taichino.com/programming/python-programming/2811
http://yuku-tech.hatenablog.com/entry/20101018/1287391988
タスクキューとかジョブキューってキーワードと検索すると出てきます。

ここまでのものはいらない、使えないということだと簡単なのを自前で作っていく事になると思います。
バックエンドをcronで行うというのもアリですが、cronは分単位ですのでユーザーに待ってもらう処理ではレスポンスが良くないので、この場合、完了通知はメールとかTwitterとかが適していると思います。
あと、フロントエンドとバックエンドの間の通信をどうするかという話もあって、専用のキューサーバというのもありますが、今時ならデータベースを使うのが簡単だと思います。

今回の場合、バックエンドもWebアプリにしていくのもアリでしょう。
ポイントとして、処理はなるべく細切れにしておくといいです。
フロントエンドは処理内容をDBに入れて、ajaxで進捗状況を得ます。
ajaxで進捗状況の問い合わせがある度に細切れの処理を一つこなして何番目の処理が終わったか返します。
必要なデータはセッションと紐つけてDBに入れてやりとりします。
フロントエンドは処理の進捗に合わせてプログレスバーでも表示していきます。
DBアクセスやオーバーヘッドは大きいですが、Webアプリのフレームワークで出来ます。
ただ、処理はセッション毎に平行します。
また、ユーザがページを閉じちゃうと処理は完全に止まります。
そういった不完全なタスクの処理のほか、エラー処理やリカバリ、キャンセル方法なども考えておく必要があります。
#そのあたり、タスクキューで共通の課題だと思います。

id:fenrifja

TransFreeBSDさん

回答ありがとうございます。

django-celeryがまさに期待していたライブラリでした。先ほど動作確認をしまして、特にバグも出ず動いてくれました。まだ使い方がよくわからない部分もありますが、先に進めそうです。

ありがとうございました。

2013/07/27 21:46:34
id:fenrifja

環境を書いていませんでしたので補足です。

OSはUbuntu Server 12.04で、Apache2.2、Django1.4.1、Python2.7.3でwebアプリケーションを作っています。

引き続き回答を募集します、宜しくお願いします。

id:holoholobird No.4

回答回数574ベストアンサー獲得回数104

http://web-terminal.blogspot.jp/2013/04/php.html
方法の概念のみ説明します。
execはセキュリティ的に取り扱いには十分注意してください。
以下のコードはセキュリティ対策をしていないので、そのままでは使用しないようにしてください。

情報を受け取るecho.php
echo.phpはindex.htmlから送られてきたアドレスをwork.phpに処理させます。

サイトマップ作製に50分かかるとして、一つ目を0:00に行いました。この処理は0:50に完了します。
0:10に2つ目の処理要求が来たら、1つ目と並行してバックグラウンドで処理を行い、この処理は1:00に完了します。
0:20に3つ目の処理要求が来たら、1つ目、2つ目と並行してバックグラウンドで処理を行い、この処理は1:10に完了します。



という感じです。

<?php
$url=$_GET['url'];
exec("nohup php -c '' 'work.php' $url > /dev/null &");
?>


work.php
サイトマップ作成後、データを保存します。

<?php
$url=$argv[1];
//サイトマップ作成
$result=$sitemap_create($url);
//出力データをファイル名$urlで保存
file_put_contents("output/".$url,$result);
?>

index.htmlではecho.phpにurl送信後はjavascriptでhttp://test.com/output/[送ったURL]に一定時間ごとに読み込みを試みて、応答があれば作成完了の表示を行えばいいでしょう。

id:fenrifja

holoholobirdさん

回答ありがとうございます。

サンプルコードまで提示してくれてありがとうございました。今回は
・私がPHPを書いたことがない
・別の方の回答で期待通りの結果が出た
ため、別の方の案を採用することにしました。

2013/07/27 21:51:52

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません