-
Notifications
You must be signed in to change notification settings - Fork 0
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
Feat: Add a generic webhook for sending event notifications #879
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #879 +/- ##
==========================================
+ Coverage 89.43% 89.75% +0.32%
==========================================
Files 121 124 +3
Lines 3701 3769 +68
Branches 741 753 +12
==========================================
+ Hits 3310 3383 +73
+ Misses 379 374 -5
Partials 12 12 ☔ View full report in Codecov by Sentry. |
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.
Some comments in line
src/types/index.ts
Outdated
export type GenericEvent = { | ||
source: string; | ||
timestamp: number; | ||
service_name?: string; // Official service registry name if applicable |
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.
What are you going to use this for ? If I remember correctly the service registry was supposed to be used to route messages to the right channel, but the channel is also passed as a parameter.
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.
Yes, the idea was to use the service-registry if the service_name is supplied, but I'm not sure if everything that will use this in the future will be associated with a service. If we can make that guarantee, I can remove the channel parameter
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.
If we can make that guarantee, I can remove the channel parameter
we cannot make this guarantee.
So the problem is the same as below. Please let's not have an api method with a lot of optional fields at the same level and rely on the user to know which combination are valid and which ones are not.
Instead, I would suggest one of these two so that making mistakes is harder:
- Have more granular methods: one for slack with smart routing that goes to service and one where we specify the channel. Though we need to think through which methods we are going to build upfront.
- Have one method but provide different structured types for the different types of notification: slack with direct routing, slack with service routing (service is relevant only for slack), jira, datadog, etc.
src/types/index.ts
Outdated
channels: { | ||
slack?: string[]; // list of Slack Channels | ||
datadog?: string[]; // list of DD Monitors | ||
jira?: string[]; // list of Jira Projects | ||
bigquery?: string; | ||
}; | ||
tags?: string[]; // Not used for Slack | ||
misc: { | ||
alertType?: EventAlertType; // Datadog alert type | ||
blocks?: (KnownBlock | Block)[]; // Optional Slack blocks |
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 has been quite some time since when we discussed this design.
I cannot remember anymore whether the generic event was supposed to know where to route the message or whether it was supposed to be the simple api the user would use to route a message to a specific channel.
If it is the first (the user sends the message and there is logic in eng-pipes that figures out where to route the message) then it should not be a generic event and it should not contain channel specific parameters (like tags and the list of channels)
If it is the simple one (the user picks the channel), then I don't think putting all the channel fields in the same message and api is a good design, you should have dedicated apis per channel. It would be quite hard to understand which fields are supposed to be populated in which scenario.
If there are good reaons to have one api (still in the simple option where eng-pipes does not provide any routing loigic) and if you wanted to support multiple channels in one api call then a better api design would be to require a list of objects, each object containing all the details needed for a specific channel:
channel[]
where channel is the union of
Slack: {
channel: string
blocks
}
Datadog {
monitor: string
tags: string[]
}
...
If there are common fields they can be specified only once.
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.
I think the idea was to have a combination of both: a generic, simple api which a user can use to route a message to a specific channel, and a more complex webhook which has logic to route more complicated events.
I agree that the typing for the generic event payload can be improved, will work on that
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.
Defining the public api of a service is a task that should be thought through carefully as changing it afterwards when clients are using is hard.
So feel free to take the time to think the details of all the apis method you expect to create and send a PR with only those types and the empty business logic so we can review if the whole api is coherent and meaningful.
await messageSlack(body); | ||
await sendEventToDatadog(body, moment().unix()); |
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.
Where are the other channels ?
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.
The only other one was Jira, but never really got around to getting that added since Alex was (i think?) working a little on the env setup, so I was originally waiting for him to get that done first.
message: GenericEvent, | ||
timestamp: number | ||
) { | ||
if (message.data.channels.datadog) { |
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.
I'd like a pattern where you decide which methods to call in the genericEventNotifier
function. That is the orchestrating function, which parses the message and trigger the relevant channels. From their name sendEventToDatadog
and messageSlack
should always send the message, not decide when not to send.
Dockerfile
Outdated
RUN mkdir -p ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts | ||
|
||
# Install production dependencies. & update service-registry to main | ||
RUN --mount=type=ssh yarn install --immutable && yarn up "service-registry@git+ssh://[email protected]:getsentry/service-registry#main" |
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.
I don't think you can do this.
service-registry is private, this is still a public repo.
I'd suggest you skip this part for now.
I think you will have to provide the service registry as a config file when you deploy the system, not as a package in the image.
src/types/index.ts
Outdated
export interface SlackMessage { | ||
type: 'slack'; | ||
channels: string[]; | ||
text: string; | ||
blocks?: KnownBlock[] | Block[]; | ||
} | ||
|
||
export interface DatadogEvent { | ||
type: 'datadog'; | ||
title: string; | ||
text: string; | ||
tags: string[]; | ||
alertType: EventAlertType; | ||
} | ||
|
||
export interface JiraEvent { | ||
type: 'jira'; | ||
projectId: string; | ||
title: string; | ||
} | ||
|
||
export type GenericEvent = { | ||
source: string; | ||
timestamp: number; | ||
data: (DatadogEvent | JiraEvent | SlackMessage | ServiceSlackMessage)[]; | ||
}; |
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.
Ok, this is better.
src/types/index.ts
Outdated
// Currently only used for Slack notifications since | ||
// service registry only contains Slack channels (and not DD or Jira or others) | ||
export interface ServiceSlackMessage { | ||
type: 'service_notification'; | ||
service_name: string; // Official service registry service id | ||
text: string; | ||
blocks?: KnownBlock[] | Block[]; | ||
} |
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.
This seems the same as the slack message, except that you can provide the channel via a service name.
Doing it this way would mean we would duplicate all the methods that can take a destination from the service registry.
Why not abstracting the concept of SlackChannel, and pass it here https://github.com/getsentry/eng-pipes/pull/879/files#diff-a9ba9cbedd19c9f66d564d2e89912890209b98f0a7ef19187877d2587300e476R34 .
You can create two implementations: SlackChannel and ServiceSlackChannel. One contains the channel name and the other contains the service name.
b4961f7
to
c61f87c
Compare
This PR adds a generic webhook:
/event-notifier/v1
which can be used to send events and messages to Slack and DD (with support for Jira coming soon).