Skip to content

feat: spin down prod deployments after 30min#4974

Merged
chronark merged 19 commits intomainfrom
spin-down-production
Feb 11, 2026
Merged

feat: spin down prod deployments after 30min#4974
chronark merged 19 commits intomainfrom
spin-down-production

Conversation

@chronark
Copy link
Collaborator

@chronark chronark commented Feb 10, 2026

Automatically set production deployments to standby 30 minutes after they are superseded by a newer deploy, reducing idle resource consumption. Previously, old deployments kept running indefinitely.

Architecture

This PR introduces a new Restate virtual object (DeploymentService) and splits the existing deployment proto into two services:

  • DeployService (Restate Workflow) — orchestrates the full deployment lifecycle: build, provision, health-check, route, promote, rollback. Keyed by a caller-supplied workflow ID. This is the renamed former DeploymentService.
  • DeploymentService (Restate Virtual Object) — serializes all desired-state mutations for a single deployment, keyed by deployment ID. Handles scheduling standby/archive transitions with a nonce-based last-writer-wins mechanism.

The split exists because multiple callers need to mutate a deployment's desired state (deploy workflow, preview cron, promote, rollback). The virtual object key guarantees sequential processing per deployment without external locks.

How Production Spin-Down Works

After a successful production deploy, the DeployService workflow calls ScheduleDesiredStateChange(standby, 30min) on the previous live deployment's virtual object. The flow:

  1. ScheduleDesiredStateChange generates a unique nonce, stores {nonce, target_state} in Restate state, and enqueues a delayed ChangeDesiredState call.
  2. After 30 minutes, ChangeDesiredState fires, verifies the nonce still matches the stored transition, and writes desired_state = standby to the database.

Last-Writer-Wins via Nonce

Restate delayed calls cannot be cancelled, so the nonce provides conflict resolution:

  • No intervention — nonce matches after 30 min, standby is applied.
  • Promote/Rollback restores the deploymentClearScheduledStateChanges deletes the stored transition. The delayed call still fires but finds nothing to match against and no-ops.
  • A newer schedule supersedes — overwrites the stored nonce. The old delayed call fires, sees a nonce mismatch, and no-ops. Only the latest schedule takes effect.

Key Changes

New: svc/ctrl/worker/deployment/

A new Restate virtual object with three RPCs:

  • ScheduleDesiredStateChange — records a delayed state transition with nonce-based last-writer-wins.
  • ChangeDesiredState — internal handler that fires after the delay; no-ops on nonce mismatch, otherwise writes new desired_state to the DB.
  • ClearScheduledStateChanges — cancels pending transitions by deleting the stored transition record.

Modified: svc/ctrl/worker/deploy/

  • Deploy handler — after a successful production deploy, schedules the previous live deployment for standby in 30 min via the new virtual object.
  • Promote handler — clears scheduled state changes on the promoted deployment (so it won't be spun down), and schedules the old live deployment for standby.
  • Rollback handler — clears scheduled state changes on the rollback target before switching routes, ensuring it stays running.
  • Preview scale-down — renamed from ScaleDownIdleDeployments to ScaleDownIdlePreviewDeployments; now transitions idle previews to archived via the virtual object instead of directly.

Proto Split

  • deployment.protodeploy.proto (workflow RPCs: Deploy, Rollback, Promote, ScaleDownIdlePreviewDeployments) + deployment.proto (virtual object RPCs: ScheduleDesiredStateChange, ChangeDesiredState, ClearScheduledStateChanges).
  • All Go and TypeScript references updated accordingly.

@vercel
Copy link

vercel bot commented Feb 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dashboard Ready Ready Preview, Comment Feb 11, 2026 7:24pm
engineering Ready Ready Preview, Comment Feb 11, 2026 7:24pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Renamed DeploymentService to DeployService across protos, clients, handlers, and docs; added a new hydra.v1 DeployService proto; introduced a Restate-backed Deployment virtual-object package with nonce-based schedule/change/clear RPCs; updated workflows to call ScheduleDesiredStateChange for idle-preview standby transitions.

Changes

Cohort / File(s) Summary
Proto Definitions
svc/ctrl/proto/ctrl/v1/deployment.proto, svc/ctrl/proto/hydra/v1/deploy.proto, svc/ctrl/proto/hydra/v1/deployment.proto
Renamed ctrl v1 service to DeployService; added hydra.v1 DeployService proto (Deploy/Rollback/Promote/ScaleDownIdlePreviewDeployments); converted hydra.v1.DeploymentService from WORKFLOW → VIRTUAL_OBJECT with Schedule/Change/Clear RPCs and DeploymentDesiredState enum.
Deploy Workflow Code
svc/ctrl/worker/deploy/...
(deploy_handler.go, promote_handler.go, rollback_handler.go, scale_down_idle_preview_deployments.go, service.go, doc.go, *_test.go, BUILD.bazel)
Workflow updated to use DeployService types; deploy source is a oneof (GitSource/DockerImage); promotion/rollback now clear scheduled transitions and schedule previous live deployment to STANDBY after 30m; scale-down logic renamed to preview variant and now calls DeploymentService.ScheduleDesiredStateChange.
Deployment Virtual Object
svc/ctrl/worker/deployment/...
(service.go, clear_scheduled.go, deployment_state.go, doc.go, BUILD.bazel)
New deployment package implementing a Restate VirtualObject (VirtualObject) with ScheduleDesiredStateChange, ChangeDesiredState, and ClearScheduledStateChanges; implements nonce-based last-writer-wins transition persistence and DB updates.
Control Plane Bindings & Tests
svc/ctrl/services/deployment/service.go, svc/ctrl/api/run.go, svc/ctrl/api/github_webhook.go, svc/ctrl/api/..._test.go, svc/ctrl/integration/harness/...
Replaced constructors/handlers/assertions from DeploymentService*DeployService*; added binding/instance for new deployment virtual-object; updated ingress client constructors and test wiring to DeployService variants.
API Surface & Routes
svc/api/routes/services.go, svc/api/routes/v2_deploy_create_deployment/handler.go, svc/api/internal/testutil/mock_deployment_client.go, svc/api/run.go
Updated fields, compile-time assertions and client constructors from ctrlv1connect.DeploymentServiceClientctrlv1connect.DeployServiceClient.
Build / Bazel
svc/ctrl/worker/BUILD.bazel, svc/ctrl/worker/deploy/BUILD.bazel, svc/ctrl/worker/deployment/BUILD.bazel, svc/ctrl/integration/harness/BUILD.bazel, pkg/db/BUILD.bazel
Added new deployment go_library target and added it to deps; renamed scale-down source/test targets to preview variants; added new generated SQL source to pkg/db.
DB Additions
pkg/db/queries/deployment_topology_update_desired_status.sql, pkg/db/deployment_topology_update_desired_status.sql_generated.go, pkg/db/querier_generated.go
New SQL query and generated Go code to update deployment_topology desired_status, version, and updated_at by deployment_id and region; added Querier method UpdateDeploymentTopologyDesiredStatus.
Worker Service Wiring
svc/ctrl/services/deployment/service.go, svc/ctrl/worker/deploy/service.go, svc/ctrl/worker/service.go
Adjusted embedded Unimplemented* handler types and public assertions to DeployService variants; deployment ingress client factory updated to DeployService ingress client.
Web / Frontend & Docs & CI
web/apps/.../deployment/*.ts, web/apps/engineering/content/docs/..., svc/ctrl/services/doc.go, .github/workflows/restate_scheduled_tasks.yml
Updated frontend imports/constructors from DeploymentServiceDeployService, updated proto paths and field names in docs, replaced scheduled-task REST endpoint path to use ScaleDownIdlePreviewDeployments, and refreshed architecture/workflow docs to reflect new services and locations.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant DeployWF as DeployService (Workflow)
    participant Routing as RoutingService
    participant DeploymentVO as DeploymentService (VirtualObject)
    participant DB
    Caller->>DeployWF: Deploy(request)
    activate DeployWF
    DeployWF->>DeployWF: Build / provision / health checks
    DeployWF->>Routing: Update frontline routes
    DeployWF->>DB: Update live_deployment_id
    alt Previous live exists
        DeployWF->>DeploymentVO: ScheduleDesiredStateChange(previous_id, delay=30m, STANDBY)
        activate DeploymentVO
        DeploymentVO->>DeploymentVO: Store transition + nonce (restate)
        DeploymentVO->>DeploymentVO: Enqueue delayed ChangeDesiredState
        deactivate DeploymentVO
    end
    DeployWF->>Caller: DeployResponse
    deactivate DeployWF

    par Delayed transition (after 30m)
        DeploymentVO->>DeploymentVO: ChangeDesiredState(nonce)
        activate DeploymentVO
        DeploymentVO->>DB: Update desired_state=STANDBY, version++
        DeploymentVO->>DeploymentVO: Clear stored transition
        deactivate DeploymentVO
    end
Loading
sequenceDiagram
    participant Caller
    participant DeployWF as DeployService (Workflow)
    participant DeploymentVO as DeploymentService (VirtualObject)
    participant Routing as RoutingService
    participant DB
    Caller->>DeployWF: Promote(target_deployment_id)
    activate DeployWF
    DeployWF->>DeploymentVO: ClearScheduledStateChanges(target_deployment_id)
    activate DeploymentVO
    DeploymentVO->>DeploymentVO: Clear pending transition
    deactivate DeploymentVO
    DeployWF->>Routing: Update frontline routes -> target_deployment_id
    DeployWF->>DB: Update live_deployment_id
    DeployWF->>DeploymentVO: ScheduleDesiredStateChange(previous_id, delay=30m, STANDBY)
    activate DeploymentVO
    DeploymentVO->>DeploymentVO: Store transition + nonce
    DeploymentVO->>DeploymentVO: Enqueue delayed ChangeDesiredState
    deactivate DeploymentVO
    DeployWF->>Caller: PromoteResponse
    deactivate DeployWF
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is comprehensive, covering what the PR does, architecture changes, how the feature works, key code changes, and proto modifications. However, it does not follow the provided template structure with required sections like 'Type of change', 'How should this be tested', or the checklist. Follow the repository's PR template by adding 'Type of change' section, 'How should this be tested' section with specific test instructions, and complete the required checklist items.
Docstring Coverage ⚠️ Warning Docstring coverage is 36.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: automatically spinning down production deployments after 30 minutes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch spin-down-production

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
svc/ctrl/worker/deployment/deployment_state.go (1)

100-103: Consider explicit handling for deployment not found.

If deployment doesn't exist, sql.ErrNoRows propagates as a retriable error. Wrap with restate.TerminalError if not-found should be terminal.

Diff
 		deployment, err := db.Query.FindDeploymentById(txCtx, tx, deploymentID)
 		if err != nil {
+			if errors.Is(err, sql.ErrNoRows) {
+				return restate.TerminalErrorf("deployment not found: %s", deploymentID)
+			}
 			return err
 		}

Comment @coderabbitai help to get the list of available commands and usage tips.

@chronark chronark marked this pull request as ready for review February 10, 2026 19:53
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
web/apps/engineering/content/docs/architecture/workflows/creating-services.mdx (1)

114-129: ⚠️ Potential issue | 🟡 Minor

Import path in example may be stale.

The import on line 118 references svc/ctrl/workflows/yourservice but the documented service location on line 63 is svc/ctrl/worker/yourservice/. Consider updating the example import to match:

import (
    "github.com/unkeyed/unkey/svc/ctrl/worker/yourservice"
)
web/apps/engineering/content/docs/architecture/workflows/github-deployments.mdx (2)

103-127: ⚠️ Potential issue | 🟡 Minor

Deploy workflow diagram omits standby scheduling.
Current flow schedules the previous live deployment to standby after UpdateLive; add that step for accuracy.


321-330: ⚠️ Potential issue | 🟡 Minor

Proto location for DeployRequest likely outdated.
If workflow RPCs moved to deploy.proto after the split, update this location block.

🤖 Fix all issues with AI agents
In `@svc/ctrl/worker/deploy/deploy_handler.go`:
- Around line 421-433: The ScheduleDesiredStateChange call that moves
previousLiveDeploymentID to standby is unguarded and runs for preview deploys;
wrap this block with the same production/rolled-back condition used when
updating the live pointer so only real production live updates trigger
scheduling. Concretely, before calling
hydrav1.NewDeploymentServiceClient(...).ScheduleDesiredStateChange(), check the
same production/rolled-back predicate used in the live-pointer update logic
(reuse that predicate or helper), and only run the ScheduleDesiredStateChange
request (and restate.WithIdempotencyKey(deployment.ID)) when that predicate
indicates a production non-rolled-back live update.

In `@svc/ctrl/worker/deployment/clear_scheduled.go`:
- Around line 8-12: The comment on ClearScheduledStateChanges incorrectly states
that a delayed ChangeDesiredState call will "return a terminal error" when the
transition is nil; in reality ChangeDesiredState (see deployment_state.go - the
branch that checks t == nil) returns an empty ChangeDesiredStateResponse and nil
error (a no-op success). Update the ClearScheduledStateChanges comment to
describe the actual behavior: that any delayed ChangeDesiredState will see a nil
transition and be treated as a no-op (successful no-op) rather than producing a
terminal error, and optionally mention that callers should treat it as a
harmless no-op.

In `@svc/ctrl/worker/run.go`:
- Around line 171-173: The call to deployment.New passes a Config with the wrong
field name `DB`, causing a compile error; update the struct literal in the
restateSrv.Bind invocation (where
hydrav1.NewDeploymentServiceServer(deployment.New(...)) is called) to use the
correct field name `Database: database` matching deployment.Config.Database, so
deployment.New(deployment.Config{Database: database}) compiles.

In `@web/apps/engineering/content/docs/architecture/services/ctrl/index.mdx`:
- Around line 22-24: The docs list only DeployService which is ambiguous after
the new split; update the service list text to also mention the new
DeploymentService virtual object and briefly state its role (handling
desired-state mutations) alongside DeployService (which manages deployment
creation/management workflows); locate and edit the paragraph that currently
enumerates `ClusterService`, `BuildService`, `DeployService`, `AcmeService`,
`OpenApiService`, and `CtrlService` to insert `DeploymentService` with a short
parenthetical or clause clarifying it is the virtual object for desired-state
mutations while `DeployService` continues to orchestrate deployments.

In `@web/apps/engineering/content/docs/architecture/workflows/index.mdx`:
- Around line 17-20: The example text incorrectly states the key/service:
replace the reference to DeployService keyed by project_id with the correct
mapping between the workflow and the virtual object — mention that DeployService
is a workflow keyed by deployment/workflow ID and the serialized virtual object
is DeploymentService keyed by deployment_id (not project_id); update the
sentence in the Virtual Objects section to use DeploymentService and
deployment_id so the example accurately reflects that only one deployment per
deployment_id runs at a time and remove the incorrect project_id implication.
- Around line 31-36: Update the DeployService metadata block so the Proto points
to the post-split deploy proto and the Key reflects the workflow/deployment
identifier: change the Proto value to svc/ctrl/proto/hydra/v1/deploy.proto and
set Key to workflow_id (the workflow/deployment ID, not project_id) in the
DeployService section for DeployService (Location: svc/ctrl/worker/deploy/;
Operations remain Deploy, Rollback, Promote, ScaleDownIdlePreviewDeployments).
🧹 Nitpick comments (5)
svc/ctrl/worker/deploy/rollback_handler.go (1)

91-95: Wrap error for consistency with other service calls.

Other service/query errors in this handler include context (e.g., line 133: "failed to switch frontlineRoutes"). Wrapping here aids debugging.

Suggested change
 // ensure the rolled back deployment does not get spun down from existing scheduled actions
 _, err = hydrav1.NewDeploymentServiceClient(ctx, targetDeployment.ID).ClearScheduledStateChanges().Request(&hydrav1.ClearScheduledStateChangesRequest{})
 if err != nil {
-    return nil, err
+    return nil, fmt.Errorf("failed to clear scheduled state changes: %w", err)
 }
svc/ctrl/proto/hydra/v1/deploy.proto (1)

78-79: Consider removing the unused key_auth_id field.

The TODO indicates this field is unused. Keeping deprecated proto fields can lead to confusion. If removal is deferred, consider marking it reserved or deprecated option.

svc/ctrl/proto/hydra/v1/deployment.proto (1)

38-43: Consider adding a note about internal-only invocation in the proto documentation.

The comment states ChangeDesiredState is internal, but it's a public RPC. While Restate's delayed calls require the RPC to be public, you might want to document that external callers should not invoke it directly (e.g., via a convention like _internal suffix or explicit documentation in the request message).

svc/ctrl/worker/deploy/promote_handler.go (1)

128-132: Error from Send() is silently ignored.

The ScheduleDesiredStateChange().Send() call returns an error that isn't checked. If scheduling fails, the old deployment won't spin down, and there's no indication of failure.

Consider handling the error or at minimum logging it:

♻️ Suggested improvement
 // schedule old deployment to be spun down
-hydrav1.NewDeploymentServiceClient(ctx, project.LiveDeploymentID.String).ScheduleDesiredStateChange().Send(&hydrav1.ScheduleDesiredStateChangeRequest{
+_, err = hydrav1.NewDeploymentServiceClient(ctx, project.LiveDeploymentID.String).ScheduleDesiredStateChange().Send(&hydrav1.ScheduleDesiredStateChangeRequest{
     State:       hydrav1.DeploymentDesiredState_DEPLOYMENT_DESIRED_STATE_STANDBY,
     DelayMillis: (30 * time.Minute).Milliseconds(),
 })
+if err != nil {
+    logger.Warn("failed to schedule standby for previous live deployment",
+        "deployment_id", project.LiveDeploymentID.String,
+        "error", err)
+    // Non-fatal: promotion succeeded, just won't auto-spindown
+}
svc/ctrl/worker/deploy/deploy_handler.go (1)

327-335: TODO: source type hardcoded.
Routing metadata will always show CLI_UPLOAD even for Git/Docker. Want me to draft a source-type mapping?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@svc/ctrl/worker/deployment/deployment_state.go`:
- Around line 28-37: ScheduleDesiredStateChange currently persists the incoming
req.GetState() without validation; before calling restate.Set (and before
creating transition/nonce), validate that req.GetState() maps to a legal domain
state (e.g., parse/convert the raw enum into your domain ADT or check against
the allowed enum values in hydrav1), return an appropriate error if invalid, and
only construct the transition struct and call restate.Set with transitionKey
once the state is validated/converted. Target symbols:
ScheduleDesiredStateChange, req.GetState(), transition (Nonce/To), restate.Set,
transitionKey.
🧹 Nitpick comments (1)
svc/ctrl/worker/deploy/deploy_handler.go (1)

334-336: Consider tracking the hardcoded source type as technical debt.

Static analysis flagged this TODO. The source type should reflect actual source (GitSource vs DockerImage).

Would you like me to open an issue to track fixing this?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@svc/ctrl/worker/deploy/scale_down_idle_preview_deployments.go`:
- Around line 17-22: The comment for ScaleDownIdlePreviewDeployments is
inconsistent: it says idle deployments are transitioned to "archived" but the
implementation sets the deployment status to STANDBY; update the documentation
to reflect the actual behavior or change the code to archive if that was
intended. Locate the ScaleDownIdlePreviewDeployments declaration and the logic
that sets the status to STANDBY and either (a) change the wording in the
function comment to say "transitions idle deployments to STANDBY" or (b) if the
desired state is archived, replace the STANDBY assignment with the
ARCHIVED/archived state symbol used elsewhere; ensure the comment and the code
use the same unique symbol (STANDBY or ARCHIVED) consistently.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@svc/ctrl/proto/hydra/v1/deploy.proto`:
- Around line 17-20: The top-of-file comment incorrectly references
SetDeploymentDesiredState (which is not defined in this service); update the
comment to refer to the DeploymentService desired-state RPCs instead and keep
the description of ScaleDownIdlePreviewDeployments intact. Specifically, in the
comment block that mentions ScaleDownIdlePreviewDeployments and
SetDeploymentDesiredState, remove or replace the SetDeploymentDesiredState
reference with a phrase like "DeploymentService desired-state RPCs" so readers
are directed to the correct RPC surface (e.g., DeploymentService) while
preserving the cron/idle/standby explanation.

In `@svc/ctrl/worker/deploy/deploy_handler.go`:
- Around line 364-365: buildDomains currently hardcodes the source type to
ctrlv1.SourceType_SOURCE_TYPE_CLI_UPLOAD which mislabels DockerImage/Git
deployments; update buildDomains to accept and use the actual source type from
the incoming request or the deployment object (e.g., use req.SourceType or
deployment.SourceType) instead of the hardcoded
ctrlv1.SourceType_SOURCE_TYPE_CLI_UPLOAD, and propagate that value into the call
site so DockerImage/Git paths are labeled correctly.

In `@svc/ctrl/worker/run.go`:
- Around line 181-183: The DeploymentServiceServer bind call currently exposes
state-mutating endpoints without ingress restrictions; update the
restateSrv.Bind invocation that wraps
hydrav1.NewDeploymentServiceServer(deployment.New(deployment.Config{DB:
database})) to include the same ingress restriction used by other services
(e.g., restate.WithIngressPrivate(true)), so the DeploymentServiceServer is
bound with restate.WithIngressPrivate(true) to prevent public access to mutation
methods.
🧹 Nitpick comments (1)
svc/ctrl/worker/deploy/deploy_handler.go (1)

41-44: Doc note: replicas default isn’t always 1.

RegionConfig overrides replica count. Update comment to avoid mismatch.

Proposed minimal edit
-// The workflow creates deployment topologies for all configured regions, each with
-// a version obtained from VersioningService and 1 desired replica. Sentinel
+// The workflow creates deployment topologies for all configured regions, each with
+// a version obtained from VersioningService and desired replicas from runtime
+// settings (default 1). Sentinel

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@svc/ctrl/integration/harness/harness.go`:
- Around line 183-185: The config field passed to deployment.New uses the wrong
key name; update the struct literal for deployment.Config in harness.go to use
the expected field name Database (matching deployment.Config's Database
db.Database) instead of DB so it compiles; ensure the value you pass (database)
matches the type expected by deployment.Config's Database field.
🧹 Nitpick comments (3)
svc/ctrl/api/deployment_integration_test.go (1)

28-33: Unused requests field in mockDeploymentService.

DeploymentService RPCs (ScheduleDesiredStateChange, ChangeDesiredState, ClearScheduledStateChanges) don't use DeployRequest. This field appears to be copy-paste from mockDeployService and is never used.

♻️ Proposed cleanup
 type mockDeploymentService struct {
 	hydrav1.UnimplementedDeploymentServiceServer
-	requests chan *hydrav1.DeployRequest
 }
svc/ctrl/worker/deploy/deploy_handler.go (1)

364-365: Track TODO for source type handling.

The hardcoded SOURCE_TYPE_CLI_UPLOAD doesn't reflect the actual source (GitSource vs DockerImage). This affects domain generation accuracy.

Would you like me to open an issue to track deriving the correct SourceType from req.GetSource()?

svc/ctrl/proto/hydra/v1/deploy.proto (1)

77-78: Track removal of unused field.

The key_auth_id field is marked as unused. Consider removing it in a follow-up to avoid confusion.

Comment on lines +183 to +185
deploymentSvc := deployment.New(deployment.Config{
DB: database,
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Config field name mismatch causes compilation error.

Per the relevant snippet from svc/ctrl/worker/deployment/service.go lines 19-22, deployment.Config expects Database, not DB:

Config struct {
    Database db.Database
    ...
}
🐛 Proposed fix
 deploymentSvc := deployment.New(deployment.Config{
-    DB: database,
+    Database: database,
 })
🤖 Prompt for AI Agents
In `@svc/ctrl/integration/harness/harness.go` around lines 183 - 185, The config
field passed to deployment.New uses the wrong key name; update the struct
literal for deployment.Config in harness.go to use the expected field name
Database (matching deployment.Config's Database db.Database) instead of DB so it
compiles; ensure the value you pass (database) matches the type expected by
deployment.Config's Database field.

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.

3 participants