mirror of
https://github.com/coder/coder.git
synced 2026-10-31 19:36:41 +08:00
feat: add flag to disable workspace agent context sync (#28522)
This commit is contained in:
@@ -83,7 +83,10 @@ type Options struct {
|
||||
Pubsub pubsub.Pubsub
|
||||
// ContextDirtyMarker is the chatd-backed hydrate/dirty fan-out invoked
|
||||
// from PushContextState. Nil when chatd is disabled.
|
||||
ContextDirtyMarker ContextDirtyMarker
|
||||
ContextDirtyMarker ContextDirtyMarker
|
||||
// ContextSyncDisabled makes PushContextState reject pushes with a dRPC
|
||||
// Unimplemented code so agents stop sending context snapshots.
|
||||
ContextSyncDisabled bool
|
||||
ConnectionLogger *atomic.Pointer[connectionlog.ConnectionLogger]
|
||||
DerpMapFn func() *tailcfg.DERPMap
|
||||
TailnetCoordinator *atomic.Pointer[tailnet.Coordinator]
|
||||
@@ -257,6 +260,7 @@ func New(opts Options, workspace database.Workspace, agent database.WorkspaceAge
|
||||
Clock: opts.Clock,
|
||||
Database: opts.Database,
|
||||
DirtyMarker: opts.ContextDirtyMarker,
|
||||
Disabled: opts.ContextSyncDisabled,
|
||||
}
|
||||
|
||||
// Start background cache refresh loop to handle workspace changes
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"storj.io/drpc/drpcerr"
|
||||
|
||||
"cdr.dev/slog/v3"
|
||||
agentproto "github.com/coder/coder/v2/agent/proto"
|
||||
@@ -67,6 +68,13 @@ type ContextAPI struct {
|
||||
// snapshot persisted by a push. It is nil when chatd is not running,
|
||||
// in which case PushContextState stays a pure write path.
|
||||
DirtyMarker ContextDirtyMarker
|
||||
// Disabled rejects every push with a dRPC Unimplemented code. The
|
||||
// agent's DRPCPusher translates that code into ErrPushUnimplemented,
|
||||
// which terminates its RunPush loop for the life of the connection,
|
||||
// exactly as if coderd predated the v2.10 Agent API. This is the
|
||||
// deployment-wide kill switch for context sync write load
|
||||
// (CODER_DISABLE_WORKSPACE_AGENT_CONTEXT_SYNC).
|
||||
Disabled bool
|
||||
}
|
||||
|
||||
// ContextDirtyMarker hydrates chats from, and marks chats dirty against, a
|
||||
@@ -103,6 +111,14 @@ type ContextDirtyMarker interface {
|
||||
// authorizes the actor (the agent's token subject) against the
|
||||
// workspace that owns the agent.
|
||||
func (a *ContextAPI) PushContextState(ctx context.Context, req *agentproto.PushContextStateRequest) (*agentproto.PushContextStateResponse, error) {
|
||||
if a.Disabled {
|
||||
// The Unimplemented code (not a plain error) is what tells the
|
||||
// agent to stop pushing instead of retrying with backoff.
|
||||
return nil, drpcerr.WithCode(
|
||||
xerrors.New("agentapi: workspace agent context sync is disabled on this deployment"),
|
||||
drpcerr.Unimplemented,
|
||||
)
|
||||
}
|
||||
if req == nil {
|
||||
return nil, xerrors.New("agentapi: PushContextState request is nil")
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/lib/pq"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
"storj.io/drpc/drpcerr"
|
||||
|
||||
"cdr.dev/slog/v3"
|
||||
"cdr.dev/slog/v3/sloggers/slogtest"
|
||||
@@ -58,6 +59,27 @@ func TestPushContextState(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
t.Run("DisabledReturnsUnimplemented", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// No InTx or query expectations: a disabled push must return
|
||||
// before touching the store. The Unimplemented dRPC code is
|
||||
// load-bearing; the agent's DRPCPusher translates it into
|
||||
// ErrPushUnimplemented, which stops its RunPush loop instead
|
||||
// of retrying with backoff.
|
||||
api, _ := makeAPI(t)
|
||||
api.Disabled = true
|
||||
|
||||
resp, err := api.PushContextState(context.Background(), &agentproto.PushContextStateRequest{
|
||||
Version: 1,
|
||||
AggregateHash: []byte{0x01, 0x02},
|
||||
Initial: true,
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.Nil(t, resp)
|
||||
require.EqualValues(t, drpcerr.Unimplemented, drpcerr.Code(err))
|
||||
})
|
||||
|
||||
t.Run("AcceptsInitialPush", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user