@@ -898,10 +898,18 @@ func (h *RegistryHandler) Heartbeat(c *gin.Context) {
|
||||
// flip, independent of evaluateStatus. evaluateStatus still owns the OTHER
|
||||
// recovery transitions (offline/degraded/awaiting_agent/failed→online),
|
||||
// which the inline CASE does not touch.
|
||||
//
|
||||
// IMPORTANT (enum scan): `status` is a NOT-NULL `workspace_status` ENUM.
|
||||
// Do NOT wrap it in COALESCE(status, '') — the '' literal is coerced to
|
||||
// the enum type and Postgres rejects it with `invalid input value for
|
||||
// enum workspace_status: ""`, failing the WHOLE row scan. That left
|
||||
// prevStatus = "" on every heartbeat, so the prevStatus=='provisioning'
|
||||
// reconcile trigger NEVER fired (the #32 regression returned). Select the
|
||||
// column bare; it is never NULL.
|
||||
var prevTask string
|
||||
var prevSpend int64
|
||||
var prevStatus string
|
||||
if err := db.DB.QueryRowContext(ctx, `SELECT COALESCE(current_task, ''), COALESCE(monthly_spend, 0), COALESCE(status, '') FROM workspaces WHERE id = $1`, payload.WorkspaceID).Scan(&prevTask, &prevSpend, &prevStatus); err != nil {
|
||||
if err := db.DB.QueryRowContext(ctx, `SELECT COALESCE(current_task, ''), COALESCE(monthly_spend, 0), status FROM workspaces WHERE id = $1`, payload.WorkspaceID).Scan(&prevTask, &prevSpend, &prevStatus); err != nil {
|
||||
log.Printf("registry heartbeat: prev_task query failed for workspace %s: %v", payload.WorkspaceID, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -271,7 +271,14 @@ func TestHeartbeatHandler_ProvisioningToOnline(t *testing.T) {
|
||||
|
||||
// prevTask + prevStatus SELECT — prevStatus='provisioning' is the state a
|
||||
// freshly-created workspace is in before its first heartbeat.
|
||||
mock.ExpectQuery("SELECT COALESCE\\(current_task").
|
||||
//
|
||||
// The matcher pins `status` selected BARE (not COALESCE-wrapped): `status`
|
||||
// is a NOT-NULL workspace_status ENUM, and COALESCE(status, '') coerces ''
|
||||
// to the enum → Postgres `invalid input value for enum workspace_status: ""`
|
||||
// → the whole row scan fails → prevStatus stays "" → this reconcile trigger
|
||||
// NEVER fires (the live #32 regression). Requiring `, status FROM workspaces`
|
||||
// here makes a re-introduced COALESCE(status, ...) fail this unit test.
|
||||
mock.ExpectQuery("SELECT COALESCE\\(current_task, ''\\), COALESCE\\(monthly_spend, 0\\), status FROM workspaces").
|
||||
WithArgs("ws-provisioning").
|
||||
WillReturnRows(sqlmock.NewRows([]string{"current_task", "monthly_spend", "status"}).AddRow("", 0, "provisioning"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user