Azure / azure-sdk-for-go

This repository is for active development of the Azure SDK for Go. For consumers of the SDK we recommend visiting our public developer docs at:
https://docs.microsoft.com/azure/developer/go/
MIT License
1.64k stars 844 forks source link

Getting 503 error when calling `(*runtime.Pager[armquota.ClientListResponse]).NextPage` #22167

Open mattwelke opened 10 months ago

mattwelke commented 10 months ago

Bug Report

I'm using the Go SDK and learning how the Quota Service API works. I'm testing out making a call to list all quotas that already exist for Microsoft.Network for location "eastus". I picked the location from examples in the docs.

When I call NextPage, I only ever get 429 and 503 errors. When I encounter a 429 error, it always has Retry-After in the response headers set to 300, so I wait about 5 minutes and try again. At which point I get the 503 response.

I'm wondering if this 503 is being caused by some issue server side (the REST API docs page says it's in Public Preview and the CLI docs page says it's in GA, so I understand it may not be fully GA yet), or if it's related to something on my side, like my code in this test or the state of my Azure account while I run the code.

Concerning my Azure account, right now this is a free trial account and I have already manually enabled the quotas provider when I ran a test similar to this before and got an error that told me I had not enabled it yet. I found instructions in the docs to enable the provider back then, followed them, and was able to get that test to succeed (it was to list quotas for virtual machines in eastus, which returned []).

My code:

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/quota/armquota"
)

func main() {
    fmt.Printf("Hello, %s!\n", "World")

    cred, err := azidentity.NewDefaultAzureCredential(nil)
    if err != nil {
        panic(err)
    }

    client, err := armquota.NewClient(cred, nil)
    if err != nil {
        log.Fatalf("Failed to create client: %s", err)
    }

    subscription := os.Getenv("SCOPE_SUB")
    location := os.Getenv("SCOPE_LOC")

    scope := fmt.Sprintf("subscriptions/%s/providers/Microsoft.Network/locations/%s",
        subscription,
        location)

    resp := client.NewListPager(scope, nil)
    items := []*armquota.CurrentQuotaLimitBase{}
    for resp.More() {
        page, err := resp.NextPage(context.TODO())
        if err != nil {
            log.Fatalf("failed to get next page: %s", err)
        }

        items = append(items, page.Value...)
    }

    _ = items
    fmt.Println("stop")
}

The 503 response:

image image

github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/quota/armquota

> go list -m github.com/Azure/azure-sdk-for-go/sdk/azcore
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0

go version go1.21.3 linux/amd64

Alancere commented 10 months ago

Hi @mattwelke , I used the code you provided to replace the subscriptionId and it was successful.

image

mattwelke commented 10 months ago

Thanks for taking a look. I actually also tried this again tonight with a different subscription in a different Azure account and I was also successful.

So I'm going to try it again with the subscription and account where I had this issue to see if I can reproduce it.

mattwelke commented 10 months ago

I tried this again and I was able to reproduce my issue. I still got a 503 response. Then, I was able to resolve it by making the same change to this Azure account that I did to the Azure account where I was able to get it working yesterday. I registered the Microsoft.Network resource provider. After registering it, and running the code again, I got a response with data about network limits instead of a 503 response.

I think there were a few things that led me down this path where I got confused.

The first Azure API I tried to use was Authorization. I started from its docs which did not talk about registering resource providers. I was able to run examples from its docs.

Later, while trying to use the Azure Quota Service API, I was applying the knowledge I gained from the earlier API. I planned to run the examples. Its docs did talk about registering a resource provider. So I registered the Microsoft.Quota resource provider before trying to run the examples. I started with an example that used the resource provider Microsoft.Compute as its scope. It worked.

I then tried the example where the scope included Microsoft.Network instead of Microsoft.Compute. This is where I got this error. Because I did not have to enable the Microsoft.Authorization in order to run the examples for the Authorization API and I did not have to enable the Microsoft.Compute resource provider in order to run the Quota Service API example with the Compute scope, I assumed that I wouldn't need to enable the Microsoft.Network resource provider in order to run the quota API example with the Network scope.

I now understand that the reason I didn't need to register the Microsoft.Authorization resource provider is because it is one of the resource providers that is registered by default when a subscription is created. I do not yet understand why I was able to run the Quota Service API example with the Microsoft.Compute scope without first registering the Microsoft.Compute resource provider.

So to summarize the different experiences I've had making various API calls:

Provider Provider in quota scope Provider registered? Provider in scope registered? API call succeeds?
Microsoft.Quota Microsoft.Compute Yes No Yes
Microsoft.Quota Microsoft.Network Yes No No
Microsoft.Quota Microsoft.Network Yes Yes Yes

This leads me to a few questions which I think will help me understand what happened.

1) Is it true that in general, one must register the resource provider associated with the resource provider they indicate in the scope of a Quota Service API call? For example, if they want to make a call like, the following...

   clientFactory, _ := armquota.NewClientFactory(cred, nil)
   scope := "subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Network/locations/eastus"
   pager := clientFactory.NewClient().NewListPager(scope, nil)

Then they must register both the Microsoft.Quota and Microsoft.Network resource providers?

2) Why is it possible to use a scope that includes the Microsoft.Compute resource provider in a call like the one above without first registering it?

3) Could any of this behavior I've witnessed be related to the fact that the API is in Public Preview right now and is not yet GA?

raych1 commented 10 months ago

Hi @mattwelke , this document captures the default registered resource providers. https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-services-resource-providers#management-resource-providers.

Yes, in general, a resource provider needs to be registered before use it even in the scope.

I'm not sure if this inconsistent issue is related to the fact that this API hasn't been GAed yet. This needs service team response.

mattwelke commented 10 months ago

Thanks for clarifying.

Now that we're letting the service team know, I'm curious what they'll say about it. This isn't urgent on our part. We're just doing dev work right now while it's in preview. We don't need to launch til its GA. So I'm just keeping an eye on things for now.