Repository navigation
feat: add notification for task status - #19965
Conversation
62ff41a to
b20b801
Compare
| enabled_by_default | ||
| ) VALUES ( | ||
| 'bd4b7168-d05e-4e19-ad0f-3593b77aa90f', | ||
| 'Task Working', |
There was a problem hiding this comment.
I kept the terminology aligned with the current workspace agent app status (Working, Idle). In PR: https://github.com/coder/coder/pull/19773/files#diff-1894d4f2ccb1125739e504fc6d8d3a7daeec9dd829a81c342cf28f3e92efbf58R2-R7 I see the task status types differ. Is that finalized? If yes, should I update this PR to adopt the new task status terms?
| if workspaceBuild.HasAITask.Valid && workspaceBuild.HasAITask.Bool && | ||
| workspaceBuild.AITaskSidebarAppID.Valid && workspaceBuild.AITaskSidebarAppID.UUID == app.ID { |
There was a problem hiding this comment.
With the current data model, this is the correct way to determine if a workspace agent app is an AI task, right?
There was a problem hiding this comment.
For now, yes. This will need to be refactored later.
| if workspaceBuild.HasAITask.Valid && workspaceBuild.HasAITask.Bool && | ||
| workspaceBuild.AITaskSidebarAppID.Valid && workspaceBuild.AITaskSidebarAppID.UUID == app.ID { |
There was a problem hiding this comment.
For now, yes. This will need to be refactored later.
| notificationTemplate = notifications.TemplateTaskIdle | ||
| } | ||
|
|
||
| if _, err := api.NotificationsEnqueuer.EnqueueWithData( |
There was a problem hiding this comment.
Before we enqueue a notification, we should ensure that the new task status is different to the previous. An agent could insert multiple app statuses with the same state but different messages e.g.
- "working / doing thing A"
- "working / doing thing B"
There was a problem hiding this comment.
Ok, that is good to know. I was not aware it was possible for a task to transition to the same status. Addressed in 06ed8c7
mafredri
left a comment
There was a problem hiding this comment.
Looks good to me, nice work 👍🏻. Not much to add from what Cian already, just one question/potential gotcha.
| // Include a minute-bucketed timestamp to bypass per-day dedupe, | ||
| // allowing identical content to resend within the same day | ||
| // (but not more than once per minute) | ||
| "dedupe_bypass_ts": api.Clock.Now().UTC().Truncate(time.Minute), |
There was a problem hiding this comment.
How does this work if the task quickly jumps between working/idle/working? Is there a chance we miss the second working and never emit it? If yes, I think that would lead to bad UX as the notifications are untrustworthy.
There was a problem hiding this comment.
If a task were to go through the state transition Idle -> Working -> Idle -> Working -> Idle all within the space of a minute, you'd only get the initial -> Working and -> Idle notifications.
There was a problem hiding this comment.
Thanks for confirming, that's what I suspected. It gets a bit funky when we're bordering on the minute mark.
14:39:00 Working
14:39:29 Idle
14:39:59 Working
14:40:30 Idle
We get Working -> Idle -> Idle (alt. Idle -> Working -> Working).
There was a problem hiding this comment.
Yes, that’s a good point. There are still scenarios where the system could skip some notification types, resulting in the same type being sent back-to-back. The minute-level dedupe was intended as a safeguard to avoid spamming users. Based on the problem definition "By definition tasks may take quite a long time to be completed. We do not want the users to stare at the screen waiting because that invalidates the whole purpose." the assumption was that these transitions wouldn’t happen very quickly.
Instead of truncating to the minute, should we use the exact timestamp? That would avoid missing intermediate states, but it does increase the risk of too many notifications. Open to suggestions 😊
There was a problem hiding this comment.
Unfortunately I think there is no perfect solution here. We could still truncate to the second, but like before, any truncation runs the risk of missing a notification. I'd be satisfied with truncating it down to the second. @mafredri thoughts?
There was a problem hiding this comment.
I'd rather risk missing some notifications than spamming and potentially overloading coderd or whatever notification backed is in use.
There was a problem hiding this comment.
Second or even 5-10 second truncate would work. 👍🏻 Especially if we implement the safeguard that Cian mentioned, i.e. previous status must have been different from current status, then we minimize the risk of spam.
There was a problem hiding this comment.
Added a 10-second truncate to the dedupe key and a check to send notifications only on new transitions.
Addressed in 06ed8c7
johnstcn
left a comment
There was a problem hiding this comment.
Some comments below, but I don't need to review again.
There was a problem hiding this comment.
Obligatory reminder to check migration number before merge!
| -- name: GetLatestWorkspaceAppStatusesByAppID :many | ||
| SELECT * | ||
| FROM workspace_app_statuses | ||
| WHERE app_id = @app_id::uuid | ||
| ORDER BY created_at DESC, id DESC; | ||
|
|
There was a problem hiding this comment.
Would it make sense to instead add an ORDER BY clause to GetWorkspaceAppStatusesByAppIDs?
There was a problem hiding this comment.
We could add ORDER BY to GetWorkspaceAppStatusesByAppIDs and rename it to reflect the ordering (e.g., GetLatestWorkspaceAppStatusesByAppIDs). For this PR I only need one app, newest-first, so the dedicated query seemed to keep things clearer.
DanielleMaywood
left a comment
There was a problem hiding this comment.
Approve with a non-blocking issue:
| } | ||
|
|
||
| func (q *querier) GetLatestWorkspaceAppStatusesByAppID(ctx context.Context, appID uuid.UUID) ([]database.WorkspaceAppStatus, error) { | ||
| if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil { |
There was a problem hiding this comment.
I realize the other functions around here do the same but I think we were wanting to stop introducing more uses of ResourceSystem
There was a problem hiding this comment.
AFAIK, there isn’t a dedicated resource for workspace apps, so operations on them currently authorize against rbac.ResourceSystem. I’m not sure what the best alternative is, skipping the authorization check would make this data accessible to anyone, which we don’t want.
There was a problem hiding this comment.
This is unfortunately a pre-existing issue from the introduction of app statuses. It may be worth addressing in a follow-up.
Description
Send a notification to the workspace owner when an AI task’s app state becomes
WorkingorIdle.An AI task is identified by a workspace build with
HasAITask = trueandAITaskSidebarAppIDmatching the agent app’s ID.Changes
TemplateTaskWorkingnotification template.TemplateTaskIdlenotification template.GetLatestWorkspaceAppStatusesByAppIDSQL query to get the workspace app statuses ordered by latest first.PATCH /workspaceagents/me/app-statusto enqueue:TemplateTaskWorkingwhen state transitions toworkingTemplateTaskIdlewhen state transitions toidletask: task initial promptworkspace: workspace nameCloses: #19776