-
Notifications
You must be signed in to change notification settings - Fork 359
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: Implement custom trigger for webhooks #9879
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #9879 +/- ##
==========================================
- Coverage 54.67% 54.61% -0.07%
==========================================
Files 1263 1263
Lines 156862 157047 +185
Branches 3597 3598 +1
==========================================
+ Hits 85768 85769 +1
- Misses 70963 71147 +184
Partials 131 131
Flags with carried forward coverage won't be shown. Click here to find out more.
|
✅ Deploy Preview for determined-ui canceled.
|
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 suggestions but otherwise web LGTM. would be nice to have unit testing but won't block on it.
useEffect(() => { | ||
if ((triggers || []).includes(V1TriggerType.CUSTOM)) { | ||
form.setFieldValue('mode', V1WebhookMode.SPECIFIC); | ||
} | ||
}, [triggers, form]); | ||
|
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.
nit: consolidate with existing useEffect
and/or move to onChange
?
name="mode" | ||
rules={[{ message: 'Webhook mode is required', required: true }]}> | ||
<Select | ||
disabled={(triggers || []).includes(V1TriggerType.CUSTOM)} |
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.
nit: don't think || []
throughout the file is necessary?
if (t.triggerType === V1TriggerType.CUSTOM) { | ||
return ( | ||
<li className={css.listBadge} key={t.id}> | ||
<Badge>CUSTOM</Badge> |
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.
nit: could use labels from triggerOptions
in WebhookCreateModal
?
|
||
// Event data for custom trigger. | ||
message CustomWebhookEventData { | ||
// The level for the event data. |
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 level for the event data. | |
// The level at which the event data is logged. |
if t.TriggerType == webhookv1.TriggerType_TRIGGER_TYPE_CUSTOM { | ||
if req.Webhook.Mode != webhookv1.WebhookMode_WEBHOOK_MODE_SPECIFIC { | ||
return nil, status.Errorf(codes.InvalidArgument, | ||
"custom trigger only works on webhook with mode 'SPECIFIC' got %v", |
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.
"custom trigger only works on webhook with mode 'SPECIFIC' got %v", | |
"custom trigger only works on webhook with mode 'SPECIFIC'. Got %v", |
type CustomTriggerData struct { | ||
Title string `json:"title"` | ||
Description string `json:"description"` | ||
Level string `json:"level"` |
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.
nit: Should we keep the CustomWebhookEventData
fields in the same order as this CustomTriggerData
?
Just so it's clear what the most important field(s) are (which is presumably the Title
field)
// Event data for custom trigger. | ||
message CustomWebhookEventData { | ||
// The level for the event data. | ||
determined.log.v1.LogLevel level = 1; |
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.
Should we make this log_level
?
determined.log.v1.LogLevel level = 1; | |
determined.log.v1.LogLevel log_level = 1; |
|
||
activeConfig, err := expconf.ParseAnyExperimentConfigYAML(m.ConfigBytes) | ||
if err != nil { | ||
return fmt.Errorf("error parsing experiment config : %w", err) |
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.
return fmt.Errorf("error parsing experiment config : %w", err) | |
return fmt.Errorf("error parsing experiment config: %w", err) |
master/static/migrations/20240828101021_custom-webhook-trigger.tx.up.sql
Show resolved
Hide resolved
@@ -223,3 +230,29 @@ func (a *WebhooksAPIServer) TestWebhook( | |||
} | |||
return &apiv1.TestWebhookResponse{}, nil | |||
} | |||
|
|||
// PostWebhookEventData handles data for custom trigger. | |||
func (a *WebhooksAPIServer) PostWebhookEventData( |
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.
Can we maybe add a couple of integration tests for this function?
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.
e2e tests for this function were accidentally dropped during a merge, now they should be restored
@@ -359,6 +390,7 @@ def init( | |||
_metrics=metrics, | |||
_tensorboard_manager=tensorboard_manager, | |||
_session=session, | |||
info=info, |
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.
Just for my understanding, why do we need info
now?
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.
Because we want to access the experiment id and trial id in alert
function
err = generateEventForCustomTrigger( | ||
ctx, &es, webhook.Triggers, webhook.WebhookType, webhook.URL, m.Experiment, activeConfig, data, trialID) | ||
if err != nil { | ||
return fmt.Errorf("error genrating event %d %+v: %w", webhookID, webhook, err) |
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.
return fmt.Errorf("error genrating event %d %+v: %w", webhookID, webhook, err) | |
return fmt.Errorf("error genrating event for webhook with ID %d %+v: %w", webhookID, webhook, err) |
} | ||
|
||
var es []Event | ||
if webhookConfig.WebhookID != nil { |
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.
(not a blocker)From the user perspective, since they can provide a list of webhook ids, where can a user find out the id of a webhook?
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.
Since webhook is not part of the CLI, user can only access the webhook ids from REST api. This is alright to me because we want to encourage user to use webhook name for readability, and using id is more like an add-on.
} | ||
|
||
if _, err := db.Bun().NewInsert().Model(&es).Exec(ctx); err != nil { | ||
return fmt.Errorf("report experiment state changed inserting event trigger: %w", err) |
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.
would the error message be something like handle custom trigger data inserting events
?
Where("name = ?", webhookName). | ||
Where("workspace_id = ?", workspaceID). |
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.
Nice, this makes sure only one webhook is selected if there are multiple webhooks with the same names but different url.
mStatus = string(e.State) | ||
} | ||
|
||
endTime := time.Now() |
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.
Why we need to set endTime to time.Now()?
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 could be wrong but it seems like endTime
is only used here to set the experiment duration in expBlockFields
, so if it hasn't completed yet (endTime == nil
), then we can get the duration from start time up until the present!
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.
Ah thanks! That calculates the experiment duration for a Slack message.
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.
Exactly, thanks @amandavialva01
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.
LGTM
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.
LGTM! Awesome work with this 😆
Ticket
MD-480
Description
Part of workload alerting project.
ERD link: https://hpe-aiatscale.atlassian.net/wiki/spaces/ENGINEERIN/pages/1666809868/Workload+Alerting+ERD
Implement trigger type
CUSTOM
for webhook.Test Plan
Create a webhook with custom trigger, note that for custom trigger, the mode of webhook can only be
Specific
.Within the same workspace as the webhook, create an experiment with config including
In the experiment code, trigger the webhook as
Verify that the webhook is triggered.
Checklist
docs/release-notes/
See Release Note for details.