Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: implement thin vertical slice of system-generated notifications#13537

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
dannykopping merged 30 commits intomainfromdk/system-notifications-lib
Jul 8, 2024

Conversation

dannykopping
Copy link
Contributor

@dannykoppingdannykopping commentedJun 11, 2024
edited
Loading

NOTE: this is a stacked PR, please review#13536 as well.

This introduces a new subsystem into Coder to enable notifications (seemilestone). In this PR, I have implemented a very thin vertical slice of this functionality:

  • immutable system-generated notificationsonly (later we will expand this to operator-managed notifications)
  • SMTP and webhook deliveryonly
    • SMTP auth & TLS is not yet enabled; will be added subsequently
    • additional notification methods to come later as well

This functionality is also hidden behind an experiment.


The main entities in this package are:

Notifier is responsible for:

  • periodically dequeuing pendingnotification_messages entries
  • preparing them for delivery
  • delivering them
  • informing theManager of successful/failed deliveries

Manager is a controller which is responsible for:

  • facilitating the enqueuing of new messages
  • starting up queue consumers (Notifiers)
  • periodically updating the store with delivery updates
  • managing its own and theNotifiers' lifecycles (run/shutdown)

The queue has been designed to be safe for concurrent use. This can either mean multiplecoderd instances running side-by-side and/or eachcoderd having multiple queue consumers.

stirby reacted with thumbs up emoji
@dannykoppingGraphite App
Copy link
ContributorAuthor

dannykopping commentedJun 11, 2024
edited
Loading

@dannykoppingdannykoppingforce-pushed thedk/system-notifications-lib branch 2 times, most recently froma1b4e2b tod2a947aCompareJune 11, 2024 12:52
@dannykoppingdannykoppingforce-pushed thedk/system-notifications-database branch from1cb776a to25636ecCompareJune 11, 2024 13:15
@dannykoppingdannykoppingforce-pushed thedk/system-notifications-lib branch 2 times, most recently fromdc359de to2e16d76CompareJune 11, 2024 13:40
@dannykoppingdannykopping changed the titlefeat: system-generated notificationsfeat: implement thin vertical slice of system-generated notificationsJun 11, 2024
@dannykoppingdannykopping marked this pull request as ready for reviewJune 11, 2024 14:13
@dannykoppingdannykoppingforce-pushed thedk/system-notifications-lib branch fromd8f51ce to284b781CompareJune 12, 2024 08:33
@dannykoppingdannykoppingforce-pushed thedk/system-notifications-database branch from1c4046c to538bc42CompareJune 12, 2024 09:08
@dannykoppingdannykoppingforce-pushed thedk/system-notifications-lib branch from284b781 to9fd8527CompareJune 12, 2024 10:50
@dannykoppingdannykoppingforce-pushed thedk/system-notifications-database branch from538bc42 to438bcbaCompareJune 12, 2024 10:51
@github-actionsgithub-actionsbot added the staleThis issue is like stale bread. labelJun 20, 2024
@johnstcnjohnstcn reopened thisJun 23, 2024
@johnstcnjohnstcn removed the staleThis issue is like stale bread. labelJun 23, 2024
@dannykoppingdannykoppingforce-pushed thedk/system-notifications-database branch from438bcba toc1a3010CompareJune 27, 2024 09:46
@dannykoppingdannykoppingforce-pushed thedk/system-notifications-lib branch from9fd8527 to8b7fa18CompareJune 27, 2024 09:47
Base automatically changed fromdk/system-notifications-database tomainJune 28, 2024 09:21
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Copy link
Member

@johnstcnjohnstcn left a comment

Choose a reason for hiding this comment

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

Some comments below but I don't need to review again. 👍

spikecurtis
spikecurtis previously requested changesJul 3, 2024
require.Eventually(t, func() bool { return santa.naughty.Load() == 1 && santa.nice.Load() == 2 }, testutil.WaitMedium, testutil.IntervalFast)

// Stop the manager which forces an update of buffered updates.
require.NoError(t, mgr.Stop(ctx))
Copy link
Contributor

Choose a reason for hiding this comment

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

there is a race condition here, which is that above we wait for notifications to be sent to santa, but sending to santa happensbefore sending on thesuccess andfailure channels. So, triggering stop and the final bulk update might miss one or more success/failure updates and cause this test to flake.

Quartz can help here. The manager's bulk update and the notifier's processing loop depend on Tickers. If you convert them to use aquartz.TickerFunc, then you can control the mock clock and trigger the processing loop and bulk update, and wait for them to finish.

This lets us get rid of theEventually that checks for dispatched notifications (Quartz allows you to wait until the tick processing is done, so there is no race in just asserting santa got what we expected).

It also means we can get rid of theEventually below for the same reason --- we can wait for bulk processing to complete before asserting theinterceptor's state.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I've got a follow-up item to implement Quartz in a subsequent PR.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Addressed in613e074

Copy link
Member

@mtojekmtojek left a comment

Choose a reason for hiding this comment

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

Awesome work! It's a pity we couldn't get this PR in smaller chunks.

I left a few comments, please forgive if some of them were already discussed. I didn't track the whole thread.


// WebhookPayload describes the JSON payload to be delivered to the configured webhook endpoint.
type WebhookPayload struct {
Version string `json:"_version"`
Copy link
Member

Choose a reason for hiding this comment

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

nit: that needs to be published in our Coder docs

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Good call, will add as a follow-up.

return ctx.Err()
default:
logger.Warn(ctx, "message dispatch failed", slog.Error(err))
failure <- newFailedDispatch(n.id, msg.ID, err, retryable)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is still racy. What you want is

select {    case <-ctx.Done():        return ctx.Err()    case failure <- newFailedDispatch(n.id, msg.ID, err, retryable):}

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

My understanding is thatdefault will only be called if there are no cases which can proceed.
https://go.dev/ref/spec#Select_statements

Execution of a "select" statement proceeds in several steps:
...
2. If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. ...

Am I misunderstanding something?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's true thatdefault only executes if it is the only case that can succeed, but then writing tofailure is a TOCTOU race.

Signed-off-by: Danny Kopping <danny@coder.com>
Signed-off-by: Danny Kopping <danny@coder.com>
Copy link
Member

@johnstcnjohnstcn left a comment

Choose a reason for hiding this comment

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

I smoke-tested enabling the experiment with no further configuration via docker-compose, and didn't see anything immediately break.

dannykopping reacted with thumbs up emoji
@dannykopping
Copy link
ContributorAuthor

@spikecurtis since you appear to be on PTO this week, and since I have made a reasonable effort to address all of your comments, I'm going to merge this. I've resolved all of the trivial comments and kept the substantive ones open to prompt further discussion when you return. This is behind an experiment and is reasonably self-contained, so I feel merging this is quite safe. Thanks very much for your thoughtful reviews!

@dannykoppingdannykopping merged commitbdd2caf intomainJul 8, 2024
34 checks passed
@dannykoppingdannykopping deleted the dk/system-notifications-lib branchJuly 8, 2024 13:38
@github-actionsgithub-actionsbot locked and limited conversation to collaboratorsJul 8, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers

@EmyrkEmyrkEmyrk left review comments

@mtojekmtojekmtojek approved these changes

@johnstcnjohnstcnjohnstcn approved these changes

@kylecarbskylecarbsAwaiting requested review from kylecarbs

@spikecurtisspikecurtisAwaiting requested review from spikecurtis

Assignees

@dannykoppingdannykopping

Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

5 participants
@dannykopping@johnstcn@spikecurtis@Emyrk@mtojek

[8]ページ先頭

©2009-2025 Movatter.jp