smartsheet-platform / smartsheet-python-sdk

Library that uses Python to connect to Smartsheet services (using API 2.0).
Apache License 2.0
136 stars 81 forks source link

Inaccessible 429 Response from client #177

Closed deployment-ian closed 2 years ago

deployment-ian commented 2 years ago

I am trying to understand / plan for the rate limits, particularly for the get_cell_history method in the python api.

When I run the code below, I see the following response printed to my console:

{"response": {"statusCode": 429, "reason": "Too Many Requests", "content": {"errorCode": 4003, "message": "Rate limit exceeded.", "refId": "SOME_REF_ID"}}}

But I am trying to force my if statement to read the response and check for the 429 status code

import smartsheet

smartsheet_client = smartsheet.Smartsheet('My_API_KEY')
smartsheet_client.errors_as_exceptions(True)

sheet_id = 'My_Sheet_ID'
edit_sheet = smartsheet_client.Sheets.get_sheet(sheet_id)  # type: smartsheet.smartsheet.models.Sheet

for row in edit_sheet.rows:  # type: smartsheet.smartsheet.models.Row
    for cell in row.cells:  # type: smartsheet.smartsheet.models.Cell
        cell_history = smartsheet_client.Cells.get_cell_history(sheet_id, row.id, cell.column_id,
                                                                include_all=True)
        if cell_history.request_response.status_code == 429:
            print(f'Rate limit exceeded.')
        elif cell_history.request_response.status_code == 200:
            print(f'Found Cell History: {len(cell_history.data)} edits')

Where can I access this response? Why does my program run without printing out the "Rate limit exceeded" string? I am using Python 3.8 and the package smartsheet-python-sdk==2.105.1

RCoff commented 2 years ago

Hey @deployment-ian

Try commenting out this line and run your code again:

smartsheet_client.errors_as_exceptions(True)

I'm thinking that, due to the above line, an exception is being thrown

Alternatively, you could use a try/except to handle this. I think that's what I use in my code

deployment-ian commented 2 years ago

I posted this question on stack overflow: https://stackoverflow.com/a/73194270/6770704

Essentially, in the class OperationErrorResult, there are a few errors which are automatically retried:

class OperationErrorResult(object):
    """The error result of a call to an operation."""

    error_lookup = {
        0: {
            'name': 'ApiError',
            'recommendation': 'Do not retry without fixing the problem. ',
            'should_retry': False},
        4001: {
            'name': 'SystemMaintenanceError',
            'recommendation': ('Retry using exponential backoff. Hint: '
                               'Wait time between retries should measure '
                               'in minutes (not seconds).'),
            'should_retry': True},
        4002: {
            'name': 'ServerTimeoutExceededError',
            'recommendation': 'Retry using exponential backoff.',
            'should_retry': True},
        4003: {
            'name': 'RateLimitExceededError',
            'recommendation': ('Retry using exponential backoff. Hint: '
                               'Reduce the rate at which you are sending '
                               'requests.'),
            'should_retry': True},
        4004: {
            'name': 'UnexpectedErrorShouldRetryError',
            'recommendation': 'Retry using exponential backoff.',
            'should_retry': True},
    }

So this particular rate limit exceeded error is automatically paused and re-tried

RCoff commented 2 years ago

@deployment-ian has your issue been solved?

deployment-ian commented 2 years ago

Yes