Search code examples
gomicrosoft-graph-sdks

Handling retries and throttling in microsoft graph API SDK


The current microsoft graph SDK for Go doesn't specify any parameters for the graph client to leverage throttling or retries, or anything to determine the default behaviour.

It can be done based on response codes if you use a custom REST client by looking at the error code 429 and backoff time from the response headers but not from using the sdk.

Looking for a solution so that the graph sdk internally retries within the Retry-After header

The doc also doesn't mention any custom adapters for a throttling handle https://pkg.go.dev/github.com/microsoftgraph/msgraph-sdk-go-core


Solution

  • Ok so i was able to figure out how to add a retry handler as a middleware to the graph client in Go. here is the piece of code:

    // Generate credentials
    cred, err := azidentity.NewClientSecretCredential(sharepointTenantId, clientId, clientSecret, nil)
    
    if err != nil {
        return err
    }
    
    defaultClientOptions := msgraphsdk.GetDefaultClientOptions()
    defaultMiddleWare := msgraphgocore.GetDefaultMiddlewaresWithOptions(&defaultClientOptions)
    
    
    // Custom middleware function to retry only on ratelimit error (Code: 429) can be customized to retry on more error codes)
    
    graphRetryOptions := nethttplibrary.RetryHandlerOptions{MaxRetries: 5, ShouldRetry: func(delay time.Duration, executionCount int, request *http.Request, response *http.Response) bool {
        if response.StatusCode == 429 {
            if v := response.Header["Retry-After"]; len(v) > 0 {
                // Logic to add sleep based on retry after recommended time
                return true
            }
        }
        return false
    }}
    
    retryMiddleware := nethttplibrary.NewRetryHandlerWithOptions(graphRetryOptions)
    defaultMiddleWare = append(defaultMiddleWare, retryMiddleware)
    
    graphOpts := &msgraphgocore.GraphClientOptions{GraphServiceVersion: DefaultGraphScope, GraphServiceLibraryVersion: "1.0.0"}
    
    graphHttpClient := msgraphgocore.GetDefaultClient(graphOpts, defaultMiddleWare...)
    
    authProvider, _ := authentication.NewAzureIdentityAuthenticationProviderWithScopes(cred, []string{".default"})
    
    adapter, err := msgraphsdk.NewGraphRequestAdapterWithParseNodeFactoryAndSerializationWriterFactoryAndHttpClient(authProvider, nil, serialization.DefaultSerializationWriterFactoryInstance, graphHttpClient)
    
    
    if err != nil {
        return err
    }
    
    // your graph client
    client := msgraphsdk.NewGraphServiceClient(adapter)