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

✨ poc(nowa): poc for issue alert migration #81288

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

iamrajjoshi
Copy link
Member

@iamrajjoshi iamrajjoshi commented Nov 26, 2024

this is a poc to see how issue alerts notifications will work using NOWA in ACI.

i am planning to build this out so we can fire notifications, but currently i have the migration path from Rule -> Action and the first part of the NOWA logic, which translates an Action to legacy models (Rule and RuleFireHistory)

edit: added the invoke_nowa function and was able to successfully send a notification using the new models.

currently i convert a Rule to Action and back to a Rule, and send a notification using the new rule.

@iamrajjoshi iamrajjoshi added the Do Not Merge Don't merge label Nov 26, 2024
@iamrajjoshi iamrajjoshi requested a review from a team November 26, 2024 00:49
@iamrajjoshi iamrajjoshi self-assigned this Nov 26, 2024
@@ -21,8 +39,36 @@ class Action(DefaultFieldsModel):

# TODO (@saponifi3d): Don't hardcode these values, and these are incomplete values
class Type(models.TextChoices):
Copy link
Member Author

Choose a reason for hiding this comment

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

this can change. just have this here so i can use this

Copy link
Contributor

Choose a reason for hiding this comment

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

👍 yeah - let's update this a bit, happy to chat through ideas!

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Nov 26, 2024
Copy link

codecov bot commented Nov 26, 2024

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
322 1 321 9
View the top 1 failed tests by shortest run time
::tests.sentry.workflow_engine.actions.notification_action.test_notification_action
Stack Traces | 0s run time
No failure message available

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

src/sentry/rules/processing/processor.py Outdated Show resolved Hide resolved
src/sentry/workflow_engine/nowa/logic.py Outdated Show resolved Hide resolved
src/sentry/workflow_engine/nowa/logic.py Outdated Show resolved Hide resolved
Action.Type.NOTIFICATION_EMAIL,
]
)
def notification_action_handler(action: Action, group_event: GroupEvent):
Copy link
Member Author

@iamrajjoshi iamrajjoshi Nov 27, 2024

Choose a reason for hiding this comment

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

this is the entrypoint of NOWA, it will be invoked when someone calls trigger_action with one of the registered action types

Copy link
Member Author

Choose a reason for hiding this comment

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

i am having trouble with this registry registering in 1 of my tests, if i import it it claims i registered this function twice. if i don't, it says this isn't registered 😕

Copy link
Contributor

Choose a reason for hiding this comment

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

i think it might be the way you're using the registry. i'd just do something like, @action_handler_registry.register(Action.Type.NOTIFICATION) to encapsulate any notification.

you can also stack the decorators if we keep many kinds of notifications:

@action_handler_registry.register(Action.Type.NOTIFICATION_SLACK)
@action_handler_registry.register(Action.Type.NOTIFICATION_DISCORD)
@action_handler_registry.register(Action.Type.NOTIFICATION_MSTEAMS)
def notification_action_handler(action: Action, group_event: GroupEvent):
    pass

raise ValueError(f"No handler found for action type: {action.type}")


def trigger_action(action: Action, group_event: GroupEvent):
Copy link
Member Author

Choose a reason for hiding this comment

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

other parts of ACI can call this function which will trigger nowa if the action.type is correct

@@ -0,0 +1,137 @@
import uuid
Copy link
Member Author

Choose a reason for hiding this comment

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

meat of nowa

Comment on lines 13 to 37
def register_action_handler(action_types: list[Action.Type]):
"""
Decorator to register a handler for specific action types.

Usage:
@register_action_handler([Action.Type.NOTIFICATION_SLACK, Action.Type.NOTIFICATION_DISCORD])
def notification_action_handler(action: Action, group_event: GroupEvent):
...
"""

def decorator(handler_class: ActionHandler):
for action_type in action_types:
action_handler_registry.register(action_type.value)(handler_class)
return handler_class

return decorator


def get_handler(action: Action) -> ActionHandler:
"""Get the handler instance for a given action."""
try:
handler_class = action_handler_registry.get(action.type.value)
return handler_class()
except NoRegistrationExistsError:
raise ValueError(f"No handler found for action type: {action.type}")
Copy link
Contributor

Choose a reason for hiding this comment

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

you shouldn't nee to create these, you can just use the action_handler_registry directly.

@action_handler_registry.register(Action.Type)
def handler(action: Action, group_event: GroupEvent):
    pass

and

action_handler_register.get(Action.Type)

(i can also create these as they're part of milestone 1 -- i'm about to need this registry on my branch, i'll probably just copy pasta bits of this 🎉)

from sentry.workflow_engine.models.detector import Detector


def build_rule_data_blob(action: Action) -> list[dict[str, Any]]:
Copy link
Contributor

Choose a reason for hiding this comment

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

is this dict shaped like anything in particular? it seems like we always have an id, uuid, integration_id_key (based on the action type), etc -- can we make a type that encapsulates the expected shape?

@@ -0,0 +1,137 @@
import uuid
from typing import Any
Copy link
Contributor

Choose a reason for hiding this comment

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

After moving around the other files, we could then update this to be notification_action.py -- that might be nice to keep it actions/<action_implementation>.py - and keeping it flat is one of the big wins of using a registry for just the handler method.

}


def build_notification_actions_from_rule_data(actions: list[dict[str, Any]]) -> list[Action]:
Copy link
Contributor

Choose a reason for hiding this comment

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

how can we improve the typing here? Is there a specific format for each action?

:param group_event: GroupEvent model instance
"""

rule, rule_fire_history, notification_uuid = form_issue_alert_models(
Copy link
Contributor

Choose a reason for hiding this comment

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

for production code, let's add a span to this method so we can see how long we're spending creating legacy models per notification.

:param group_event: GroupEvent model instance
"""

rule, rule_fire_history, notification_uuid = form_issue_alert_models(
Copy link
Contributor

Choose a reason for hiding this comment

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

also, should we add a check to see if we need to create a new rule vs fetching an existing rule from the db?

)

# TODO(iamrajjoshi): Add a check to see if the rule has only one action
assert len(rule.data.get("actions", [])) == 1
Copy link
Contributor

Choose a reason for hiding this comment

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

a little nervous that this will really increase the number of rules we have in the db; it seems like for each notification we're sending; we'll be creating a new rule (so if the workflow has 5 actions, we'll create 5 rules with 1 action each). It also seems like we're creating it every time, but not removing it and not reusing it.

}


class RuleDataBlob:
Copy link
Member Author

Choose a reason for hiding this comment

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

working through this at the moment, need to figure out how we can handle dynamic fields

"""
IntegrationIdKey is the key used to identify the integration in the rule data.
"""
IntegrationIdKey = Union[
Copy link
Member Author

Choose a reason for hiding this comment

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

not used atm

@iamrajjoshi iamrajjoshi force-pushed the raj/nowa/issue-alert-migration-poc branch from 35b8b7e to 488376e Compare December 4, 2024 01:46
@iamrajjoshi iamrajjoshi changed the base branch from master to jcallender/aci-evaluate-workflow-actions December 5, 2024 00:08
Base automatically changed from jcallender/aci-evaluate-workflow-actions to master December 5, 2024 18:16
@iamrajjoshi iamrajjoshi closed this Dec 9, 2024
@iamrajjoshi iamrajjoshi force-pushed the raj/nowa/issue-alert-migration-poc branch from 488376e to b186dea Compare December 9, 2024 21:20
@getsantry
Copy link
Contributor

getsantry bot commented Dec 31, 2024

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you remove the label Waiting for: Community, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

@getsantry getsantry bot added the Stale label Dec 31, 2024
@getsantry getsantry bot closed this Jan 8, 2025
@iamrajjoshi iamrajjoshi added the WIP label Jan 8, 2025
@iamrajjoshi iamrajjoshi reopened this Jan 8, 2025
@iamrajjoshi iamrajjoshi removed the Stale label Jan 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Do Not Merge Don't merge Scope: Backend Automatically applied to PRs that change backend components WIP
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants