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

Metrica: retry query if quota exceeded #6459

Merged
merged 9 commits into from
Oct 17, 2023

Conversation

denisov-vlad
Copy link
Member

What type of PR is this?

  • Refactor
  • Feature
  • Bug Fix
  • New Query Runner (Data Source)
  • New Alert Destination
  • Other

Description

Metrica has a limit for simultaneous queries. If you have dashboard with 5+ different queries there is always errors. I use backoff library to retry queries if it fails with 429 (quota exceeded) error.

How is this tested?

  • Unit tests (pytest, jest)
  • E2E Tests (Cypress)
  • Manually
  • N/A

Ran queries with modified source both within query and dashboard.

Related Tickets & Documents

Mobile & Desktop Screenshots/Recordings (if there are UI changes)

@codecov
Copy link

codecov bot commented Sep 16, 2023

Codecov Report

Merging #6459 (d80609b) into master (d4ade51) will increase coverage by 0.27%.
The diff coverage is 66.66%.

@@            Coverage Diff             @@
##           master    #6459      +/-   ##
==========================================
+ Coverage   61.26%   61.53%   +0.27%     
==========================================
  Files         158      158              
  Lines       12889    12898       +9     
  Branches     1755     1756       +1     
==========================================
+ Hits         7896     7937      +41     
+ Misses       4743     4704      -39     
- Partials      250      257       +7     
Files Coverage Δ
redash/query_runner/yandex_metrica.py 70.43% <66.66%> (+32.69%) ⬆️

@guidopetri
Copy link
Contributor

This makes sense to me (although ideally we'd just submit the queries to Metrica in sequence and not overload it). Can we add a test of some kind to verify the quota exceeded error gets raised, and that the query gets retried after a while?

@guidopetri guidopetri self-assigned this Sep 16, 2023
@denisov-vlad
Copy link
Member Author

denisov-vlad commented Sep 17, 2023

@guidopetri

although ideally we'd just submit the queries to Metrica in sequence and not overload it

Yes, but in this case we need to change the logic for the scheduler/worker.

Can we add a test of some kind to verify the quota exceeded error gets raised, and that the query gets retried after a while?

That's not possible without access token.

@guidopetri
Copy link
Contributor

Hmm, is there no way to mock the calls and have a mocked object keep track of how many active queries there are?

@denisov-vlad
Copy link
Member Author

Honestly, I'm not sure that I can create unit test with parallel execution, because I have small experience with pytest. If you have suggestions how to do it, please share with me, and I'll try to research.

@guidopetri
Copy link
Contributor

I don't think we'd need parallel execution. Maybe we can set it up as a fixture that looks something like this:

def keep_only_5_items(item):
    if len(active_items) >= 5:
        print('Only 5 items are allowed')
        # clear active items and set flag
        active_items, flag = [], True
        return 429
    elif not flag:
        active_items.append(item)
        return 200
    elif flag:
        print("Called again after cleared items")
        return 200

with a test that calls on this function several times, and with the expectation that the nth call will raise the 429 we're looking for - and then after x amount of time, that the function gets called again.

@denisov-vlad
Copy link
Member Author

I still don't understand how to create such a test with backoff. When we run the run_query method, it will be restarted in the background, so we can't handle it.

By the way, added simple query test.

@guidopetri
Copy link
Contributor

Alright, no worries. I can try giving it a shot this weekend or next.


if not r.ok:
error_message = f"Code: {r.status_code}, message: {r.text}"
if response_data["code"] == 429:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@denisov-vlad shouldn't this be if r.status_code == 429? Can you provide an example 429 response from Metrica?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guidopetri thanks! Yes, r.status_code is better here.

@guidopetri
Copy link
Contributor

@denisov-vlad I converted the test to pytest and added a 429 test. The __call__ function is replacing requests.get(), essentially, so once we call it a 3rd time (according to N_API_CALLS) it returns a 429 / failing response, and then afterwards returns success; so we expect to call requests.get() N_API_CALLS + 1 times. Does this make sense? Do you think this test looks good, or do you think anything should be changed?

@denisov-vlad
Copy link
Member Author

@guidopetri thank you! The updated code looks good.

@guidopetri guidopetri enabled auto-merge (squash) October 17, 2023 01:57
@guidopetri guidopetri disabled auto-merge October 17, 2023 02:53
@guidopetri guidopetri merged commit 4210808 into getredash:master Oct 17, 2023
13 checks passed
harveyrendell pushed a commit to pushpay/redash that referenced this pull request Jan 8, 2025
* metrica: added retries

* updated poetry.lock

* use poetry v1.6.1

* added simple test

* convert unittest to pytest

* add 429 test

* fix 429 status code response?

---------

Co-authored-by: Guido Petri <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants