Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I troubleshoot routes? #1181

Open
grtswt opened this issue Nov 8, 2023 · 6 comments
Open

How do I troubleshoot routes? #1181

grtswt opened this issue Nov 8, 2023 · 6 comments

Comments

@grtswt
Copy link

grtswt commented Nov 8, 2023

I have a problem where calls to an URL sometimes hang. Nothing gets logged in the access log and the scriptblock in the route never gets executed. I Post this as a Question since I don't know if it is my fault or not.

In the log below, ContextID 6333d327-1874-1d7f-2e4a-df70f7698335 is a successful call and ContextID 7d73d055-4d3d-6013-e368-ae9f8b4f6e80 is where it failed

[Verbose]: [ContextId: 6333d327-1874-1d7f-2e4a-df70f7698335] Received request
[Verbose]: [ContextId: 6333d327-1874-1d7f-2e4a-df70f7698335] Sending response
[Verbose]: [ContextId: 6333d327-1874-1d7f-2e4a-df70f7698335] Response sent
[Verbose]: [ContextId: 6333d327-1874-1d7f-2e4a-df70f7698335] Request disposed
[Verbose]: [ContextId: 6333d327-1874-1d7f-2e4a-df70f7698335] Response disposed
[Verbose]: [ContextId: 7d73d055-4d3d-6013-e368-ae9f8b4f6e80] Received request
[Verbose]: [ContextId: 7d73d055-4d3d-6013-e368-ae9f8b4f6e80] Sending response
[Verbose]: [ContextId: 7d73d055-4d3d-6013-e368-ae9f8b4f6e80] Response sent
[Verbose]: [ContextId: 7d73d055-4d3d-6013-e368-ae9f8b4f6e80] Response disposed
[Verbose]: [ContextId: 7d73d055-4d3d-6013-e368-ae9f8b4f6e80] Socket listening
[Verbose]: [ContextId: 7d73d055-4d3d-6013-e368-ae9f8b4f6e80] Sending response
[Verbose]: [ContextId: 7d73d055-4d3d-6013-e368-ae9f8b4f6e80] Response sent
[Verbose]: [ContextId: 7d73d055-4d3d-6013-e368-ae9f8b4f6e80] Request disposed
[Verbose]: [ContextId: 7d73d055-4d3d-6013-e368-ae9f8b4f6e80] Response disposed

How would I continue troubleshooting? Why would two different calls to the same route log so differently?

/Peter

@RobinBeismann
Copy link
Sponsor Contributor

Hi @grtswt,

how many threads are you running? Might be that your existing threads are busy while the new call comes in.

@grtswt
Copy link
Author

grtswt commented Nov 9, 2023

I'm using four threads. And I think in this case that only one was busy at this time.

Lets say that I use invoke-restmethod to call the URL. If the error occurs, then invoke-restmethod hangs forever.
Nothing gets logged and the routes scriptblock is not called.

If I press CTRL-C and break invoke-restmethod, then the scriptblock is called and the call is logged to the access_log.

It is as if Pode is still waiting for the request to finish sending.

@Badgerati
Copy link
Owner

That would explain why it goes back into "socket listening", it's still waiting for IRM to send all the data - or it thinks there's still more data.

What version of Pode, Powershell, and OS are you on? Are you using HTTP or HTTPS? Would you be able to give an example of the script that triggers this behaviour, plus the IRM call?

I have seen this before, and it was on Mac and HTTPS calls when the SSL Protocol was wrong.

@grtswt
Copy link
Author

grtswt commented Nov 9, 2023

I'm using
Pode 2.9.0
Windows server 2019
pwsh 7.3.9

APIServer

import-module Pode
#Import-Module -Name Pode.Kestrel
Import-Module -Name PSHTML
#Import-Module ActiveDirectory

$sysRoot = (get-item $PSScriptRoot).FullName

write-host "Starting"

#Start-PodeServer -ListenerType Kestrel -Threads 2 -Verbose  -RootPath "..\SystemConfig" {
Start-PodeServer -Threads 4 -RootPath $sysRoot {

    Add-PodeEndpoint -Address localhost -Port 8080 -Protocol Https -SelfSigned

    New-PodeLoggingMethod -File -Name 'access_log' -Path $sysroot |Enable-PodeRequestLogging 
    New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging -Levels '*'

    New-PodeAuthScheme -Basic | Add-PodeAuthUserFile -Name 'Login'  -Sessionless

    $CurrentThreads = [System.Collections.Concurrent.ConcurrentDictionary[int32,string]]::new()

    Add-PodeRoute -Method get -Path "/threads" -ContentType "text/html" -ArgumentList @($CurrentThreads) -ScriptBlock {
        param (
            [System.Collections.Concurrent.ConcurrentDictionary[int32,string]]
            $CurrentThreads 
        )
        $str = "[{0}] Thread {1} This thread" -f [datetime]::now.tostring("yyyy-MM-dd HH:mm:ss.fff"),[System.Threading.Thread]::CurrentThread.ManagedThreadId,$webevent.path
        $adder = $updater = { return Write-Output $str -NoEnumerate }
        $CurrentThreads.AddOrUpdate([System.Threading.Thread]::CurrentThread.ManagedThreadId, $adder, $updater)

        $html = html {
            head {
                Title "Current threads"
                style "table, th, td {border: 1px solid black; border-collapse: collapse;}"
            }
            body {
                H1 "Current threads and their action"
                table {
                    Thead { tr {th "TID";th "Action"} }
                    Tbody {
                        foreach ($t in $CurrentThreads.GetEnumerator()) {
                            tr {td $t.key;td $t.Value}
                        }
                    }
                }
            }
        }

        $str = "[{0}] Thread {1} sleeping" -f [datetime]::now.tostring("yyyy-MM-dd HH:mm:ss.fff"),[System.Threading.Thread]::CurrentThread.ManagedThreadId
        $adder = $updater = { return Write-Output $str -NoEnumerate }
        $CurrentThreads.AddOrUpdate([System.Threading.Thread]::CurrentThread.ManagedThreadId, $adder, $updater)

        Write-PodeHtmlResponse -Value $html -StatusCode 200
    }

    add-poderoute -Path "/test" -Method Get -Authentication 'Login' -argumentlist @($CurrentThreads) -ScriptBlock {
        param([System.Collections.Concurrent.ConcurrentDictionary[int32,string]]$CurrentThreads)
        $str = "[{0}] Thread {1} executing {2}" -f [datetime]::now.tostring("yyyy-MM-dd HH:mm:ss.fff"),[System.Threading.Thread]::CurrentThread.ManagedThreadId,$webevent.path
        $adder = $updater = { return Write-Output $str -NoEnumerate }
        $CurrentThreads.AddOrUpdate([System.Threading.Thread]::CurrentThread.ManagedThreadId, $adder, $updater)

        #Just log the request
        write-podehost ("{0} received {1}(PID={2};TID={3})" -f [datetime]::now.ToString("HH:mm:ss.fff"),$webevent.query["call"],$PID,[System.Threading.Thread]::CurrentThread.ManagedThreadId)
        Write-PodeTextResponse -Value ("Received call {0}" -f $webevent.query["call"]) -ContentType "text/plain" -StatusCode 200

        # Do nothing else
        $str = "[{0}] Thread {1} sleeping" -f [datetime]::now.tostring("yyyy-MM-dd HH:mm:ss.fff"),[System.Threading.Thread]::CurrentThread.ManagedThreadId
        $adder = $updater = { return Write-Output $str -NoEnumerate }
        $CurrentThreads.AddOrUpdate([System.Threading.Thread]::CurrentThread.ManagedThreadId, $adder, $updater)
    } |out-null
}

Query loop:

[string]$userName = 'test'
[string]$userPassword = 'test'

# Convert to SecureString
[securestring]$secStringPassword = ConvertTo-SecureString $userPassword -AsPlainText -Force
[pscredential]$cred = New-Object System.Management.Automation.PSCredential ($userName, $secStringPassword)

$url = "https://127.0.0.1:8080/test?call={0}"

ForEach($i in 1..10000) {
    "Calling $i"
    Invoke-RestMethod -Uri ($url -f $i) -Method get -Credential $cred -ResponseHeadersVariable rh -SkipCertificateCheck
    "Call {0} finished, ContextID: {1}" -f $i, ($rh.'X-Pode-ContextId' -join " ")
} 

I tested the above in two different windows and the query loop hung on:

4578 finished ContextID: 33a866ae-e8f2-8738-df87-b56e00cb5aee
Calling 4579
Received call 4579
4579 finished ContextID: bec4df88-8490-9da8-0f7b-e2b76536e542
Calling 4580

That means that irm had not finished.

in the apiserver window the following was showing:

[Verbose]: [ContextId: 33a866ae-e8f2-8738-df87-b56e00cb5aee] Received request
14:46:14.277 received 4578(PID=14640;TID=47)
[Verbose]: [ContextId: 33a866ae-e8f2-8738-df87-b56e00cb5aee] Sending response
[Verbose]: [ContextId: 33a866ae-e8f2-8738-df87-b56e00cb5aee] Response sent
[Verbose]: [ContextId: 33a866ae-e8f2-8738-df87-b56e00cb5aee] Request disposed
[Verbose]: [ContextId: 33a866ae-e8f2-8738-df87-b56e00cb5aee] Response disposed
[Verbose]: [ContextId: b17212e9-1c1c-cfaf-825a-d28f7046494b] Received request
[Verbose]: [ContextId: b17212e9-1c1c-cfaf-825a-d28f7046494b] Sending response
[Verbose]: [ContextId: b17212e9-1c1c-cfaf-825a-d28f7046494b] Response sent
[Verbose]: [ContextId: b17212e9-1c1c-cfaf-825a-d28f7046494b] Request disposed
[Verbose]: [ContextId: b17212e9-1c1c-cfaf-825a-d28f7046494b] Response disposed
[Verbose]: [ContextId: bec4df88-8490-9da8-0f7b-e2b76536e542] Received request
14:46:14.323 received 4579(PID=14640;TID=48)
[Verbose]: [ContextId: bec4df88-8490-9da8-0f7b-e2b76536e542] Sending response
[Verbose]: [ContextId: bec4df88-8490-9da8-0f7b-e2b76536e542] Response sent
[Verbose]: [ContextId: bec4df88-8490-9da8-0f7b-e2b76536e542] Request disposed
[Verbose]: [ContextId: bec4df88-8490-9da8-0f7b-e2b76536e542] Response disposed
[Verbose]: [ContextId: 77e5e9f8-7256-0b39-07ef-d4805ee345cd] Received request
[Verbose]: [ContextId: 77e5e9f8-7256-0b39-07ef-d4805ee345cd] Sending response
[Verbose]: [ContextId: 77e5e9f8-7256-0b39-07ef-d4805ee345cd] Response sent
[Verbose]: [ContextId: 77e5e9f8-7256-0b39-07ef-d4805ee345cd] Request disposed
[Verbose]: [ContextId: 77e5e9f8-7256-0b39-07ef-d4805ee345cd] Response disposed
--- CTRL-C ---
[Verbose]: [ContextId: ad1db8ba-e909-457d-6401-0f8208ec4c6a] Received request
14:59:32.706 received 4580(PID=14640;TID=47)
[Verbose]: [ContextId: ad1db8ba-e909-457d-6401-0f8208ec4c6a] Sending response
[Verbose]: [ContextId: ad1db8ba-e909-457d-6401-0f8208ec4c6a] Request disposed
[Verbose]: [ContextId: ad1db8ba-e909-457d-6401-0f8208ec4c6a] Response disposed

It had stopped on the CTRL-C. When I pressed CTRL-C in the query loop window, the rows below CTRL-C appeared in the server window.

I don't know why my original server (in the first log) does a restart of the same ContextID. And the sample code instead has another hidden call (with a different ContextID). For example b17212e9-1c1c-cfaf-825a-d28f7046494b in the second logfile is a call wasn't explicitly executed. Maybe it is hidden inside IRM.

@Badgerati
Copy link
Owner

Thanks!

I am able to reproduce the hanging with the above. Just to make sure, what happens if you drop HTTPS? Ie:

Add-PodeEndpoint -Address localhost -Port 8080 -Protocol Http

When I do this, I can't get it to hang any more. Is this the same for you as well? If so, I'll have to do some debugging around where the request stream is being read in 🤔

@grtswt
Copy link
Author

grtswt commented Nov 10, 2023

I can confirm that it works if I turn off encryption.

While using encryption, I noticed that cURL gave fewer errors. But I only tried that with 20000 repetitions. Might be some random thing.

The Application that calls the API-server is written i Java and I can't control how it makes the calls.

If I compare the fault frequency between IRM and the Application:
IRM 1 call out of 10000
Application 4 calls out of 10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants