10

了解しました。希望どおりに機能させることができました(ただし、一部/ほとんどの場合、この方法に同意できない場合があります)。以下の推奨事項に従ってFlaskを使用しました。「間違っている」と見なされる可能性のある部分は、404チェックループです。これは適切な設計ではなく、長時間続くと、一部のブラウザで「スクリプトのスタック」エラーが発生します。しかし、私が実行したいスクリプトは、それが問題になるほど長くは続きません。

助けてくれてありがとう。他に何か提案があれば教えてください。

フラスコアプリ:

import threading
import subprocess
import os
import sys
from flask import Flask
from flask import render_template, abort
app = Flask(__name__)
app.debug = True

def run_script():
    theproc = subprocess.Popen([sys.executable, "run_me.py"])
    theproc.communicate()

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/generate')
def generate():
    threading.Thread(target=lambda: run_script()).start()
    return render_template('processing.html')

@app.route('/is_done')
def is_done():
    hfile = "templates\\itworked.html"
    if os.path.isfile(hfile):
        return render_template('itworked.html')
    else:
        abort(404)

if __name__ == "__main__":
    app.run()

processing.html:

<!DOCTYPE html>
<html>
<head>
    <script src="/static/jquery.min.js"></script>
</head>

<body>
<p>Processing...</p>
<script>
    setInterval(function()
    {
        var http = new XMLHttpRequest();
        http.open('HEAD', "is_done", false);
        http.send();
        if (http.status==200)
            window.location.replace("is_done");
    },2000);
</script>
</body>
</html>

元の質問:

私は初心者/中級のPythonプログラマーであり、初心者のWeb開発者ですので、優しくしてください。私が欲しいもの:ユーザーがハイパーリンクをクリックすると、「処理中...」のような中間のWebページに移動します。バックグラウンド(サーバー上)では、このリンクにより、ファイルを処理して新しいWebページを作成するPythonスクリプトがトリガーされます。スクリプトが完了すると、ユーザーは新しく作成されたページにリダイレクトされます。私が持っているもの:処理を実行して新しいページを吐き出すスクリプトがあります。私が理解していないのは、Pythonスクリプトをトリガーし、スクリプトの完了時にリダイレクトをトリガーする方法です。djangoやcgiスクリプトなどのWebフレームワークを見てきました。しかし、私は自分が法案に合うと思うものを何も見つけていません。完全に明白な何かを見逃している可能性が非常に高いので、助けていただければ幸いです。

4

4 に答える 4

8

この問題に取り組む簡単な方法は、Flaskのような単純なWebフレームワークを使用して、システムのWebパーツを構築することです。マジックリンクのリクエストハンドラーで、スクリプトを生成して追跡する必要があります。スクリプトが完了したかどうかを確認し、それをユーザーに中継する簡単な方法は、定期的にajaxリクエストを送信して完了を確認することです。

たとえば、FlaskのWebサイトは次のようになります。

import threading
import subprocess
import uuid
from flask import Flask
from flask import render_template, url_for, abort, jsonify, request
app = Flask(__name__)

background_scripts = {}

def run_script(id):
    subprocess.call(["/path/to/yourscript.py", "argument1", "argument2"])
    background_scripts[id] = True

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/generate')
def generate():
    id = str(uuid.uuid4())
    background_scripts[id] = False
    threading.Thread(target=lambda: run_script(id)).start()
    return render_template('processing.html', id=id)

@app.route('/is_done')
def is_done():
    id = request.args.get('id', None)
    if id not in background_scripts:
        abort(404)
    return jsonify(done=background_scripts[id])

そしてindex.html

<a href="{{ url_for('generate') }}">click me</a>

そしてprocessing.html

<html>
<head>
<script src="/static/jquery.js"></script>
<script>
    function ajaxCallback(data) {
        if (data.done)
            window.location.replace("http://YOUR_GENERATED_PAGE_URL");
        else
            window.setTimeout(function() {
                $.getJSON('{{ url_for('is_done') }}', {id: {{ id }} }, ajaxCallback);
            }, 3000);
    }
    $(document).ready(function(){
        ajaxCallback({done=false});
    });
</script>
</head>
<body>
    Processing...
</body></html>

これは現時点ではすべてテストされていないコードですが、この問題に取り組む方法についてのアイデアが得られることを願っています。また、これは1つのプロセスからページを提供する場合にのみ機能するため、Apacheとmod_wsgiを設定する場合は、プロセスグループにプロセスが1つしかないことを確認してください。

より複雑なソリューションが必要な場合は、メッセージキューなどを確認することをお勧めします。

于 2012-06-05T21:14:25.397 に答える
2

これはおそらく非常に頑丈なソリューションですが、「サーバー上にファイルを作成する」部分を廃止できないと仮定すると、これはWeb開発の「ベストプラクティス」ソリューションと見なされます。

ページを提供するには、FlaskやDjangoなどのWebフレームワークを使用します。ユーザーがリクエストを介してジョブの開始をリクエストすると(GETリクエストは重大な副作用を引き起こさないため、POSTリクエストが望ましい)、フレームワークはCeleryなどの遅延タスクシステムにメッセージを送信します。次に、ジョブが送信されたことを示すページがユーザーに表示されます。

この時点で、ajaxを使用してサーバーをポーリングし、ジョブがいつ完了したかを確認できますが、通常、これがジョブが完了したかどうかを確認する唯一の方法ではありません。ユーザーが誤ってブラウザーまたはタブを閉じた場合(非常に一般的)など、何らかの理由で接続が中断された場合、労力が無駄になり、ユーザーはプロセスを最初からやり直す必要があります。可能であれば、ユーザーと通信するためのバックアップ方法が必要です。これは、サイトの他の場所に表示されるフラッシュメッセージ、自動化された「ジョブ終了」メール、最近完了したジョブを表示するホームページのボックスなどです。これがどれほど実用的で重要かは、ユーザーがログインしているかどうかと方法によって異なります。作業に時間がかかる/ファイルの作成以外の副作用があるかどうか。

最後に、ユーザーがそのユーザーのジョブ結果に固有のURLを介してページにアクセスできるようにすることができます。そのURLが無期限に有効にならない場合、たとえば、ファイルがタイマーで削除される場合は、必ずユーザーに通知してください。

于 2012-06-06T15:49:41.357 に答える
0

これを行うための2つの簡単な方法:

1)ajaxを使用してサーバーをポーリングします。10秒ごと、または適切と思われる間隔で完了を確認します。たとえば、スクリプトが処理されている間、スクリプトはファイルまたはデータベースに書き込みます。これは、完了率を示し、プロセスを何らかの方法で識別します(複数のスクリプトを同時に実行している場合は、どれがどれであるかを知りたい場合があります)。ボブとスージーのどちらか)。

2)出力バッファリングを無効にし、出力をクライアントにストリーミングします。これは最初のオプションよりも簡単です。基本的に、スクリプトを実行し、その処理中にjavascriptコードを出力して、進行状況インジケーターを更新します。出力バッファリングを無効にするか、手動でバッファをフラッシュする必要があります。そうしないと、クライアントが出力をすぐに受信しない可能性があります(インジケータの更新は、100%に達したときにのみクライアントに表示される場合があります)。実行しているセットアップ(PHP、Djangoなど)でそれを行う方法をGoogleで確認してください。

于 2012-06-05T19:48:17.207 に答える
0

あなたが望むことは可能ですが、それは実際には約3つの問題です。

最初の質問は、PHPから新しいファイルをどのように作成するかです。私はこれに本当に答えることができません。何をする必要があるかは、おそらく作成しようとしているファイルの種類とその理由によって異なります。

2番目の質問は、これが発生していることをユーザーにどのように通知するか、3番目の質問は新しいページにどのようにリダイレクトするかです。

個人的には、勝利への最短ルートは、おそらくクライアント側のJavaScriptに、新しいコンテンツを作成するサーバーページまたはCGIモジュールに対してAJAXリクエストを行わせることだと思います。

  1. ボタンをクリックしたら、新しいコンテンツページを生成するPHPページにajaxリクエストを送信します。
  2. ビジーインジケーターを提示します。
  3. リクエストされたページに、新しいページのURLをコンテンツとして返してもらいます。
  4. リクエストが完了すると、javascriptを介して返されたURLにリダイレクトされます。

Web開発に不慣れな人として、最も簡単なことはjQueryとそのAJAX機能を調べることかもしれません。そこにあるラッパーを使用すると、上記を非常に簡単に実行できます。もちろん、他の主要なjavascriptフレームワークやストレートjavascriptでも同じことができます。

参考のために:

于 2012-06-05T19:54:25.643 に答える