gRCP Health Check with Powershell

FJS 21 Reputation points
2022-05-08T16:38:07.973+00:00

Hello.
I am checking periodically gRPC health of several microservices, every two seconds, it is working since I got the response they are serving, the output is { "status": "SERVING" }

 while ($true) {grpcurl -d '{ \"service1\": \"name1\" }' -H "authorization: key key"  host1:port grpc.health.v1.Health/Check>> grpcurl -d '{ \"service2\": \"name2\" }' -H "authorization: key key"  host2:port grpc.health.v1.Health/Check>> grpcurl -d '{ \"service3\": \"name3\" }' -H "authorization: key key"  host3:port grpc.health.v1.Health/Check>> grpcurl -d '{ \"service4\": \"name4\" }' -H "authorization: key key"  host4:port grpc.health.v1.Health/Check>> grpcurl -d '{ \"service5\": \"name5\" }' -H "authorization: key key"  host5:port grpc.health.v1.Health/Check>> grpcurl -d '{ \"service6\": \"name6\" }' -H "authorization: key key" host6:port grpc.health.v1.Health/Check>> grpcurl -d '{ \"service7\": \"name7\" }' -H "authorization: key key" host7:port grpc.health.v1.Health/Check;start-sleep 2}

Now I need a notification if the output is not "SERVING" while the code keeps running in a loop, how can I achieve this?

Please note, one or more service can fail but other can be ok so notification should only about the ones are not answering "SERVING", thanks,

Windows Server PowerShell
Windows Server PowerShell
Windows Server: A family of Microsoft server operating systems that support enterprise-level management, data storage, applications, and communications.PowerShell: A family of Microsoft task automation and configuration management frameworks consisting of a command-line shell and associated scripting language.
5,363 questions
{count} votes

Accepted answer
  1. Rich Matheisen 44,776 Reputation points
    2022-05-10T14:49:34.68+00:00

    There are ways to make this more efficient, and to also handle those times when grpcurl doesn't return anything in STDOUT (e.g. the host cannot be contacted, authentication fails, etc.) but writes an error message to STDERR, but I'll leave that part up to you,

    Give this one a try:

    function Serving{
        param(
            $val
        )
        if ($val -isnot [array]){
            return $false
        }
        if ($val.count -ne 3){
            return $false
        }
        Try{
            $p = $val -join "" | ConvertFrom-Json -ErrorAction STOP
            if ($p.status -eq 'serving'){
                $true
            }
            else{
                $false
            }
        }
        Catch{
            Write-Host "'$p' is not JSON"
            $false
        }
    }
    while ($true) {
        $beep = $false
        [array]$response = grpcurl -d '{ \"service1\": \"name1\" }' -H "authorization: key key"  host1:port grpc.health.v1.Health/Check
        if (-Not (Serving $response)){
            Write-Host "Service1 isn't serving" -ForegroundColor Yellow
            $beep = $true
        }
        [array]$response = grpcurl -d '{ \"service2\": \"name2\" }' -H "authorization: key key"  host2:port grpc.health.v1.Health/Check
        if (-Not (Serving $response)){
            Write-Host "Service2 isn't serving" -ForegroundColor Yellow
            $beep = $true
        }
        [array]$response = grpcurl -d '{ \"service3\": \"name3\" }' -H "authorization: key key"  host3:port grpc.health.v1.Health/Check
        if (-Not (Serving $response)){
            Write-Host "Service3 isn't serving" -ForegroundColor Yellow
            $beep = $true
        }
        [array]$response = grpcurl -d '{ \"service4\": \"name4\" }' -H "authorization: key key"  host4:port grpc.health.v1.Health/Check 
        if (-Not (Serving $response)){
            Write-Host "Service4 isn't serving" -ForegroundColor Yellow
            $beep = $true
        }
        [array]$response = grpcurl -d '{ \"service5\": \"name5\" }' -H "authorization: key key"  host5:port grpc.health.v1.Health/Check
        if (-Not (Serving $response)){
            Write-Host "Service5 isn't serving" -ForegroundColor Yellow
            $beep = $true
        }
        [array]$response = grpcurl -d '{ \"service6\": \"name6\" }' -H "authorization: key key"  host6:port grpc.health.v1.Health/Check
        if (-Not (Serving $response)){
            Write-Host "Service6 isn't serving" -ForegroundColor Yellow
            $beep = $true
        }
        [array]$response = grpcurl -d '{ \"service7\": \"name7\" }' -H "authorization: key key"  host7:port grpc.health.v1.Health/Check 
        if (-Not (Serving $response)){
            Write-Host "Service7 isn't serving" -ForegroundColor Yellow
            $beep = $true
        }
        if ($beep){
            [console]::beep(500, 300)
        }
        Start-Sleep 2 
    }
    

14 additional answers

Sort by: Most helpful
  1. Rich Matheisen 44,776 Reputation points
    2022-05-08T19:36:59.253+00:00

    See if this works:

    $responses = @()  
    while ($true) {  
        $responses += grpcurl -d '{ \"service1\": \"name1\" }' -H "authorization: key key"  host1:port grpc.health.v1.Health/Check  
        $responses += grpcurl -d '{ \"service2\": \"name2\" }' -H "authorization: key key"  host2:port grpc.health.v1.Health/Check  
        $responses += grpcurl -d '{ \"service3\": \"name3\" }' -H "authorization: key key"  host3:port grpc.health.v1.Health/Check   
        $responses += grpcurl -d '{ \"service4\": \"name4\" }' -H "authorization: key key"  host4:port grpc.health.v1.Health/Check   
        $responses += grpcurl -d '{ \"service5\": \"name5\" }' -H "authorization: key key"  host5:port grpc.health.v1.Health/Check   
        $responses += grpcurl -d '{ \"service6\": \"name6\" }' -H "authorization: key key"  host6:port grpc.health.v1.Health/Check   
        $responses += grpcurl -d '{ \"service7\": \"name7\" }' -H "authorization: key key"  host7:port grpc.health.v1.Health/Check   
        $ctr = 0  
        [array]$bad = @()  
        ForEach ($response in $responses){  
            $ctr++  
            if ($response -ne '{ "status": "SERVING" }'){  
                $bad += $ctr  
            }        
        }  
        if ($bad.count -gt 0){  
            [console]::beep(500,300)  
            $bad |  
                ForEach-Object{  
                    Write-Host "host$($_): $($responses[$_ - 1])" -ForegroundColor Yellow  
                }  
      
        }  
        $responses = @()  
        $bad = @()  
        Start-Sleep 2   
    }  
    

    I don't know what your host names are so the script will probably need some work to be usable.

    0 comments No comments

  2. FJS 21 Reputation points
    2022-05-08T20:43:25.243+00:00

    It works, but couple of things all are SERVING now and I get a beep at first just when the script is executed and a beep when the 7 checks are done just before start the loop again, the idea of the beep used as a warning is in case the output is not SERVING also how can I change in the Write-Host "host$ part to have the name of each service?
    now I am geting this output...
    host1: {
    host2: "status": "SERVING"
    host3: }
    host4: {
    host5: "status": "SERVING"
    host6: }
    host7: {
    host8: "status": "SERVING"
    host9: }
    host10: {
    host11: "status": "SERVING"
    host12: }
    host13: {
    host14: "status": "SERVING"
    host15: }
    host16: {
    host17: "status": "SERVING"
    host18: }
    host19: {
    host20: "status": "SERVING"
    host21: }
    host1: {
    host2: "status": "SERVING"
    host3: }
    host4: {
    host5: "status": "SERVING"
    host6: }
    host7: {
    host8: "status": "SERVING"
    host9: }
    host10: {
    host11: "status": "SERVING"
    host12: }
    host13: {
    host14: "status": "SERVING"

    thanks!

    0 comments No comments

  3. Rich Matheisen 44,776 Reputation points
    2022-05-08T23:07:40.037+00:00

    I just phonied up a few "responses and commented out the "while" and the execution of the grpcurl tool, and changed the "sleep" time to 5 seconds.

    $responses = @(  
        '{ "status": "SERVING" }'  
        '{ "status": "SERVING" }'  
        '{ "status": "is not SERVING" }'  
        '{ "status": "SERVING" }'  
        '{ "status": "is not SERVING" }'  
        '{ "status": "SERVING" }'  
    )  
    #while ($true) {  
    #     $responses += grpcurl -d '{ \"service1\": \"name1\" }' -H "authorization: key key"  host1:port grpc.health.v1.Health/Check  
    #     $responses += grpcurl -d '{ \"service2\": \"name2\" }' -H "authorization: key key"  host2:port grpc.health.v1.Health/Check  
    #     $responses += grpcurl -d '{ \"service3\": \"name3\" }' -H "authorization: key key"  host3:port grpc.health.v1.Health/Check   
    #     $responses += grpcurl -d '{ \"service4\": \"name4\" }' -H "authorization: key key"  host4:port grpc.health.v1.Health/Check   
    #     $responses += grpcurl -d '{ \"service5\": \"name5\" }' -H "authorization: key key"  host5:port grpc.health.v1.Health/Check   
    #     $responses += grpcurl -d '{ \"service6\": \"name6\" }' -H "authorization: key key"  host6:port grpc.health.v1.Health/Check   
    #     $responses += grpcurl -d '{ \"service7\": \"name7\" }' -H "authorization: key key"  host7:port grpc.health.v1.Health/Check   
        $ctr = 0  
        [array]$bad = @()  
        ForEach ($response in $responses){  
            $ctr++  
            if ($response -ne '{ "status": "SERVING" }'){  
                $bad += $ctr  
            }        
        }  
        if ($bad.count -gt 0){  
            [console]::beep(500,300)  
            $bad |  
                ForEach-Object{  
                    Write-Host "host$($_): $($responses[$_ - 1])" -ForegroundColor Yellow  
                }  
      
        }  
        $responses = @()  
        $bad = @()  
        Start-Sleep -s 5   
    #}  
    

    The results were a "beep" and this:

    PS C:\Users\richm> . "c:\Junk\Untitled-22.ps1"  
    host3: { "status": "is not SERVING" }  
    host5: { "status": "is not SERVING" }  
    PS C:\Users\richm>   
    

    I don't any way to run grpcurl so I can't tell you what is being written to STDOUT. Perhaps there are multiple lines being written to STDOUT by each execution? Or each line is ended (or preceded) by a CrLf pair?

    0 comments No comments

  4. Rich Matheisen 44,776 Reputation points
    2022-05-08T23:10:00.26+00:00

    If there are CrLf in the grpcurl responses they'll screw up the response checking.

    Try this version. It removes any whitespace at the begging and end of each response from grpcurl:

    while ($true) {
         $responses += grpcurl -d '{ \"service1\": \"name1\" }' -H "authorization: key key"  host1:port grpc.health.v1.Health/Check
         $responses += grpcurl -d '{ \"service2\": \"name2\" }' -H "authorization: key key"  host2:port grpc.health.v1.Health/Check
         $responses += grpcurl -d '{ \"service3\": \"name3\" }' -H "authorization: key key"  host3:port grpc.health.v1.Health/Check 
         $responses += grpcurl -d '{ \"service4\": \"name4\" }' -H "authorization: key key"  host4:port grpc.health.v1.Health/Check 
         $responses += grpcurl -d '{ \"service5\": \"name5\" }' -H "authorization: key key"  host5:port grpc.health.v1.Health/Check 
         $responses += grpcurl -d '{ \"service6\": \"name6\" }' -H "authorization: key key"  host6:port grpc.health.v1.Health/Check 
         $responses += grpcurl -d '{ \"service7\": \"name7\" }' -H "authorization: key key"  host7:port grpc.health.v1.Health/Check 
        $ctr = 0
        [array]$bad = @()
        ForEach ($response in $responses){
            $r = $response.Trim()
            $ctr++
            if ($r -ne '{ "status": "SERVING" }'){
                $bad += $ctr
            }      
        }
        if ($bad.count -gt 0){
            [console]::beep(500,300)
            $bad |
                ForEach-Object{
                    Write-Host "host$($_): $($responses[$_ - 1].Trim())" -ForegroundColor Yellow
                }
    
        }
        $responses = @()
        $bad = @()
        Start-Sleep 2 
    }
    
    0 comments No comments