forked from wrenn/wrenn
Replace synchronous RPC-based CP-host communication for sandbox lifecycle operations (Create, Pause, Resume, Destroy) with an async pattern. CP handlers now return 202 Accepted immediately, fire agent RPCs in background goroutines, and publish state events to a Redis Stream. A background consumer processes events as a fallback writer. Agent-side auto-pause events are pushed to the CP via HTTP callback (POST /v1/hosts/sandbox-events), keeping Redis internal to the CP. All DB status transitions use conditional updates (UpdateSandboxStatusIf, UpdateSandboxRunningIf) to prevent race conditions between concurrent operations and background goroutines. The HostMonitor reconciler is kept at 60s as a safety net, extended to handle transient statuses (starting, pausing, resuming, stopping). Frontend updated to handle 202 responses with empty bodies and render transient statuses with blue indicators.
609 lines
16 KiB
Go
609 lines
16 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.30.0
|
|
// source: sandboxes.sql
|
|
|
|
package db
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const bulkRestoreRunning = `-- name: BulkRestoreRunning :exec
|
|
UPDATE sandboxes
|
|
SET status = 'running',
|
|
last_updated = NOW()
|
|
WHERE id = ANY($1::uuid[]) AND status = 'missing'
|
|
`
|
|
|
|
// Called by the reconciler when a host comes back online and its sandboxes are
|
|
// confirmed alive. Restores only sandboxes that are in 'missing' state.
|
|
func (q *Queries) BulkRestoreRunning(ctx context.Context, dollar_1 []pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, bulkRestoreRunning, dollar_1)
|
|
return err
|
|
}
|
|
|
|
const bulkUpdateStatusByIDs = `-- name: BulkUpdateStatusByIDs :exec
|
|
UPDATE sandboxes
|
|
SET status = $2,
|
|
last_updated = NOW()
|
|
WHERE id = ANY($1::uuid[])
|
|
`
|
|
|
|
type BulkUpdateStatusByIDsParams struct {
|
|
Column1 []pgtype.UUID `json:"column_1"`
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
func (q *Queries) BulkUpdateStatusByIDs(ctx context.Context, arg BulkUpdateStatusByIDsParams) error {
|
|
_, err := q.db.Exec(ctx, bulkUpdateStatusByIDs, arg.Column1, arg.Status)
|
|
return err
|
|
}
|
|
|
|
const getSandbox = `-- name: GetSandbox :one
|
|
SELECT id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata FROM sandboxes WHERE id = $1
|
|
`
|
|
|
|
func (q *Queries) GetSandbox(ctx context.Context, id pgtype.UUID) (Sandbox, error) {
|
|
row := q.db.QueryRow(ctx, getSandbox, id)
|
|
var i Sandbox
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getSandboxByTeam = `-- name: GetSandboxByTeam :one
|
|
SELECT id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata FROM sandboxes WHERE id = $1 AND team_id = $2
|
|
`
|
|
|
|
type GetSandboxByTeamParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
TeamID pgtype.UUID `json:"team_id"`
|
|
}
|
|
|
|
func (q *Queries) GetSandboxByTeam(ctx context.Context, arg GetSandboxByTeamParams) (Sandbox, error) {
|
|
row := q.db.QueryRow(ctx, getSandboxByTeam, arg.ID, arg.TeamID)
|
|
var i Sandbox
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getSandboxProxyTarget = `-- name: GetSandboxProxyTarget :one
|
|
SELECT s.status, h.address AS host_address
|
|
FROM sandboxes s
|
|
JOIN hosts h ON h.id = s.host_id
|
|
WHERE s.id = $1
|
|
`
|
|
|
|
type GetSandboxProxyTargetRow struct {
|
|
Status string `json:"status"`
|
|
HostAddress string `json:"host_address"`
|
|
}
|
|
|
|
// Returns the sandbox status and its host's address in one query.
|
|
// Used by SandboxProxyWrapper to avoid two round-trips.
|
|
func (q *Queries) GetSandboxProxyTarget(ctx context.Context, id pgtype.UUID) (GetSandboxProxyTargetRow, error) {
|
|
row := q.db.QueryRow(ctx, getSandboxProxyTarget, id)
|
|
var i GetSandboxProxyTargetRow
|
|
err := row.Scan(&i.Status, &i.HostAddress)
|
|
return i, err
|
|
}
|
|
|
|
const insertSandbox = `-- name: InsertSandbox :one
|
|
INSERT INTO sandboxes (id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, template_id, template_team_id, metadata)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
|
RETURNING id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata
|
|
`
|
|
|
|
type InsertSandboxParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
TeamID pgtype.UUID `json:"team_id"`
|
|
HostID pgtype.UUID `json:"host_id"`
|
|
Template string `json:"template"`
|
|
Status string `json:"status"`
|
|
Vcpus int32 `json:"vcpus"`
|
|
MemoryMb int32 `json:"memory_mb"`
|
|
TimeoutSec int32 `json:"timeout_sec"`
|
|
DiskSizeMb int32 `json:"disk_size_mb"`
|
|
TemplateID pgtype.UUID `json:"template_id"`
|
|
TemplateTeamID pgtype.UUID `json:"template_team_id"`
|
|
Metadata []byte `json:"metadata"`
|
|
}
|
|
|
|
func (q *Queries) InsertSandbox(ctx context.Context, arg InsertSandboxParams) (Sandbox, error) {
|
|
row := q.db.QueryRow(ctx, insertSandbox,
|
|
arg.ID,
|
|
arg.TeamID,
|
|
arg.HostID,
|
|
arg.Template,
|
|
arg.Status,
|
|
arg.Vcpus,
|
|
arg.MemoryMb,
|
|
arg.TimeoutSec,
|
|
arg.DiskSizeMb,
|
|
arg.TemplateID,
|
|
arg.TemplateTeamID,
|
|
arg.Metadata,
|
|
)
|
|
var i Sandbox
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const listActiveSandboxesByTeam = `-- name: ListActiveSandboxesByTeam :many
|
|
SELECT id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata FROM sandboxes
|
|
WHERE team_id = $1 AND status IN ('running', 'paused', 'starting', 'hibernated')
|
|
ORDER BY created_at DESC
|
|
`
|
|
|
|
func (q *Queries) ListActiveSandboxesByTeam(ctx context.Context, teamID pgtype.UUID) ([]Sandbox, error) {
|
|
rows, err := q.db.Query(ctx, listActiveSandboxesByTeam, teamID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Sandbox
|
|
for rows.Next() {
|
|
var i Sandbox
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listSandboxes = `-- name: ListSandboxes :many
|
|
SELECT id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata FROM sandboxes ORDER BY created_at DESC
|
|
`
|
|
|
|
func (q *Queries) ListSandboxes(ctx context.Context) ([]Sandbox, error) {
|
|
rows, err := q.db.Query(ctx, listSandboxes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Sandbox
|
|
for rows.Next() {
|
|
var i Sandbox
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listSandboxesByHostAndStatus = `-- name: ListSandboxesByHostAndStatus :many
|
|
SELECT id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata FROM sandboxes
|
|
WHERE host_id = $1 AND status = ANY($2::text[])
|
|
ORDER BY created_at DESC
|
|
`
|
|
|
|
type ListSandboxesByHostAndStatusParams struct {
|
|
HostID pgtype.UUID `json:"host_id"`
|
|
Column2 []string `json:"column_2"`
|
|
}
|
|
|
|
func (q *Queries) ListSandboxesByHostAndStatus(ctx context.Context, arg ListSandboxesByHostAndStatusParams) ([]Sandbox, error) {
|
|
rows, err := q.db.Query(ctx, listSandboxesByHostAndStatus, arg.HostID, arg.Column2)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Sandbox
|
|
for rows.Next() {
|
|
var i Sandbox
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listSandboxesByTeam = `-- name: ListSandboxesByTeam :many
|
|
SELECT id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata FROM sandboxes
|
|
WHERE team_id = $1 AND status NOT IN ('stopped', 'error')
|
|
ORDER BY created_at DESC
|
|
`
|
|
|
|
func (q *Queries) ListSandboxesByTeam(ctx context.Context, teamID pgtype.UUID) ([]Sandbox, error) {
|
|
rows, err := q.db.Query(ctx, listSandboxesByTeam, teamID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Sandbox
|
|
for rows.Next() {
|
|
var i Sandbox
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const markSandboxesMissingByHost = `-- name: MarkSandboxesMissingByHost :exec
|
|
UPDATE sandboxes
|
|
SET status = 'missing',
|
|
last_updated = NOW()
|
|
WHERE host_id = $1 AND status IN ('running', 'starting', 'pending', 'pausing', 'resuming', 'stopping')
|
|
`
|
|
|
|
// Called when the host monitor marks a host unreachable.
|
|
// Marks running/starting/pending sandboxes on that host as 'missing' so users see
|
|
// the sandbox is not currently reachable, without permanently losing the record.
|
|
func (q *Queries) MarkSandboxesMissingByHost(ctx context.Context, hostID pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, markSandboxesMissingByHost, hostID)
|
|
return err
|
|
}
|
|
|
|
const updateLastActive = `-- name: UpdateLastActive :exec
|
|
UPDATE sandboxes
|
|
SET last_active_at = $2,
|
|
last_updated = NOW()
|
|
WHERE id = $1
|
|
`
|
|
|
|
type UpdateLastActiveParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
LastActiveAt pgtype.Timestamptz `json:"last_active_at"`
|
|
}
|
|
|
|
func (q *Queries) UpdateLastActive(ctx context.Context, arg UpdateLastActiveParams) error {
|
|
_, err := q.db.Exec(ctx, updateLastActive, arg.ID, arg.LastActiveAt)
|
|
return err
|
|
}
|
|
|
|
const updateSandboxMetadata = `-- name: UpdateSandboxMetadata :exec
|
|
UPDATE sandboxes
|
|
SET metadata = $2,
|
|
last_updated = NOW()
|
|
WHERE id = $1
|
|
`
|
|
|
|
type UpdateSandboxMetadataParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
Metadata []byte `json:"metadata"`
|
|
}
|
|
|
|
func (q *Queries) UpdateSandboxMetadata(ctx context.Context, arg UpdateSandboxMetadataParams) error {
|
|
_, err := q.db.Exec(ctx, updateSandboxMetadata, arg.ID, arg.Metadata)
|
|
return err
|
|
}
|
|
|
|
const updateSandboxRunning = `-- name: UpdateSandboxRunning :one
|
|
UPDATE sandboxes
|
|
SET status = 'running',
|
|
host_ip = $2,
|
|
guest_ip = $3,
|
|
started_at = $4,
|
|
last_active_at = $4,
|
|
last_updated = NOW()
|
|
WHERE id = $1
|
|
RETURNING id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata
|
|
`
|
|
|
|
type UpdateSandboxRunningParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
HostIp string `json:"host_ip"`
|
|
GuestIp string `json:"guest_ip"`
|
|
StartedAt pgtype.Timestamptz `json:"started_at"`
|
|
}
|
|
|
|
func (q *Queries) UpdateSandboxRunning(ctx context.Context, arg UpdateSandboxRunningParams) (Sandbox, error) {
|
|
row := q.db.QueryRow(ctx, updateSandboxRunning,
|
|
arg.ID,
|
|
arg.HostIp,
|
|
arg.GuestIp,
|
|
arg.StartedAt,
|
|
)
|
|
var i Sandbox
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const updateSandboxRunningIf = `-- name: UpdateSandboxRunningIf :one
|
|
UPDATE sandboxes
|
|
SET status = 'running',
|
|
host_ip = $3,
|
|
guest_ip = $4,
|
|
started_at = $5,
|
|
last_active_at = $5,
|
|
last_updated = NOW()
|
|
WHERE id = $1 AND status = $2
|
|
RETURNING id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata
|
|
`
|
|
|
|
type UpdateSandboxRunningIfParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
Status string `json:"status"`
|
|
HostIp string `json:"host_ip"`
|
|
GuestIp string `json:"guest_ip"`
|
|
StartedAt pgtype.Timestamptz `json:"started_at"`
|
|
}
|
|
|
|
// Conditionally transition a sandbox to running only if the current status
|
|
// matches the expected value. Prevents races where a user destroys a sandbox
|
|
// while the create/resume goroutine is still in-flight.
|
|
func (q *Queries) UpdateSandboxRunningIf(ctx context.Context, arg UpdateSandboxRunningIfParams) (Sandbox, error) {
|
|
row := q.db.QueryRow(ctx, updateSandboxRunningIf,
|
|
arg.ID,
|
|
arg.Status,
|
|
arg.HostIp,
|
|
arg.GuestIp,
|
|
arg.StartedAt,
|
|
)
|
|
var i Sandbox
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const updateSandboxStatus = `-- name: UpdateSandboxStatus :one
|
|
UPDATE sandboxes
|
|
SET status = $2,
|
|
last_updated = NOW()
|
|
WHERE id = $1
|
|
RETURNING id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata
|
|
`
|
|
|
|
type UpdateSandboxStatusParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
func (q *Queries) UpdateSandboxStatus(ctx context.Context, arg UpdateSandboxStatusParams) (Sandbox, error) {
|
|
row := q.db.QueryRow(ctx, updateSandboxStatus, arg.ID, arg.Status)
|
|
var i Sandbox
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const updateSandboxStatusIf = `-- name: UpdateSandboxStatusIf :one
|
|
UPDATE sandboxes
|
|
SET status = $3,
|
|
last_updated = NOW()
|
|
WHERE id = $1 AND status = $2
|
|
RETURNING id, team_id, host_id, template, status, vcpus, memory_mb, timeout_sec, disk_size_mb, guest_ip, host_ip, created_at, started_at, last_active_at, last_updated, template_id, template_team_id, metadata
|
|
`
|
|
|
|
type UpdateSandboxStatusIfParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
Status string `json:"status"`
|
|
Status_2 string `json:"status_2"`
|
|
}
|
|
|
|
// Atomically update status only when the current status matches the expected value.
|
|
// Prevents background goroutines from overwriting a status that has since changed
|
|
// (e.g. user destroyed a sandbox while Create was in-flight).
|
|
func (q *Queries) UpdateSandboxStatusIf(ctx context.Context, arg UpdateSandboxStatusIfParams) (Sandbox, error) {
|
|
row := q.db.QueryRow(ctx, updateSandboxStatusIf, arg.ID, arg.Status, arg.Status_2)
|
|
var i Sandbox
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.TeamID,
|
|
&i.HostID,
|
|
&i.Template,
|
|
&i.Status,
|
|
&i.Vcpus,
|
|
&i.MemoryMb,
|
|
&i.TimeoutSec,
|
|
&i.DiskSizeMb,
|
|
&i.GuestIp,
|
|
&i.HostIp,
|
|
&i.CreatedAt,
|
|
&i.StartedAt,
|
|
&i.LastActiveAt,
|
|
&i.LastUpdated,
|
|
&i.TemplateID,
|
|
&i.TemplateTeamID,
|
|
&i.Metadata,
|
|
)
|
|
return i, err
|
|
}
|