From 9e07bb40ee66387252443b177a58aa366e8b42bc Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Fri, 25 Oct 2024 19:42:42 +0000 Subject: [PATCH 01/11] fix: stop activity bump if no tracked sessions --- coderd/workspacestats/reporter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/workspacestats/reporter.go b/coderd/workspacestats/reporter.go index 6bb1b2dea4028..20e3cf7160e2c 100644 --- a/coderd/workspacestats/reporter.go +++ b/coderd/workspacestats/reporter.go @@ -136,8 +136,8 @@ func (r *Reporter) ReportAgentStats(ctx context.Context, now time.Time, workspac }, stats.Metrics) } - // if no active connections we do not bump activity - if stats.ConnectionCount == 0 { + // if no active sessions we do not bump activity + if stats.SessionCountJetbrains == 0 && stats.SessionCountVscode == 0 && stats.SessionCountReconnectingPty == 0 && stats.SessionCountSsh == 0 { return nil } From d702dca0279497413391a774dad5f1f16c72663b Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Fri, 25 Oct 2024 19:52:57 +0000 Subject: [PATCH 02/11] fix: do not bump activity with no sessions --- coderd/agentapi/stats_test.go | 38 ++--------------------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/coderd/agentapi/stats_test.go b/coderd/agentapi/stats_test.go index 83edb8cccc4e1..b3676d1f192ba 100644 --- a/coderd/agentapi/stats_test.go +++ b/coderd/agentapi/stats_test.go @@ -325,6 +325,7 @@ func TestUpdateStates(t *testing.T) { "dean": 2, }, ConnectionCount: 3, + SessionCountSsh: 3, }, } ) @@ -409,11 +410,7 @@ func TestUpdateStates(t *testing.T) { } batcher = &workspacestatstest.StatsBatcher{} updateAgentMetricsFnCalled = false - tickCh = make(chan time.Time) - flushCh = make(chan int, 1) - wut = workspacestats.NewTracker(dbM, - workspacestats.TrackerWithTickFlush(tickCh, flushCh), - ) + wut = workspacestats.NewTracker(dbM) req = &agentproto.UpdateStatsRequest{ Stats: &agentproto.Stats{ @@ -479,39 +476,15 @@ func TestUpdateStates(t *testing.T) { // Workspace gets fetched. dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(workspace, nil) - // We expect an activity bump because ConnectionCount > 0. - dbM.EXPECT().ActivityBumpWorkspace(gomock.Any(), database.ActivityBumpWorkspaceParams{ - WorkspaceID: workspace.ID, - NextAutostart: time.Time{}.UTC(), - }).Return(nil) - - // Workspace last used at gets bumped. - dbM.EXPECT().BatchUpdateWorkspaceLastUsedAt(gomock.Any(), database.BatchUpdateWorkspaceLastUsedAtParams{ - IDs: []uuid.UUID{workspace.ID}, - LastUsedAt: now, - }).Return(nil) - // User gets fetched to hit the UpdateAgentMetricsFn. dbM.EXPECT().GetUserByID(gomock.Any(), user.ID).Return(user, nil) - // Ensure that pubsub notifications are sent. - notifyDescription := make(chan []byte) - ps.Subscribe(codersdk.WorkspaceNotifyChannel(workspace.ID), func(_ context.Context, description []byte) { - go func() { - notifyDescription <- description - }() - }) - resp, err := api.UpdateStats(context.Background(), req) require.NoError(t, err) require.Equal(t, &agentproto.UpdateStatsResponse{ ReportInterval: durationpb.New(10 * time.Second), }, resp) - tickCh <- now - count := <-flushCh - require.Equal(t, 1, count, "expected one flush with one id") - batcher.Mu.Lock() defer batcher.Mu.Unlock() require.EqualValues(t, 1, batcher.Called) @@ -519,13 +492,6 @@ func TestUpdateStates(t *testing.T) { require.EqualValues(t, 0, batcher.LastStats.SessionCountJetbrains) require.EqualValues(t, 0, batcher.LastStats.SessionCountVscode) require.EqualValues(t, 0, batcher.LastStats.SessionCountReconnectingPty) - ctx := testutil.Context(t, testutil.WaitShort) - select { - case <-ctx.Done(): - t.Error("timed out while waiting for pubsub notification") - case description := <-notifyDescription: - require.Equal(t, description, []byte{}) - } require.True(t, updateAgentMetricsFnCalled) }) } From 218f4b0c28bdc0646b85b74634d67e4d2c329f1a Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Mon, 28 Oct 2024 16:07:56 +0000 Subject: [PATCH 03/11] fix test --- agent/agent.go | 6 ++++++ agent/agentssh/agentssh.go | 34 ++++++++++++++++++++++++++++---- agent/agentssh/jetbrainstrack.go | 5 ++++- coderd/activitybump_test.go | 6 ++++++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index cb0037dd0ed48..014a1efcef388 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -1503,6 +1503,12 @@ func (a *agent) Collect(ctx context.Context, networkStats map[netlogtype.Connect stats.SessionCountReconnectingPty = a.connCountReconnectingPTY.Load() + // if we've seen sessions but currently have no connections we + // just count the sum of the sessions as connections + if stats.ConnectionCount == 0 { + stats.ConnectionCount = stats.SessionCountSsh + stats.SessionCountVscode + stats.SessionCountJetbrains + stats.SessionCountReconnectingPty + } + // Compute the median connection latency! a.logger.Debug(ctx, "starting peer latency measurement for stats") var wg sync.WaitGroup diff --git a/agent/agentssh/agentssh.go b/agent/agentssh/agentssh.go index 081056b4f4ebd..d157092bcfe19 100644 --- a/agent/agentssh/agentssh.go +++ b/agent/agentssh/agentssh.go @@ -105,6 +105,9 @@ type Server struct { connCountVSCode atomic.Int64 connCountJetBrains atomic.Int64 connCountSSHSession atomic.Int64 + seenVSCode atomic.Bool + seenJetBrains atomic.Bool + seenSSHSession atomic.Bool metrics *sshServerMetrics } @@ -167,7 +170,7 @@ func NewServer(ctx context.Context, logger slog.Logger, prometheusRegistry *prom ChannelHandlers: map[string]ssh.ChannelHandler{ "direct-tcpip": func(srv *ssh.Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx ssh.Context) { // Wrapper is designed to find and track JetBrains Gateway connections. - wrapped := NewJetbrainsChannelWatcher(ctx, s.logger, newChan, &s.connCountJetBrains) + wrapped := NewJetbrainsChannelWatcher(ctx, s.logger, newChan, &s.connCountJetBrains, &s.seenJetBrains) ssh.DirectTCPIPHandler(srv, conn, wrapped, ctx) }, "direct-streamlocal@openssh.com": directStreamLocalHandler, @@ -245,10 +248,31 @@ type ConnStats struct { } func (s *Server) ConnStats() ConnStats { + // if we have 0 active connections, but we have seen a connection + // since the last time we collected, count it as 1 so that workspace + // activity is properly counted. + sshCount := s.connCountSSHSession.Load() + if sshCount == 0 && s.seenSSHSession.Load() { + sshCount = 1 + } + vscode := s.connCountVSCode.Load() + if vscode == 0 && s.seenVSCode.Load() { + vscode = 1 + } + jetbrains := s.connCountJetBrains.Load() + if jetbrains == 0 && s.seenJetBrains.Load() { + jetbrains = 1 + } + + // Reset the seen trackers for the next collection. + s.seenSSHSession.Store(false) + s.seenVSCode.Store(false) + s.seenJetBrains.Store(false) + return ConnStats{ - Sessions: s.connCountSSHSession.Load(), - VSCode: s.connCountVSCode.Load(), - JetBrains: s.connCountJetBrains.Load(), + Sessions: sshCount, + VSCode: vscode, + JetBrains: jetbrains, } } @@ -392,12 +416,14 @@ func (s *Server) sessionStart(logger slog.Logger, session ssh.Session, extraEnv switch magicType { case MagicSessionTypeVSCode: s.connCountVSCode.Add(1) + s.seenVSCode.Store(true) defer s.connCountVSCode.Add(-1) case MagicSessionTypeJetBrains: // Do nothing here because JetBrains launches hundreds of ssh sessions. // We instead track JetBrains in the single persistent tcp forwarding channel. case "": s.connCountSSHSession.Add(1) + s.seenSSHSession.Store(true) defer s.connCountSSHSession.Add(-1) default: logger.Warn(ctx, "invalid magic ssh session type specified", slog.F("type", magicType)) diff --git a/agent/agentssh/jetbrainstrack.go b/agent/agentssh/jetbrainstrack.go index 534f2899b11ae..880caccfdb3b2 100644 --- a/agent/agentssh/jetbrainstrack.go +++ b/agent/agentssh/jetbrainstrack.go @@ -27,10 +27,11 @@ type localForwardChannelData struct { type JetbrainsChannelWatcher struct { gossh.NewChannel jetbrainsCounter *atomic.Int64 + jetbrainsSeen *atomic.Bool logger slog.Logger } -func NewJetbrainsChannelWatcher(ctx ssh.Context, logger slog.Logger, newChannel gossh.NewChannel, counter *atomic.Int64) gossh.NewChannel { +func NewJetbrainsChannelWatcher(ctx ssh.Context, logger slog.Logger, newChannel gossh.NewChannel, counter *atomic.Int64, seen *atomic.Bool) gossh.NewChannel { d := localForwardChannelData{} if err := gossh.Unmarshal(newChannel.ExtraData(), &d); err != nil { // If the data fails to unmarshal, do nothing. @@ -60,6 +61,7 @@ func NewJetbrainsChannelWatcher(ctx ssh.Context, logger slog.Logger, newChannel return &JetbrainsChannelWatcher{ NewChannel: newChannel, jetbrainsCounter: counter, + jetbrainsSeen: seen, logger: logger.With(slog.F("destination_port", d.DestPort)), } } @@ -70,6 +72,7 @@ func (w *JetbrainsChannelWatcher) Accept() (gossh.Channel, <-chan *gossh.Request return c, r, err } w.jetbrainsCounter.Add(1) + w.jetbrainsSeen.Store(true) // nolint: gocritic // JetBrains is a proper noun and should be capitalized w.logger.Debug(context.Background(), "JetBrains watcher accepted channel") diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index 60aec23475885..0ec813c0edcf3 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -212,6 +212,12 @@ func TestWorkspaceActivityBump(t *testing.T) { time.Sleep(time.Second * 3) sshConn, err := conn.SSHClient(ctx) require.NoError(t, err) + sess, err := sshConn.NewSession() + require.NoError(t, err) + err = sess.Shell() + require.NoError(t, err) + err = sess.Close() + require.NoError(t, err) _ = sshConn.Close() assertBumped(true) From 56cfa17986ae8839f10bc74dc719e0997dd2c625 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Mon, 28 Oct 2024 16:16:32 +0000 Subject: [PATCH 04/11] fix --- coderd/activitybump_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index 0ec813c0edcf3..85b5709f2de26 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -256,6 +256,12 @@ func TestWorkspaceActivityBump(t *testing.T) { time.Sleep(time.Second * 3) sshConn, err := conn.SSHClient(ctx) require.NoError(t, err) + sess, err := sshConn.NewSession() + require.NoError(t, err) + err = sess.Shell() + require.NoError(t, err) + err = sess.Close() + require.NoError(t, err) _ = sshConn.Close() assertBumped(true) From d451924bed04e23c94e165057c67fbfd877d0422 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Mon, 28 Oct 2024 16:32:18 +0000 Subject: [PATCH 05/11] Revert "fix" This reverts commit 56cfa17986ae8839f10bc74dc719e0997dd2c625. --- coderd/activitybump_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index 85b5709f2de26..0ec813c0edcf3 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -256,12 +256,6 @@ func TestWorkspaceActivityBump(t *testing.T) { time.Sleep(time.Second * 3) sshConn, err := conn.SSHClient(ctx) require.NoError(t, err) - sess, err := sshConn.NewSession() - require.NoError(t, err) - err = sess.Shell() - require.NoError(t, err) - err = sess.Close() - require.NoError(t, err) _ = sshConn.Close() assertBumped(true) From c0c0af53f78a27876735f4e6a9e9c552dcf4159e Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Mon, 28 Oct 2024 16:32:36 +0000 Subject: [PATCH 06/11] Revert "fix test" This reverts commit 218f4b0c28bdc0646b85b74634d67e4d2c329f1a. --- agent/agent.go | 6 ------ agent/agentssh/agentssh.go | 34 ++++---------------------------- agent/agentssh/jetbrainstrack.go | 5 +---- coderd/activitybump_test.go | 6 ------ 4 files changed, 5 insertions(+), 46 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 014a1efcef388..cb0037dd0ed48 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -1503,12 +1503,6 @@ func (a *agent) Collect(ctx context.Context, networkStats map[netlogtype.Connect stats.SessionCountReconnectingPty = a.connCountReconnectingPTY.Load() - // if we've seen sessions but currently have no connections we - // just count the sum of the sessions as connections - if stats.ConnectionCount == 0 { - stats.ConnectionCount = stats.SessionCountSsh + stats.SessionCountVscode + stats.SessionCountJetbrains + stats.SessionCountReconnectingPty - } - // Compute the median connection latency! a.logger.Debug(ctx, "starting peer latency measurement for stats") var wg sync.WaitGroup diff --git a/agent/agentssh/agentssh.go b/agent/agentssh/agentssh.go index d157092bcfe19..081056b4f4ebd 100644 --- a/agent/agentssh/agentssh.go +++ b/agent/agentssh/agentssh.go @@ -105,9 +105,6 @@ type Server struct { connCountVSCode atomic.Int64 connCountJetBrains atomic.Int64 connCountSSHSession atomic.Int64 - seenVSCode atomic.Bool - seenJetBrains atomic.Bool - seenSSHSession atomic.Bool metrics *sshServerMetrics } @@ -170,7 +167,7 @@ func NewServer(ctx context.Context, logger slog.Logger, prometheusRegistry *prom ChannelHandlers: map[string]ssh.ChannelHandler{ "direct-tcpip": func(srv *ssh.Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx ssh.Context) { // Wrapper is designed to find and track JetBrains Gateway connections. - wrapped := NewJetbrainsChannelWatcher(ctx, s.logger, newChan, &s.connCountJetBrains, &s.seenJetBrains) + wrapped := NewJetbrainsChannelWatcher(ctx, s.logger, newChan, &s.connCountJetBrains) ssh.DirectTCPIPHandler(srv, conn, wrapped, ctx) }, "direct-streamlocal@openssh.com": directStreamLocalHandler, @@ -248,31 +245,10 @@ type ConnStats struct { } func (s *Server) ConnStats() ConnStats { - // if we have 0 active connections, but we have seen a connection - // since the last time we collected, count it as 1 so that workspace - // activity is properly counted. - sshCount := s.connCountSSHSession.Load() - if sshCount == 0 && s.seenSSHSession.Load() { - sshCount = 1 - } - vscode := s.connCountVSCode.Load() - if vscode == 0 && s.seenVSCode.Load() { - vscode = 1 - } - jetbrains := s.connCountJetBrains.Load() - if jetbrains == 0 && s.seenJetBrains.Load() { - jetbrains = 1 - } - - // Reset the seen trackers for the next collection. - s.seenSSHSession.Store(false) - s.seenVSCode.Store(false) - s.seenJetBrains.Store(false) - return ConnStats{ - Sessions: sshCount, - VSCode: vscode, - JetBrains: jetbrains, + Sessions: s.connCountSSHSession.Load(), + VSCode: s.connCountVSCode.Load(), + JetBrains: s.connCountJetBrains.Load(), } } @@ -416,14 +392,12 @@ func (s *Server) sessionStart(logger slog.Logger, session ssh.Session, extraEnv switch magicType { case MagicSessionTypeVSCode: s.connCountVSCode.Add(1) - s.seenVSCode.Store(true) defer s.connCountVSCode.Add(-1) case MagicSessionTypeJetBrains: // Do nothing here because JetBrains launches hundreds of ssh sessions. // We instead track JetBrains in the single persistent tcp forwarding channel. case "": s.connCountSSHSession.Add(1) - s.seenSSHSession.Store(true) defer s.connCountSSHSession.Add(-1) default: logger.Warn(ctx, "invalid magic ssh session type specified", slog.F("type", magicType)) diff --git a/agent/agentssh/jetbrainstrack.go b/agent/agentssh/jetbrainstrack.go index 880caccfdb3b2..534f2899b11ae 100644 --- a/agent/agentssh/jetbrainstrack.go +++ b/agent/agentssh/jetbrainstrack.go @@ -27,11 +27,10 @@ type localForwardChannelData struct { type JetbrainsChannelWatcher struct { gossh.NewChannel jetbrainsCounter *atomic.Int64 - jetbrainsSeen *atomic.Bool logger slog.Logger } -func NewJetbrainsChannelWatcher(ctx ssh.Context, logger slog.Logger, newChannel gossh.NewChannel, counter *atomic.Int64, seen *atomic.Bool) gossh.NewChannel { +func NewJetbrainsChannelWatcher(ctx ssh.Context, logger slog.Logger, newChannel gossh.NewChannel, counter *atomic.Int64) gossh.NewChannel { d := localForwardChannelData{} if err := gossh.Unmarshal(newChannel.ExtraData(), &d); err != nil { // If the data fails to unmarshal, do nothing. @@ -61,7 +60,6 @@ func NewJetbrainsChannelWatcher(ctx ssh.Context, logger slog.Logger, newChannel return &JetbrainsChannelWatcher{ NewChannel: newChannel, jetbrainsCounter: counter, - jetbrainsSeen: seen, logger: logger.With(slog.F("destination_port", d.DestPort)), } } @@ -72,7 +70,6 @@ func (w *JetbrainsChannelWatcher) Accept() (gossh.Channel, <-chan *gossh.Request return c, r, err } w.jetbrainsCounter.Add(1) - w.jetbrainsSeen.Store(true) // nolint: gocritic // JetBrains is a proper noun and should be capitalized w.logger.Debug(context.Background(), "JetBrains watcher accepted channel") diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index 0ec813c0edcf3..60aec23475885 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -212,12 +212,6 @@ func TestWorkspaceActivityBump(t *testing.T) { time.Sleep(time.Second * 3) sshConn, err := conn.SSHClient(ctx) require.NoError(t, err) - sess, err := sshConn.NewSession() - require.NoError(t, err) - err = sess.Shell() - require.NoError(t, err) - err = sess.Close() - require.NoError(t, err) _ = sshConn.Close() assertBumped(true) From be0bbb4bb02cfb9c93fb58fc4cf743466dcc8152 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Mon, 28 Oct 2024 16:32:47 +0000 Subject: [PATCH 07/11] Revert "fix: do not bump activity with no sessions" This reverts commit d702dca0279497413391a774dad5f1f16c72663b. --- coderd/agentapi/stats_test.go | 38 +++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/coderd/agentapi/stats_test.go b/coderd/agentapi/stats_test.go index b3676d1f192ba..83edb8cccc4e1 100644 --- a/coderd/agentapi/stats_test.go +++ b/coderd/agentapi/stats_test.go @@ -325,7 +325,6 @@ func TestUpdateStates(t *testing.T) { "dean": 2, }, ConnectionCount: 3, - SessionCountSsh: 3, }, } ) @@ -410,7 +409,11 @@ func TestUpdateStates(t *testing.T) { } batcher = &workspacestatstest.StatsBatcher{} updateAgentMetricsFnCalled = false - wut = workspacestats.NewTracker(dbM) + tickCh = make(chan time.Time) + flushCh = make(chan int, 1) + wut = workspacestats.NewTracker(dbM, + workspacestats.TrackerWithTickFlush(tickCh, flushCh), + ) req = &agentproto.UpdateStatsRequest{ Stats: &agentproto.Stats{ @@ -476,15 +479,39 @@ func TestUpdateStates(t *testing.T) { // Workspace gets fetched. dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(workspace, nil) + // We expect an activity bump because ConnectionCount > 0. + dbM.EXPECT().ActivityBumpWorkspace(gomock.Any(), database.ActivityBumpWorkspaceParams{ + WorkspaceID: workspace.ID, + NextAutostart: time.Time{}.UTC(), + }).Return(nil) + + // Workspace last used at gets bumped. + dbM.EXPECT().BatchUpdateWorkspaceLastUsedAt(gomock.Any(), database.BatchUpdateWorkspaceLastUsedAtParams{ + IDs: []uuid.UUID{workspace.ID}, + LastUsedAt: now, + }).Return(nil) + // User gets fetched to hit the UpdateAgentMetricsFn. dbM.EXPECT().GetUserByID(gomock.Any(), user.ID).Return(user, nil) + // Ensure that pubsub notifications are sent. + notifyDescription := make(chan []byte) + ps.Subscribe(codersdk.WorkspaceNotifyChannel(workspace.ID), func(_ context.Context, description []byte) { + go func() { + notifyDescription <- description + }() + }) + resp, err := api.UpdateStats(context.Background(), req) require.NoError(t, err) require.Equal(t, &agentproto.UpdateStatsResponse{ ReportInterval: durationpb.New(10 * time.Second), }, resp) + tickCh <- now + count := <-flushCh + require.Equal(t, 1, count, "expected one flush with one id") + batcher.Mu.Lock() defer batcher.Mu.Unlock() require.EqualValues(t, 1, batcher.Called) @@ -492,6 +519,13 @@ func TestUpdateStates(t *testing.T) { require.EqualValues(t, 0, batcher.LastStats.SessionCountJetbrains) require.EqualValues(t, 0, batcher.LastStats.SessionCountVscode) require.EqualValues(t, 0, batcher.LastStats.SessionCountReconnectingPty) + ctx := testutil.Context(t, testutil.WaitShort) + select { + case <-ctx.Done(): + t.Error("timed out while waiting for pubsub notification") + case description := <-notifyDescription: + require.Equal(t, description, []byte{}) + } require.True(t, updateAgentMetricsFnCalled) }) } From 5a50fc37baf41da40f87de7a3fd42d4977b6c336 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Mon, 28 Oct 2024 16:33:02 +0000 Subject: [PATCH 08/11] Revert "fix: stop activity bump if no tracked sessions" This reverts commit 9e07bb40ee66387252443b177a58aa366e8b42bc. --- coderd/workspacestats/reporter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/workspacestats/reporter.go b/coderd/workspacestats/reporter.go index 20e3cf7160e2c..6bb1b2dea4028 100644 --- a/coderd/workspacestats/reporter.go +++ b/coderd/workspacestats/reporter.go @@ -136,8 +136,8 @@ func (r *Reporter) ReportAgentStats(ctx context.Context, now time.Time, workspac }, stats.Metrics) } - // if no active sessions we do not bump activity - if stats.SessionCountJetbrains == 0 && stats.SessionCountVscode == 0 && stats.SessionCountReconnectingPty == 0 && stats.SessionCountSsh == 0 { + // if no active connections we do not bump activity + if stats.ConnectionCount == 0 { return nil } From 4f0e506f3ac2978b6cd47cc4279fb7c2e9e1d599 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Mon, 28 Oct 2024 16:37:51 +0000 Subject: [PATCH 09/11] new way --- coderd/workspacestats/reporter.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/coderd/workspacestats/reporter.go b/coderd/workspacestats/reporter.go index 6bb1b2dea4028..36aea4464e08a 100644 --- a/coderd/workspacestats/reporter.go +++ b/coderd/workspacestats/reporter.go @@ -136,8 +136,13 @@ func (r *Reporter) ReportAgentStats(ctx context.Context, now time.Time, workspac }, stats.Metrics) } - // if no active connections we do not bump activity - if stats.ConnectionCount == 0 { + // workspace activity: if no sessions we do not bump activity + if usage && stats.SessionCountVscode == 0 && stats.SessionCountJetbrains == 0 && stats.SessionCountReconnectingPty == 0 && stats.SessionCountSsh == 0 { + return nil + } + + // legacy stats: if no active connections we do not bump activity + if !usage && stats.ConnectionCount == 0 { return nil } From 599d71f164f35cce8ed5987217d0709f0e1055c8 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Mon, 28 Oct 2024 16:44:11 +0000 Subject: [PATCH 10/11] lint --- coderd/workspacestats/reporter.go | 1 + 1 file changed, 1 insertion(+) diff --git a/coderd/workspacestats/reporter.go b/coderd/workspacestats/reporter.go index 36aea4464e08a..a2812eba2d8b3 100644 --- a/coderd/workspacestats/reporter.go +++ b/coderd/workspacestats/reporter.go @@ -117,6 +117,7 @@ func (r *Reporter) ReportAppStats(ctx context.Context, stats []workspaceapps.Sta return nil } +//nolint:revive usage is a control flag while we have the experiment func (r *Reporter) ReportAgentStats(ctx context.Context, now time.Time, workspace database.Workspace, workspaceAgent database.WorkspaceAgent, templateName string, stats *agentproto.Stats, usage bool) error { // update agent stats r.opts.StatsBatcher.Add(now, workspaceAgent.ID, workspace.TemplateID, workspace.OwnerID, workspace.ID, stats, usage) From 79af2ba89f24a0b29a9f1db106bde10bdf06c279 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Tue, 29 Oct 2024 17:54:48 +0000 Subject: [PATCH 11/11] lint --- coderd/workspacestats/reporter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/workspacestats/reporter.go b/coderd/workspacestats/reporter.go index a2812eba2d8b3..e59a9f15d5e95 100644 --- a/coderd/workspacestats/reporter.go +++ b/coderd/workspacestats/reporter.go @@ -117,7 +117,7 @@ func (r *Reporter) ReportAppStats(ctx context.Context, stats []workspaceapps.Sta return nil } -//nolint:revive usage is a control flag while we have the experiment +// nolint:revive // usage is a control flag while we have the experiment func (r *Reporter) ReportAgentStats(ctx context.Context, now time.Time, workspace database.Workspace, workspaceAgent database.WorkspaceAgent, templateName string, stats *agentproto.Stats, usage bool) error { // update agent stats r.opts.StatsBatcher.Add(now, workspaceAgent.ID, workspace.TemplateID, workspace.OwnerID, workspace.ID, stats, usage)