-
Notifications
You must be signed in to change notification settings - Fork 35
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
Support max_concurrency for running Looker queries #110
Support max_concurrency for running Looker queries #110
Conversation
f0f31b5
to
07c4691
Compare
Codecov Report
@@ Coverage Diff @@
## master #110 +/- ##
==========================================
- Coverage 66.89% 65.92% -0.98%
==========================================
Files 9 9
Lines 716 719 +3
==========================================
- Hits 479 474 -5
- Misses 237 245 +8
Continue to review full report at Codecov.
|
d15410c
to
e29c39d
Compare
Situation was that once we ran Spectacles on our Looker instance with 128 explores in our model, it killed the instance in a way that it stopped responding and eventually crashed. I've diagnosed that it was merely the number of running queries at a time that caused it. It scheduled pretty much all 128 queries immediately. So this adds a flag --max-concurrency which you can use to tweak and set how much load you want to put on your Looker instance. I've tried our staging server with 10 and it works nicely and doesn't crash anything.
e29c39d
to
106fedd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @iserko, this is really awesome and will be extremely important so people don't overload their instances. This is my first time writing async code in Python, so would love it if you could elaborate on the general approach here and if/why it's better so I can learn.
I want to benchmark this a bit because I have a hunch it will be faster, but I'm getting an error with --max_concurrency 0
. Added a few more comments as well.
spectacles/cli.py
Outdated
@@ -352,6 +353,14 @@ def _build_sql_subparser( | |||
user's branch to the revision of the branch that is on the remote. \ | |||
WARNING: This will delete any uncommited changes in the user's workspace.", | |||
) | |||
subparser.add_argument( | |||
"--max-concurrency", | |||
default=0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to set the default to a higher number (10? 20?) so that a user who doesn't read the documentation avoids maxing out their instance accidentally. Better to provide a performance benefit for an informed user than a performance risk for an uniformed one. Open to suggestions on what that number should be.
spectacles/runner.py
Outdated
sql_validator = SqlValidator(self.client, self.project) | ||
sql_validator.build_project(selectors) | ||
errors = sql_validator.validate(mode) | ||
errors = sql_validator.validate(mode, max_concurrent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep the variable name consistent throughout.
spectacles/validators.py
Outdated
len(task_calls), | ||
max_concurrency, | ||
) | ||
while task_calls: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I run this with max_concurrency = 0
, I get stuck in this loop forever and queries are never launched. query_task_ids
is empty as defined above, so it continually waits for non-existent query task IDs to complete. Any idea what's going on here?
I wonder if you need to change if len(query_task_ids) >= max_concurrency:
to a >
?
One thing I realised here is that I think we lose the 250 limit on fetching queries? I can test this later on a big enough explore, but I think we will get errors when fetching the queries if it does over 293 or whatever that number is? |
@iserko, inspired by your PR, I did a bunch of digging on A few major changes:
Let me know what you think of these changes. |
I've adjusted the approach to use an asyncio Queue (to preserve state for running query task IDs) and a BoundedSemaphore (to limit the number of queries running concurrently). I've also renamed the flag to query_slots, which is certainly open to discussion.
cc3d447
to
68ebf6b
Compare
Situation was that once we ran Spectacles on our Looker instance
with 128 explores in our model, it killed the instance in a way that
it stopped responding and eventually crashed. I've diagnosed that it
was merely the number of running queries at a time that caused it.
It scheduled pretty much all 128 queries immediately.
So this adds a flag --max-concurrency which you can use to tweak
and set how much load you want to put on your Looker instance.
I've tried our staging server with 10 and it works nicely and doesn't
crash anything.
Of the things I did: