IT이야기

ASP.NET 웹 페이지 요청에 의해 트리거 된 비동기 작업 실행

cyworld 2021. 4. 23. 22:00
반응형

ASP.NET 웹 페이지 요청에 의해 트리거 된 비동기 작업 실행


다양한 이유로 ASP.NET 웹 페이지에 대한 HTTP 호출을 사용하여 트리거해야하는 비동기 작업이 있습니다. 내 페이지가 요청되면이 작업을 시작하고 즉시 클라이언트에게 승인을 반환해야합니다.

이 방법은 WCF 웹 서비스를 통해서도 노출되며 완벽하게 작동합니다.

첫 번째 시도에서 예외가 발생하여 다음과 같이 알려줍니다.

이 컨텍스트에서는 비동기 작업이 허용되지 않습니다.
비동기 작업을 시작하는 페이지에는 Async가 있어야합니다.
속성이 true로 설정되고 비동기 작업은
PreRenderComplete 이벤트 이전 페이지에서 시작되었습니다.

물론 Async="true"매개 변수를 @Page지시문에 추가했습니다 . 이제 오류가 발생하지 않지만 비동기 작업이 완료 될 때까지 페이지가 차단됩니다.

진정한 화재 및 삭제 페이지가 작동하도록하려면 어떻게해야합니까?

편집 : 추가 정보를위한 일부 코드. 이것보다 조금 더 복잡하지만 일반적인 아이디어를 얻으려고 노력했습니다.

public partial class SendMessagePage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string message = Request.QueryString["Message"];
        string clientId = Request.QueryString["ClientId"];

        AsyncMessageSender sender = new AsyncMessageSender(clientId, message);
        sender.Start();

        Response.Write("Success");
    }
}

AsyncMessageSender 클래스 :

public class AsyncMessageSender
{
    private BackgroundWorker backgroundWorker;
    private string client;
    private string msg;

    public AsyncMessageSender(string clientId, string message)
    {
        this.client = clientId;
        this.msg = message;

        // setup background thread to listen
        backgroundThread = new BackgroundWorker();
        backgroundThread.WorkerSupportsCancellation = true;
        backgroundThread.DoWork += new DoWorkEventHandler(backgroundThread_DoWork);
    }

    public void Start()
    {
        backgroundThread.RunWorkerAsync();
    }

    ...
    // after that it's pretty predictable
}

사용자에게 아무것도 반환하지 않으려면 별도의 스레드를 실행하거나 빠르고 더러운 접근 방식을 위해 델리게이트를 사용하여 비동기 적으로 호출 할 수 있습니다. 비동기 작업이 완료 될 때 사용자에게 알리는 데 신경 쓰지 않는 경우 콜백을 무시할 수 있습니다. SomeVeryLongAction () 메서드의 끝에 중단 점을 넣으면 페이지가 이미 제공된 후에 실행이 완료되는 것을 볼 수 있습니다.

private delegate void DoStuff(); //delegate for the action

protected void Page_Load(object sender, EventArgs e)
{

}

protected void Button1_Click(object sender, EventArgs e)
{
    //create the delegate
    DoStuff myAction = new DoStuff(SomeVeryLongAction); 
    //invoke it asynchrnously, control passes to next statement
    myAction.BeginInvoke(null, null);
    Button1.Text = DateTime.Now.ToString();
}


private void SomeVeryLongAction()
{
    for (int i = 0; i < 100; i++)
    {
        //simulation of some VERY long job
        System.Threading.Thread.Sleep(100);
    }
}

웹 양식을 실행하는 경우 요청하는 .aspx 페이지에서 Ansync = "true"를 설정합니다.
<%@ Page Language="C#" Async="true" ... %>


OK, 여기에 문제가 있습니다. Async 속성은 페이지가 스레드를 차단하는 일부 장기 실행 작업을 호출 할 경우 사용자에게 정보를 반환하기 위해 페이지가 해당 작업의 출력을 필요로하는 경우입니다. 예를 들어 페이지에서 웹 서비스를 호출해야하는 경우 응답을 기다린 다음 응답의 데이터를 사용하여 페이지를 렌더링합니다.

Async 속성을 사용하는 이유는 스레드 차단을 방지하기 위해서입니다. 이것은 ASP.NET 응용 프로그램이 요청을 처리하기 위해 스레드 풀을 사용하고 사용 가능한 스레드 수가 상대적으로 적기 때문에 중요합니다. 그리고 각 호출이 웹 서비스 호출을 기다리는 동안 스레드를 묶으면 곧 사용자가 이러한 웹 서비스 호출이 완료 될 때까지 기다려야하는 충분한 동시 사용자를 확보하게됩니다. Async 속성을 사용하면 스레드가 스레드 풀로 돌아가 웹 서비스 호출이 반환되기를 기다리는 동안 아무 작업도하지 않고 웹 사이트에 대한 다른 동시 방문자에게 서비스를 제공 할 수 있습니다.

결론은 이것이다 : Async 속성은 비동기 작업이 완료 될 때까지 페이지를 렌더링 할 수없는 경우를 위해 설계되었으며, 이것이 바로 페이지를 렌더링하지 않는 이유입니다.

자신의 스레드를 시작하고 데몬 스레드로 만들어야합니다. 정확한 구문은 기억 나지 않지만 "daemon"에 대한 BCL 문서를 검색하여 문서에서 쉽게 찾을 수 있습니다. 이것은 스레드가 응용 프로그램이 활성화되어있는 동안 종료되는 것을 방지한다는 것을 의미합니다. 이는 ASP.NET 및 IIS가 필요하다고 판단 할 때 "프로세스를 재활용"할 수있는 권한을 보유하고 스레드가 작동하는 동안 발생하는 경우에 중요하기 때문에 중요합니다. 작업이 중지됩니다. 스레드 데몬을 만들면이를 방지 할 수 있습니다 (희귀 한 경우를 제외하고 ... 이에 대한 문서를 찾을 때 더 많은 것을 알 수 있습니다).

이 데몬 스레드는 이러한 작업을 시작하는 곳입니다. 그리고 데몬 스레드에게 작업을 수행하도록 지시 한 후에는 즉시 페이지를 렌더링 할 수 있습니다. 그러면 페이지 렌더링이 즉시 수행됩니다.

그러나 ASP.NET 프로세스의 데몬 스레드보다 더 나은 것은 작업을 수행하기 위해 Windows 서비스를 구현하는 것입니다. ASP.NET 응용 프로그램이 수행 할 작업을 서비스에 전달하도록합니다. 데몬 스레드가 필요하지 않으며 ASP.NET 프로세스가 재활용되는 것에 대해 걱정할 필요가 없습니다. 서비스에 작업을 어떻게 지시합니까? 아마도 WCF를 통하거나 서비스가 폴링하는 데이터베이스 테이블에 레코드를 삽입 할 수 있습니다. 또는 여러 다른 방법.

편집 : 여기에 내가이 같은 목적으로 이전에 사용한 또 다른 아이디어가 있습니다. 작업에 대한 정보를 MSMQ 대기열에 씁니다. 다른 프로세스 (아마도 다른 컴퓨터에있을 수도 있음)를 해당 대기열에서 가져와 시간이 많이 걸리는 작업을 수행하도록합니다. 대기열에 삽입하는 작업은 가능한 한 빨리 반환되도록 최적화되어 있으므로 대기열에 넣은 데이터가 와이어 또는 이와 유사한 것을 통해 전송되는 동안 스레드가 차단되지 않습니다. 작업이 실행될 때까지 기다리지 않고 작업을 수행해야한다는 사실을 기록하는 가장 빠른 방법 중 하나입니다.


Async를 true로 설정하지 않고도이 제한을 아주 쉽게 해결할 수 있습니다.

public void Start()
{
    new Task(() =>
    {
        backgroundThread.RunWorkerAsync();
    }).Start();
}

웹 서비스를 비동기식으로 호출 할 때이 오류가 발생하면 예외 메시지의 지시에 따라 Async = 'true'속성을 추가해야합니까?

top of the page < Page Language='VB' Async='true' AutoEventWireup='false' CodeFile='mynewpage.aspx.vb' Inherits='mynewpage' %>

ReferenceURL : https://stackoverflow.com/questions/672237/running-an-asynchronous-operation-triggered-by-an-asp-net-web-page-request

반응형