Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: send native system notification on scheduled workspace shutdown #1414

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 6 commits into from
May 13, 2022

Conversation

johnstcn
Copy link
Member

@johnstcn johnstcn commented May 12, 2022

This commit adds a fairly generic notification package and uses it
to notify users connected over SSH of pending workspace shutdowns.

It uses github.com/gen2brain/beeep under the hood for actually doing the platform-specific heavy lifting.

I've tested it out on MacOS and Windows and it seems to work fine there; I don't have a Linux desktop around with dbus and all of that associated stuff setup to test it there though.

The autobuild/notify package might be a bit of a step too far, but it lets me easily test the notification timing logic without worrying about anything else -- which is arguably the most important part.

Subtasks

  • Added a basic proof-of-concept
  • Refactored notification scheduling logic to its own package, unit tests.
  • Moved the actual notification meat and bones to the SSH command.

Additions

  • Ensured only one process at a time can notify per workspace (using gofrs/flock)
  • Added a convenience method notifier.Notify for folks who don't like making their own timers.

Fixes #861

This commit adds a fairly generic notification package and uses it
to notify users connected over SSH of pending workspace shutdowns.
@johnstcn johnstcn requested a review from a team May 12, 2022 21:08
@johnstcn johnstcn self-assigned this May 12, 2022
@codecov
Copy link

codecov bot commented May 12, 2022

Codecov Report

Merging #1414 (4f39908) into main (64e408c) will increase coverage by 0.08%.
The diff coverage is 70.96%.

@@            Coverage Diff             @@
##             main    #1414      +/-   ##
==========================================
+ Coverage   67.13%   67.22%   +0.08%     
==========================================
  Files         287      288       +1     
  Lines       19307    19424     +117     
  Branches      241      244       +3     
==========================================
+ Hits        12962    13057      +95     
- Misses       5007     5025      +18     
- Partials     1338     1342       +4     
Flag Coverage Δ
unittest-go-macos-latest 54.28% <70.96%> (+0.13%) ⬆️
unittest-go-postgres- 65.56% <70.96%> (-0.03%) ⬇️
unittest-go-ubuntu-latest 56.65% <70.96%> (+0.17%) ⬆️
unittest-go-windows-2022 52.65% <70.96%> (+0.13%) ⬆️
unittest-js 75.26% <ø> (+0.61%) ⬆️
Impacted Files Coverage Δ
cli/ssh.go 39.53% <35.71%> (-1.24%) ⬇️
coderd/autobuild/notify/notifier.go 100.00% <100.00%> (ø)
site/src/components/Section/Section.tsx 61.11% <0.00%> (-5.56%) ⬇️
site/src/xServices/auth/authXService.ts 78.12% <0.00%> (-4.49%) ⬇️
coderd/workspaceagents.go 55.34% <0.00%> (-2.56%) ⬇️
peer/channel.go 85.96% <0.00%> (ø)
coderd/rbac/object.go 100.00% <0.00%> (ø)
coderd/provisionerdaemons.go 63.31% <0.00%> (ø)
provisionerd/provisionerd.go 77.37% <0.00%> (ø)
site/src/xServices/auth/authSelectors.ts 100.00% <0.00%> (ø)
... and 8 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 64e408c...4f39908. Read the comment docs.

@bpmct
Copy link
Member

bpmct commented May 12, 2022

I've tested it out on MacOS and Windows and it seems to work fine there; I don't have a Linux desktop around with dbus and all of that associated stuff setup to test it there though.

Sounds like we need to add some templates for test desktops on v2 dogfood

Copy link
Member

@ammario ammario left a comment

Choose a reason for hiding this comment

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

Per my other comment, if the notification triggers on every open coder-cli instance, then this may overwhelm the user.

Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

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

Sorry for the sheer amount of comments 😅. I like how you managed to keep the condition logic simple!

t.Run(testCase.Name, func(t *testing.T) {
ch := make(chan time.Time)
numConditions := atomic.NewInt64(0)
numCalls := atomic.NewInt64(0)
Copy link
Member

Choose a reason for hiding this comment

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

Cool use of atomic, I need to remember this! ☺️

@johnstcn johnstcn requested review from mafredri, ammario and f0ssel May 13, 2022 11:37
Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

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

Just one more question but overall very nice!

type Notifier struct {
lock sync.Mutex
condition Condition
notifiedAt map[time.Duration]bool
Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense to move this into pollOnce? My thought is that this map never reset, and a notification can only be shown once per countdown entry (for the lifetime of the Notifier). Not sure if that's a problem or not though.

Copy link
Member Author

Choose a reason for hiding this comment

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

We could move into Poll, but not into pollOnce.
If we did that, we could probably also remove the sync.Mutex.
I like the idea of the same Notifier instance keeping track of what it's already notified between successive calls to Poll() though.

Copy link
Member

Choose a reason for hiding this comment

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

Ok that makes sense. I guess it's mostly a question of how the package is to be used and what the user (might) expect to happen. I imagine this will not be a problem for ssh since when the workspace stops, so does the command, so the notifier doesn't outlive its purpose.

Comment on lines +196 to +212
// Attempt to poll workspace autostop. We write a per-workspace lockfile to
// avoid spamming the user with notifications in case of multiple instances
// of the CLI running simultaneously.
func tryPollWorkspaceAutostop(ctx context.Context, client *codersdk.Client, workspace codersdk.Workspace) (stop func()) {
lock := flock.New(filepath.Join(os.TempDir(), "coder-autostop-notify-"+workspace.ID.String()))
condition := notifyCondition(ctx, client, workspace.ID, lock)
return notify.Notify(condition, autostopPollInterval, autostopNotifyCountdown...)
}

// Notify the user if the workspace is due to shutdown.
func notifyCondition(ctx context.Context, client *codersdk.Client, workspaceID uuid.UUID, lock *flock.Flock) notify.Condition {
return func(now time.Time) (deadline time.Time, callback func()) {
// Keep trying to regain the lock.
locked, err := lock.TryLockContext(ctx, autostopPollInterval)
if err != nil || !locked {
return time.Time{}, nil
}
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if it'd be best to place as much of this as possible in the notify package. eg. for coder port-forward we'd probably want to do the exact same type of thing.

I could imagine for the frontend too, we would send a notification via WebSocket or something!

Copy link
Member Author

Choose a reason for hiding this comment

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

That could be a good idea when we have a better idea of what different use-cases crop up.
I fear I've already over-engineered this enough as it is!

Copy link
Member

@ammario ammario left a comment

Choose a reason for hiding this comment

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

I didn't review the code, but if only one notification is sent across all coder-clis, I'm good with this.

@johnstcn johnstcn merged commit b2760b1 into main May 13, 2022
@johnstcn johnstcn deleted the cj/gh-861/cli-autostop-notify branch May 13, 2022 17:09
@misskniss misskniss added this to the V2 Beta milestone May 15, 2022
kylecarbs pushed a commit that referenced this pull request Jun 10, 2022
…#1414)

* feat: send native system notification on scheduled workspace shutdown

This commit adds a fairly generic notification package and uses it
to notify users connected over SSH of pending workspace shutdowns.
Only one notification will be sent at most 5 minutes prior to the scheduled
shutdown, and only one CLI instance will send notifications if multiple
instances are running.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

On SSH connection, notify users of scheduled auto-stop for Auto On/Off
7 participants