MCPcopy Index your code
hub / github.com/coder/coder / workspaceAgentReinit

Method workspaceAgentReinit

coderd/workspaceagents.go:1481–1650  ·  view source on GitHub ↗

@Summary Get workspace agent reinitialization @ID get-workspace-agent-reinitialization @Security CoderSessionToken @Produce json @Tags Agents @Param wait query bool false "Opt in to durable reinit checks" @Success 200 {object} agentsdk.ReinitializationEvent @Failure 409 {object} codersdk.Response @R

(rw http.ResponseWriter, r *http.Request)

Source from the content-addressed store, hash-verified

1479// @Failure 409 {object} codersdk.Response
1480// @Router /api/v2/workspaceagents/me/reinit [get]
1481func (api *API) workspaceAgentReinit(rw http.ResponseWriter, r *http.Request) {
1482 // Allow us to interrupt watch via cancel.
1483 ctx, cancel := context.WithCancel(r.Context())
1484 defer cancel()
1485 r = r.WithContext(ctx) // Rewire context for SSE cancellation.
1486
1487 workspaceAgent := httpmw.WorkspaceAgent(r)
1488 log := api.Logger.Named("workspace_agent_reinit_watcher").With(
1489 slog.F("workspace_agent_id", workspaceAgent.ID),
1490 )
1491
1492 workspace, err := api.Database.GetWorkspaceByAgentID(ctx, workspaceAgent.ID)
1493 if err != nil {
1494 log.Error(ctx, "failed to retrieve workspace from agent token", slog.Error(err))
1495 httpapi.InternalServerError(rw, xerrors.New("failed to determine workspace from agent token"))
1496 return
1497 }
1498 log = log.With(slog.F("workspace_id", workspace.ID))
1499
1500 log.Info(ctx, "agent waiting for reinit instruction")
1501
1502 // Subscribe to claim events BEFORE any durable checks to avoid a
1503 // TOCTOU race: without this, a claim could fire between the
1504 // IsPrebuild() check and the subscribe call, and we'd miss the
1505 // pubsub event entirely. By subscribing first, any event that
1506 // fires during the checks below is buffered in the channel.
1507 pubsubCh, cancelSub, err := prebuilds.NewPubsubWorkspaceClaimListener(api.Pubsub, log).ListenForWorkspaceClaims(ctx, workspace.ID)
1508 if err != nil {
1509 log.Error(ctx, "subscribe to prebuild claimed channel", slog.Error(err))
1510 httpapi.InternalServerError(rw, xerrors.New("failed to subscribe to prebuild claimed channel"))
1511 return
1512 }
1513 defer cancelSub()
1514
1515 reinitEvents := pubsubCh
1516
1517 // Only perform the durable claim check when the agent opts in via
1518 // the "wait" query parameter. Older agents don't send the
1519 // "wait" query parameter and lack the duplicate-reinit guard, so
1520 // they would enter an infinite reinit loop if we pre-seeded the
1521 // channel on every connection.
1522 waitParam, _ := strconv.ParseBool(r.URL.Query().Get("wait"))
1523 if waitParam && !workspace.IsPrebuild() {
1524 firstBuild, err := api.Database.GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx,
1525 database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams{
1526 WorkspaceID: workspace.ID,
1527 BuildNumber: 1,
1528 })
1529 if err != nil {
1530 log.Error(ctx, "failed to get first workspace build", slog.Error(err))
1531 httpapi.InternalServerError(rw, xerrors.New("failed to get first workspace build"))
1532 return
1533 }
1534 if firstBuild.InitiatorID != database.PrebuildsSystemUserID {
1535 // Not a claimed prebuild — this is a regular workspace.
1536 // Return 409 so the agent stops reconnecting to this
1537 // endpoint.
1538 httpapi.Write(ctx, rw, http.StatusConflict, codersdk.Response{

Callers

nothing calls this directly

Calls 15

TransmitMethod · 0.95
WorkspaceAgentFunction · 0.92
InternalServerErrorFunction · 0.92
WriteFunction · 0.92
WithContextMethod · 0.80
NamedMethod · 0.80
ContextMethod · 0.65
GetWorkspaceByAgentIDMethod · 0.65

Tested by

no test coverage detected