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

Remodeling Structures #17

Merged
merged 14 commits into from
Aug 29, 2022
Merged

Remodeling Structures #17

merged 14 commits into from
Aug 29, 2022

Conversation

bh2smith
Copy link
Contributor

@bh2smith bh2smith commented Aug 25, 2022

A more general approach to #15 that is intended to be more long term maintainable.

We separate QueryMonitor structure into three.

  1. QueryData A data class containing the relevant fields that constitute a Dune query
  2. QueryBase - an abstract class with hollow methods needed to report on the query data and results. Specifically here we introduce alert_message so that the class itself knows how to alert based on its own attributes and result set.
  3. QueryRunner - a class containing an implementation of QueryBase, dune connection and slack client. It will be resposible for executing the dune query, passing the results on to the query base implementation for alert message and then posting in slack based on the alert message response.

Inline comments on almost every file to make the review easier.

Test Plan

Unit Tests & other CI (type checks linting etc...) There were no logical changes to this project and it was already extensively tested. The only tests that changed were those comparing alert messages since an enum is now included with the alert message.

Note furthermore that I have run all our queries through this code to ensure they still function as expected (this involved commenting out the slack.post_message part. Could probably also implement a dry-run functionality if we wanted.

Comment on lines +14 to +22
class QueryData:
"""Basic data structure constituting a Dune Analytics Query."""

name: str
query_id: int
params: Optional[list[QueryParameter]] = None


class BaseQueryMonitor(ABC):
class QueryBase(ABC):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here we split the query data into its own class and the base is now a true abstract class. Furthermore, run_loop method has been moved out of this class an into a new class called QueryRunner which has all the third party communication fields like dune and slack client (i.e. those which are required to run query and alert).

Comment on lines +1 to +4
"""
Elementary implementation of QueryBase that alerts when
number of results returned is > `threshold`
"""
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was previously the abstract base class. We moved the default implementations out of there so not to accidentally forget to implement methods and fallback on defaults when unintended.

Comment on lines -30 to +79
return self.fixed_params + self.left_bound.as_query_parameters()
return (self.query.params or []) + self.left_bound.as_query_parameters()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change will be apparent in a few places because python type checking does not allow you to set mutable defaults. This means that the QueryData.params class has to use an Optional[list] defaulting to None instead of a list defaulting to []. The parameters methods expect a list returned and one cannot concatenate None with a list type... this is how we roll.

Comment on lines +1 to +5
"""
Query Runner takes any implementation of QueryBase, a dune connection and slack client.
It is responsible for refreshing the query, fetching results,
passing results onto the query and alerting when necessary.
"""
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The heart of the change is here. We introduce QueryRunner. This separates and encapsulates the query details into QueryBase and the third party communication logic for executing and alerting. This makes the unit testing cleaner and should also make the project more maintainable.

@bh2smith bh2smith marked this pull request as ready for review August 26, 2022 02:46
Copy link

@gentrexha gentrexha left a comment

Choose a reason for hiding this comment

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

Really high quality work. Good job Ben!

Left some minor comments/discussion points/nitpicks. Other than that LGTM!

src/alert.py Outdated Show resolved Hide resolved
src/query_monitor/base.py Outdated Show resolved Hide resolved
if "window" in cfg:
# Windowed Query
window = TimeWindow.from_cfg(cfg["window"])
return WindowedQueryMonitor(name, query_id, window, params, threshold)

Choose a reason for hiding this comment

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

I really like the passing of QueryData object here instead of the many arguments. Another cool quote from Clean Code:

The ideal number of arguments for a function is
zero (niladic). Next comes one (monadic), followed
closely by two (dyadic). Three arguments (triadic)
should be avoided where possible. More than three
(polyadic) requires very special justification—and
then shouldn’t be used anyway.

src/query_monitor/result_threshold.py Outdated Show resolved Hide resolved
src/runner.py Outdated Show resolved Hide resolved
src/slackbot.py Outdated Show resolved Hide resolved
tests/test_implementations.py Show resolved Hide resolved
Copy link

@josojo josojo left a comment

Choose a reason for hiding this comment

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

It really makes the code easier to read. Nice job

src/alert.py Outdated Show resolved Hide resolved
@bh2smith bh2smith merged commit 2ee1e25 into main Aug 29, 2022
@bh2smith bh2smith deleted the remodeling-structures branch August 29, 2022 09:58
@bh2smith bh2smith mentioned this pull request Aug 29, 2022
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.

3 participants