人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

時間のかかる処理をwebアプリが稼働している裏で行う方法を教えてください。
Djangoでwebアプリを作っています。下記のような機能を実装したいのですが方法がわかりません。

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

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

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

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

宜しくお願いします。

●質問者: fenrifja
●カテゴリ:ウェブ制作
○ 状態 :終了
└ 回答数 : 4/4件

▽最新の回答へ

1 ● だわかき
●0ポイント

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

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


fenrifjaさんのコメント
だわかきさん 回答ありがとうございます。 >バックグラウンド処理はJavaサーブレットか何かで処理します。 すみません、わたしの質問の仕方の問題かも知れませんが、曖昧過ぎてわかりません。

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

2 ● a-kuma3
●100ポイント

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 を渡した処理が順番に実行されます。


fenrifjaさんのコメント
a-kuma3さん 回答ありがとうございます。 環境も書かないで質問とか有り得なかったですね、お恥ずかしいです。補足として書いておきます。 ローカルPCでVMware上にUbuntuをインストールして開発をしているのですが、リクエストに応じてシェルスクリプトを実行することはできました。これが「外部プロセスの実行が許可されている」にあたるのかはわかりませんが、atコマンド、調べてみます。ありがとうございます。

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

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

3 ● TransFreeBSD
●200ポイント ベストアンサー

プログラムを二つの部分、フロントエンドとバックエンドに分けるという話かと思います。
フロントエンドとバックエンドに分けて処理を行うってのはそれなりにあることですので色々とフレームワークがあります。
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アプリのフレームワークで出来ます。
ただ、処理はセッション毎に平行します。
また、ユーザがページを閉じちゃうと処理は完全に止まります。
そういった不完全なタスクの処理のほか、エラー処理やリカバリ、キャンセル方法なども考えておく必要があります。
#そのあたり、タスクキューで共通の課題だと思います。


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

質問者から

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

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

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


4 ● holoholobird
●0ポイント

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]に一定時間ごとに読み込みを試みて、応答があれば作成完了の表示を行えばいいでしょう。


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

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ