8

奇妙な動作をしています。ローカル マシンでは複製できず、気が狂い始めています。

ASP.NET MVC がアクションを実行しようとしているように見えますが、何かがタイムアウトし、例外なく失敗し、ajax クライアントに通知され、アクションを再実行しようとすると、ajax クライアントは応答を取得しますが、元の呼び出しからではありません。

私はコントローラーアクションを持っています:

 [ValidateAntiForgeryToken]
 [ClientErrorHandler]
 public virtual ActionResult PlaceOrder(CheckoutDto checkoutDto)
 {
     LoadDataFromDatabase();

     // this may take up to couple minutes
     var orderConfirmationData = PlaceOrderToExternalWebservice();

     SaveConfirmationData(orderConfirmationData);

     return View(Transform(orderConfirmationData))
 }

そして、jquery ajax を使用して呼び出します。

$.ajax({
                url: placeOrderActionUrl,
                type: "POST",
                async: true,
                dataType: "html",
                data: $('#checkoutForm').serialize(),                    
                success: function (data) {
                   // show confirmation data                       
                },
                error: function (request, status, error) {
                   // show error message
                }
            });

小規模な注文の場合は正常に機能しますが、大規模な注文の場合は 2 つの注文が作成され、その理由は処理時間のようです。注文が大きいほど、外部 Web サービスへの配置に時間がかかります。

IIS ログをチェックして、クライアント スクリプトがアクションを 2 回呼び出していないことを確認しました。IIS ログには、特定のアクションへの呼び出しが 1 回しか表示されません。

外部サービスは失敗しません。イベント ログ/SQL ログに記録される例外はありません。

確認するために、その ajax クライアントは、元の呼び出しからではなく、ロックのようなものを作成しました。

 [ValidateAntiForgeryToken]
 [ClientErrorHandler]
 public virtual ActionResult PlaceOrder(CheckoutDto checkoutDto)
 {
     try 
     {
        if (OrderingLockedForCurrentUser()) 
        {
            Log("Locked");
            return View("Already placing order");
        }

        LockOrderingForCurrentUser();

        LoadDataFromDatabase();

        // this may take up to couple minutes
        var orderConfirmationData = PlaceOrderToExternalWebservice();

        SaveConfirmationData(orderConfirmationData);

        return View(Transform(orderConfirmationData))
     }
     finally 
     {
        RemoveOrderingLockForCurrentUser();
     }
 }

そして、確定データを返す代わりに、「発注済み」を返します。

おそらくアクション実行のタイムアウトだと思っていましたが、念のため試してみました

<httpRuntime executionTimeout="600" />

助けにはなりませんでした。

追加のロギングを有効にするために、理由を検索する場所、追加で確認するものはありますか?

更新: 興味深いことに、元の呼び出しも完了しています。

更新 2: アクション フィルター AjaxOnly を追加して、JavaScript からのみ呼び出されるようにしました。

public class AjaxOnlyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!filterContext.HttpContext.Request.IsAjaxRequest())
        {                  
            throw new Exception("This action is intended to be called from Ajax only.");
        }
    }
}

そしてログからはjavascriptからしか呼び出されないので謎が続きます…

更新 3:

別のテストコントローラーで単純なスレッドスリープに問題を分離しました:

[ValidateAntiForgeryToken]
    [AjaxOnly]
    [ClientErrorHandler]
    public virtual ActionResult PlaceOrderAction(CheckoutDto checkoutDto)
    {
        try
        {
            if (CanPlaceOrder(Request.RequestContext.HttpContext))
            {                   
                Thread.Sleep(TimeSpan.FromSeconds(90));

                return Content("First time");
            }

            return Content("Second time");
        } 
        finally
        {
            HttpContext.Cache.Remove(GetKey(userService.CurrentUser.UserId));
        }
    }

    public bool CanPlaceOrder(HttpContextBase httpContext)
    {
        var userId = userService.CurrentUser.UserId;
        var key = GetKey(userId);

        if (httpContext.Cache[key] == null)
        {
            httpContext.Cache.Add(key, userId, null, DateTime.Now.AddMinutes(10), new TimeSpan(), CacheItemPriority.High, null);
            return true;
        }

        return false;
    }

    private static string GetKey(int userId)
    {
        return "PlacingOrder{0}".With(userId);
    }

2 つの独立した開発マシン (win 7) と ec2 のステージング マシン (win2008sp2) で問題なく動作する限り、運用サーバーの IIS 設定 (win 2008R2 x64 sp1) に問題があることはほぼ確実です。

4

2 に答える 2

0

それを見つけた。

IIS 構成が何らかの形でこれに関与していると考え始めたので、実稼働 IIS で新しいテスト サイトを開始しました。90 秒のスレッド スリープを備えたデフォルトの mvc サイトです。
そして、それは想定どおりに機能しました。
そのため、本番サイトに影響を与えずにアイデアをより迅速にテストできると考えて、本番サイト全体を別のポートで実行するようにコピーしました。別のポートで実行しているときは問題ありませんでした。

Amazon Elastic バランサーを使用していたことが問題でした。

道徳的に言えば、最初から積極的に問題を切り分けていれば、無駄な時間を大幅に削減できただろうということです。

于 2012-07-24T08:52:32.023 に答える
0

同様の質問からの提案は次のとおりです。

「誤ってページを参照している可能性のある他のマークアップはありますか?スクリプト参照、画像参照、css 参照、すべてが誤って '.' を指している可能性があります。または現在のページ。」

MVC コントローラーが 2 回呼び出されています

于 2012-07-20T13:44:25.123 に答える