Асинхронная обработка Httplistener с Powershell (New-ScriptBlockCallback) - все еще блокирует - PullRequest
1 голос
/ 09 мая 2019

Приведенный ниже код должен обрабатывать запросы асинхронно, однако при вызове / тайм-ауте (который дает 10-секундный тайм-аут) httplistener зависает также для всех других запросов, которые делаются одновременно.Может быть, кто-то может помочь мне с кодом, чтобы понять, почему не работает асинхронная обработка?

С помощью C # мне удалось получить эту работу, однако мое понимание работы с New-ScriptBlockCallback кажется ограниченным, и мне бы очень хотелось получить эту работу с PowerShell.

function New-ScriptBlockCallback 
    {
        [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')]
        param(
            [parameter(Mandatory)]
            [ValidateNotNullOrEmpty()]
            [scriptblock]$Callback
        )

        # Is this type already defined?
        if (-not ( 'CallbackEventBridge' -as [type])) {
            Add-Type @' 
                using System; 

                public sealed class CallbackEventBridge { 
                    public event AsyncCallback CallbackComplete = delegate { }; 

                    private CallbackEventBridge() {} 

                    private void CallbackInternal(IAsyncResult result) { 
                        CallbackComplete(result); 
                    } 

                    public AsyncCallback Callback { 
                        get { return new AsyncCallback(CallbackInternal); } 
                    } 

                    public static CallbackEventBridge Create() { 
                        return new CallbackEventBridge(); 
                    } 
                } 
'@
        }
        $bridge = [callbackeventbridge]::create()
        Register-ObjectEvent -InputObject $bridge -EventName callbackcomplete -Action $Callback -MessageData $args > $null
        $bridge.Callback
    }



$listener = New-Object System.Net.HttpListener
$listener.Prefixes.Add('http://+:8080/') 
$listener.Start()
Write-host 'Listening'

$StartServiceTime = Get-Date

$requestListener = {
            [cmdletbinding()]
            param($result)

            [System.Net.HttpListener]$listener = $result.AsyncState;

            $context = $listener.EndGetContext($result);
            $request = $context.Request
            $response = $context.Response

            if ($request.Url -match '/timeout$') 
                {
                    $timeout = 10
                    sleep $timeout
                    $message = "Timeout $timeout"
                    $response.ContentType = 'text/html'
                }
            else 
                {
                    #fast response without timeout
                    $message = "no timeout";
                    $response.ContentType = 'text/html' ;
                }

            [byte[]]$buffer = [System.Text.Encoding]::UTF8.GetBytes($message)
            $response.ContentLength64 = $buffer.length
            $output = $response.OutputStream
            $output.Write($buffer, 0, $buffer.length)
            $output.Close()

    }  


$context = $listener.BeginGetContext((New-ScriptBlockCallback -Callback $requestListener), $listener)


while ($listener.IsListening)
    {

        If ($context.IsCompleted -eq $true) {$context = $listener.BeginGetContext((New-ScriptBlockCallback -Callback $requestListener), $listener)}


    }


$listener.Close()
Write-host 'Terminating ...'

Приведенный выше код можно вставить непосредственно в консоль PowerShell, и он запустит httplistener, работающий на порту 8080.

Для тестирования запросов без тайм-аута откройте новую консоль и введите (непрерывный цикл):

for ($$) {Invoke-RestMethod http://localhost:8080/}

Чтобы проверить время ожидания, откройте новую консоль и введите:

Invoke-RestMethod http://localhost:8080/timeout

Вы увидите, что непрерывные запросы будут зависать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...