2014-09-24 1 views
4

콘솔 앱의 일부로 OWIN 서버가 있습니다. 현재 주요 방법을 볼 수자체 호스트 오 틴 서버를 중지 할 때 현재 요청을 완료하십시오.

class Program 
{ 
    public static ManualResetEventSlim StopSwitch = new ManualResetEventSlim(); 

    static void Main(string[] args) 
    { 
     Console.CancelKeyPress += (s, a) => 
     { 
      a.Cancel = true; 
      StopSwitch.Set(); 
     }; 

     using (WebApp.Start<Startup>("http://+:8080/")) 
     { 
      Console.WriteLine("Server is running..."); 
      Console.WriteLine("Press CTRL+C to stop it."); 
      StopSwitch.Wait(); 
      Console.WriteLine("Server is stopping..."); 
     } 

     Console.ReadKey(); 
     Console.WriteLine("Server stopped. Press any key to close app..."); 
    } 
} 

요청의 처리가 조금 이상 함과 동시에 사용자의 요청 처리 즉시 중지되고 응답이 전송되지 않습니다 응용 프로그램을 중지하려면 Ctrl + C를 누르면. 이 행동을 바꿀 수 있습니까? 나는 모든 새로운 요청을 거절하고 싶지만 현재 처리중인 요청이 완료 될 때까지 기다렸다가 그 후에 서버를 중지 할 때까지 기다린다.

나의 초기 아이디어는 현재 처리중인 요청을 추적하고 모든 것이 완료 될 때까지 작업을 연기 할 OWIN 미들웨어를 만드는 것입니다. 미들웨어는 또한 중지 단계에서 모든 요청을 단락시킵니다. 하지만이 솔루션은 나에게 좋지 않은 소리입니다.

+0

나에게 아주 좋은 생각이 들립니다. 난 당신이 새로운 요청을 단락시키기 위해 _ 무언가를 필요로한다고 생각합니다. 그리고 파이프 라인에 무언가를 넣는 것은 그것을 할 수있는 적당한 장소처럼 보입니다. 추적 요청의 경우 기본적인 ['Interlocked.Increment'] (http://msdn.microsoft.com/en-us/library/system.threading.interlocked.increment (v = vs.110) .aspx) /'Decrement' 카운터는 요청이 시작되고 끝날 때 마지막 요청이 언제 끝났는 지 안다. – Rhumborl

답변

1

나는 미들웨어와 제안 된 접근 방식으로 종료 :

public class ShutDownMiddleware 
{ 
    private readonly Func<IDictionary<string, object>, Task> next; 
    private static int requestCount = 0; 
    private static bool shutDownStateOn = false; 

    public static void ShutDown() 
    { 
     shutDownStateOn = true; 
    } 

    public static int GetRequestCount() 
    { 
     return requestCount; 
    } 

    public ShutDownMiddleware(Func<IDictionary<string, object>, Task> next) 
    { 
     this.next = next; 
    } 

    public async Task Invoke(IDictionary<string, object> environment) 
    { 
     if (shutDownStateOn) 
     { 
      environment["owin.ResponseStatusCode"] = HttpStatusCode.ServiceUnavailable; 
      return; 
     } 

     Interlocked.Increment(ref requestCount); 
     try 
     { 
      await next.Invoke(environment); 
     } 
     finally 
     { 
      Interlocked.Decrement(ref requestCount); 
     } 
    } 
} 

이 파이프 라인의 첫 번째 미들웨어로 등록 및 프로그램의 주요 방법 I는 다음과 같이 사용할 수 있습니다 :

public class Program 
{ 
    public static ManualResetEventSlim StopSwitch = new ManualResetEventSlim(); 

    static void Main(string[] args) 
    { 
     Console.CancelKeyPress += (s, a) => 
     { 
      a.Cancel = true; 
      StopSwitch.Set(); 
     }; 

     using (WebApp.Start<Startup>("http://+:8080/")) 
     { 
      Console.WriteLine("Server is running..."); 
      Console.WriteLine("Press CTRL+C to stop it."); 
      StopSwitch.Wait(); 
      Console.WriteLine("Server is stopping..."); 
      ShutDownMiddleware.ShutDown(); 
      while (ShutDownMiddleware.GetRequestCount() != 0) 
      { 
       Thread.Sleep(TimeSpan.FromSeconds(1)); 
      } 
     } 
    } 
} 

나는 또한 이것을 발견했다 : https://katanaproject.codeplex.com/workitem/281 그들은 비슷한 접근법에 대해 이야기하고있다.

+0

코드가 스레드로부터 안전하지 않습니다. 이 시나리오를 고려해보십시오. requestCount가 0이고 ShutDown()이 호출되지만 동시에 새 요청이 도착하고 여전히 shutDownStateOn이 false로 평가됩니다. ShutDown()이 계속되면 반환하고 주 스레드는 GetRequestCount()를 0으로 평가하여 응용 프로그램을 중지합니다. 그러나 위에서 설명한 요청은 아직 실행 중입니다. –

+0

또 다른 문제점을 발견했습니다 :''''다음에 기다려라 .Invoke (환경);'''이 미들웨어와 아마도 모든 미들웨어가 완료되었음을 알지만 그 이후에는 생성 된 응답을 전송하는 데 시간이 걸릴 것입니다 네트워크를 통해. 따라서 GetRequestCount()가 0이 된 직후 응용 프로그램을 종료하면 응답 전송이 중단 될 수 있습니다. –

관련 문제