Skip to content

feat(coderd): add new dispatch logic for coder inbox #16764

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

Merged
merged 22 commits into from
Mar 5, 2025

Conversation

defelmnq
Copy link
Contributor

@defelmnq defelmnq commented Mar 3, 2025

This PR is resolving the dispatch part of Coder Inbocx.

Since the DB layer has been merged - we now want to insert notifications into Coder Inbox in parallel of the other delivery target.

To do so, we push two messages instead of one using the Enqueue method.

@defelmnq defelmnq changed the title add new notification method feat(coderd): add new dispatch logic for coder inbox Mar 3, 2025
@defelmnq defelmnq marked this pull request as ready for review March 4, 2025 11:14
Copy link
Contributor

@dannykopping dannykopping left a comment

Choose a reason for hiding this comment

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

Good start, a few things we need to address but none of them huge.

@@ -79,7 +81,7 @@ func TestBufferedUpdates(t *testing.T) {
// Wait for the expected number of buffered updates to be accumulated.
require.Eventually(t, func() bool {
success, failure := mgr.BufferedUpdatesCount()
return success == expectedSuccess && failure == expectedFailure
return success == expectedSuccess*2 && failure == expectedFailure*2 // Each message is enqueued twice.
Copy link
Contributor

Choose a reason for hiding this comment

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

Your tests are going to become complicated once inbox can be disabled (by feature flag or otherwise).
I'd suggest creating a func which returns the configured targets and then you can len them instead of hardcoding magic numbers like this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried to clean it up a bit - still not perfect but as we do not have FF or experiment logic, please tell me if that's good enough.

Copy link
Contributor

Choose a reason for hiding this comment

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

No I think we need to take this further; there are several other places relying on this magic number.

@@ -77,7 +78,10 @@ func TestMetrics(t *testing.T) {

// Build fingerprints for the two different series we expect.
methodTemplateFP := fingerprintLabels(notifications.LabelMethod, string(method), notifications.LabelTemplateID, tmpl.String())
methodTemplateFPWithInbox := fingerprintLabels(notifications.LabelMethod, string(database.NotificationMethodInbox), notifications.LabelTemplateID, tmpl.String())
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need metrics for inbox?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I kept it to avoid any specific logic and as I felt like it could be interesting to have - no real other reason tbh.

@@ -19,7 +19,8 @@
"name": "bobby-workspace",
"reason": "autostart"
},
"data": null
"data": null,
"targets": null
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess we're never testing with targets?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

def not as much as we could - I added one on the logic but we can improve the golden files.

Copy link
Contributor

Choose a reason for hiding this comment

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

Which golden file did that update? I don't see it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok I took a bit longer than expected , but this targets never changes - it is part of the buildPayload which takes directly data fetched from db that does not contain the targets.

I'd like to clean it up as a follow-up PR, seems like there's some mixed fields with targets - one within the payload and another one outside of it.

Copy link
Contributor Author

@defelmnq defelmnq left a comment

Choose a reason for hiding this comment

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

Thanks @dannykopping for the first review - I tried to fix all your comments. 🙏

Just still have an open comment on the FF for inbox.

@@ -77,7 +78,10 @@ func TestMetrics(t *testing.T) {

// Build fingerprints for the two different series we expect.
methodTemplateFP := fingerprintLabels(notifications.LabelMethod, string(method), notifications.LabelTemplateID, tmpl.String())
methodTemplateFPWithInbox := fingerprintLabels(notifications.LabelMethod, string(database.NotificationMethodInbox), notifications.LabelTemplateID, tmpl.String())
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I kept it to avoid any specific logic and as I felt like it could be interesting to have - no real other reason tbh.

@@ -79,7 +81,7 @@ func TestBufferedUpdates(t *testing.T) {
// Wait for the expected number of buffered updates to be accumulated.
require.Eventually(t, func() bool {
success, failure := mgr.BufferedUpdatesCount()
return success == expectedSuccess && failure == expectedFailure
return success == expectedSuccess*2 && failure == expectedFailure*2 // Each message is enqueued twice.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried to clean it up a bit - still not perfect but as we do not have FF or experiment logic, please tell me if that's good enough.

@defelmnq defelmnq requested a review from dannykopping March 4, 2025 16:04
// THEN: we expect to see all but the final attempts failing
// the number of tries is equal to the number of messages times the number of attempts
// times 2 as the Enqueue method pushes into both the defined dispatch method and inbox
nbTries := msgCount * maxAttempts * 2
Copy link
Contributor

Choose a reason for hiding this comment

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

If we conditionalize when inbox is used in the future, this will become brittle and it won't be easily understood why; this is why magic numbers are to be avoided at all reasonable costs.

@@ -79,7 +81,7 @@ func TestBufferedUpdates(t *testing.T) {
// Wait for the expected number of buffered updates to be accumulated.
require.Eventually(t, func() bool {
success, failure := mgr.BufferedUpdatesCount()
return success == expectedSuccess && failure == expectedFailure
return success == expectedSuccess*2 && failure == expectedFailure*2 // Each message is enqueued twice.
Copy link
Contributor

Choose a reason for hiding this comment

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

No I think we need to take this further; there are several other places relying on this magic number.

@@ -19,7 +19,8 @@
"name": "bobby-workspace",
"reason": "autostart"
},
"data": null
"data": null,
"targets": null
Copy link
Contributor

Choose a reason for hiding this comment

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

Which golden file did that update? I don't see it.

@defelmnq
Copy link
Contributor Author

defelmnq commented Mar 5, 2025

I fixed most of the comments, but would like to create two follow-up PR :

  • One prio to implement a FF to enable / disable inbox. This one would need to be implemented just after the endpoints, and will also change the tests and way we compute number of messages sent etc..
  • One less prio that will define if we want to remove or not targets from payload as this value is set in two places, including one which is always null.

@defelmnq defelmnq requested a review from dannykopping March 5, 2025 14:39
@@ -34,7 +35,7 @@ func TestInbox(t *testing.T) {
payload: types.MessagePayload{
NotificationName: "test",
NotificationTemplateID: notifications.TemplateWorkspaceDeleted.String(),
UserID: "1e965b51-9465-43d8-ac20-c5f689f9c788",
UserID: "valid",
Copy link
Contributor

Choose a reason for hiding this comment

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

How is valid a valid UserID?

Copy link
Contributor

@dannykopping dannykopping left a comment

Choose a reason for hiding this comment

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

Approving to unblock, and for the outstanding comments to be addressed in a follow-up.

I would like to see the magic numbers replaced with a functional call to express which delivery targets are active (this will help when we allow multiple targets plus inbox, later). Having the feature flag (default on, possible opt-out) will naturally expose the need for this.

We just need to ensure this PR does not get cherry-picked into a release, otherwise customers will have no way to turn it off.

@defelmnq defelmnq merged commit 522181f into main Mar 5, 2025
30 checks passed
@defelmnq defelmnq deleted the notif-inbox/inte-403 branch March 5, 2025 21:43
@github-actions github-actions bot locked and limited conversation to collaborators Mar 5, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants