Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 66 additions & 1 deletion platform-api/api/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions platform-api/config/config-template.toml
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ enable_functionality_type_verification = false
# ---------------------------------------------------------------------------
[platform_api.deployments]
max_per_api_gateway = 20 # maximum API deployments per gateway
max_builds_per_api = 50 # maximum stored builds per API; preparing more prunes
# the oldest builds no gateway is deployed from (0 = keep all)

# Deployment timeout — mark stuck deployments as failed after timeout_duration seconds.
timeout_enabled = true
Expand Down
12 changes: 8 additions & 4 deletions platform-api/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,10 +554,14 @@ type Database struct {

// Deployments holds deployment-specific configuration.
type Deployments struct {
MaxPerAPIGateway int `koanf:"max_per_api_gateway"`
TimeoutEnabled bool `koanf:"timeout_enabled"`
TimeoutInterval int `koanf:"timeout_interval"`
TimeoutDuration int `koanf:"timeout_duration"`
MaxPerAPIGateway int `koanf:"max_per_api_gateway"`
// MaxBuildsPerAPI caps how many builds are stored per API. Preparing another
// one past this prunes the API's oldest builds that no gateway is deployed
// from. Zero or less keeps every build.
MaxBuildsPerAPI int `koanf:"max_builds_per_api"`
TimeoutEnabled bool `koanf:"timeout_enabled"`
TimeoutInterval int `koanf:"timeout_interval"`
TimeoutDuration int `koanf:"timeout_duration"`
}

// APIKey holds API key-specific configuration.
Expand Down
1 change: 1 addition & 0 deletions platform-api/config/default_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ func defaultConfig() *Server {
},
Deployments: Deployments{
MaxPerAPIGateway: 20,
MaxBuildsPerAPI: 50,
TimeoutEnabled: true,
TimeoutInterval: 20,
TimeoutDuration: 60,
Expand Down
1 change: 1 addition & 0 deletions platform-api/internal/apperror/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ var (
// MCP proxy deployment operations. DeploymentNotActive's verb is the artifact
// kind, e.g. "API", "LLM provider".
var (
BuildNotFound = def(CodeBuildNotFound, http.StatusNotFound, "The specified build could not be found.")
DeploymentBaseNotFound = def(CodeDeploymentBaseNotFound, http.StatusNotFound, "The specified base deployment could not be found.")
DeploymentRestoreConflict = def(CodeDeploymentRestoreConflict, http.StatusConflict, "Cannot restore the currently deployed deployment, or the deployment is invalid.")
DeploymentNotFound = def(CodeDeploymentNotFound, http.StatusNotFound, "The specified deployment could not be found.")
Expand Down
1 change: 1 addition & 0 deletions platform-api/internal/apperror/codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const (
// Deployment domain codes, shared across REST API / LLM provider / LLM proxy /
// MCP proxy deployment operations (identical conditions across all four).
const (
CodeBuildNotFound = "BUILD_NOT_FOUND"
CodeDeploymentBaseNotFound = "DEPLOYMENT_BASE_NOT_FOUND"
CodeDeploymentRestoreConflict = "DEPLOYMENT_RESTORE_CONFLICT"
CodeDeploymentNotFound = "DEPLOYMENT_NOT_FOUND"
Expand Down
5 changes: 5 additions & 0 deletions platform-api/internal/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ const DeletedUser = "deleted_user"
const (
// DeploymentLimitBuffer is the buffer added to MaxPerAPIGateway for hard limit enforcement
DeploymentLimitBuffer = 100

// BuildCleanupBatch is how many of an API's unused builds are removed when
// preparing another one reaches the limit. A batch rather than one keeps the
// cleanup from running on every single prepare.
BuildCleanupBatch = 5
)

// Gateway artifact apiVersion (the `apiVersion:` field on deployment artifacts).
Expand Down
20 changes: 20 additions & 0 deletions platform-api/internal/database/schema.postgres.sql
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,22 @@ CREATE TABLE IF NOT EXISTS gateway_tokens (
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE
);

-- Builds table (immutable rendered snapshots of an API's definition)
CREATE TABLE IF NOT EXISTS builds (
uuid VARCHAR(40) PRIMARY KEY,
build_id VARCHAR(40) NOT NULL,
artifact_uuid VARCHAR(40) NOT NULL,
organization_uuid VARCHAR(40) NOT NULL,
content BYTEA NOT NULL,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
metadata BYTEA,
created_by VARCHAR(200),
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
UNIQUE (artifact_uuid, build_id),
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE
);

-- Artifact Deployments table (immutable deployment artifacts)
CREATE TABLE IF NOT EXISTS deployments (
uuid VARCHAR(40) PRIMARY KEY,
Expand All @@ -273,11 +289,13 @@ CREATE TABLE IF NOT EXISTS deployments (
organization_uuid VARCHAR(40) NOT NULL,
gateway_uuid VARCHAR(40) NOT NULL,
base_deployment_uuid VARCHAR(40),
build_uuid VARCHAR(40),
content BYTEA NOT NULL,
metadata BYTEA,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
created_by VARCHAR(200),
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (build_uuid) REFERENCES builds(uuid) ON DELETE NO ACTION,
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE,
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE,
Expand Down Expand Up @@ -488,6 +506,8 @@ CREATE INDEX IF NOT EXISTS idx_subscription_plans_status ON subscription_plans(s
CREATE INDEX IF NOT EXISTS idx_subscription_plan_limits_plan ON subscription_plan_limits(subscription_plan_uuid);

CREATE INDEX IF NOT EXISTS idx_artifact_subscription_plans_plan ON artifact_subscription_plans(subscription_plan_uuid);
CREATE INDEX IF NOT EXISTS idx_builds_artifact ON builds(artifact_uuid, organization_uuid, created_at);
CREATE INDEX IF NOT EXISTS idx_deployments_build ON deployments(build_uuid);

-- EventHub tables for multi-replica HA sync
CREATE TABLE IF NOT EXISTS gateway_states (
Expand Down
20 changes: 20 additions & 0 deletions platform-api/internal/database/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,22 @@ CREATE TABLE IF NOT EXISTS gateway_tokens (
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE
);

-- Builds table (immutable rendered snapshots of an API's definition)
CREATE TABLE IF NOT EXISTS builds (
uuid VARCHAR(40) PRIMARY KEY,
build_id VARCHAR(40) NOT NULL,
artifact_uuid VARCHAR(40) NOT NULL,
organization_uuid VARCHAR(40) NOT NULL,
content BLOB NOT NULL,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
metadata BLOB,
created_by VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE (artifact_uuid, build_id),
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE
);

-- Artifact Deployments table (immutable deployment artifacts)
CREATE TABLE IF NOT EXISTS deployments (
uuid VARCHAR(40) PRIMARY KEY,
Expand All @@ -265,11 +281,13 @@ CREATE TABLE IF NOT EXISTS deployments (
organization_uuid VARCHAR(40) NOT NULL,
gateway_uuid VARCHAR(40) NOT NULL,
base_deployment_uuid VARCHAR(40),
build_uuid VARCHAR(40),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
content BLOB NOT NULL,
metadata BLOB,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
created_by VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (build_uuid) REFERENCES builds(uuid) ON DELETE NO ACTION,
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE,
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE,
Expand Down Expand Up @@ -483,6 +501,8 @@ CREATE INDEX IF NOT EXISTS idx_subscription_plans_status ON subscription_plans(s
CREATE INDEX IF NOT EXISTS idx_subscription_plan_limits_plan ON subscription_plan_limits(subscription_plan_uuid);

CREATE INDEX IF NOT EXISTS idx_artifact_subscription_plans_plan ON artifact_subscription_plans(subscription_plan_uuid);
CREATE INDEX IF NOT EXISTS idx_builds_artifact ON builds(artifact_uuid, organization_uuid, created_at);
CREATE INDEX IF NOT EXISTS idx_deployments_build ON deployments(build_uuid);

-- EventHub tables for multi-replica HA sync
CREATE TABLE IF NOT EXISTS gateway_states (
Expand Down
20 changes: 20 additions & 0 deletions platform-api/internal/database/schema.sqlite.sql
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,22 @@ CREATE TABLE IF NOT EXISTS gateway_tokens (
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE
);

-- Builds table (immutable rendered snapshots of an API's definition)
CREATE TABLE IF NOT EXISTS builds (
uuid VARCHAR(40) PRIMARY KEY,
build_id VARCHAR(40) NOT NULL,
artifact_uuid VARCHAR(40) NOT NULL,
organization_uuid VARCHAR(40) NOT NULL,
content BLOB NOT NULL,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
metadata BLOB,
created_by VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE (artifact_uuid, build_id),
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE
);

-- Artifact Deployments table (immutable deployment artifacts)
CREATE TABLE IF NOT EXISTS deployments (
uuid VARCHAR(40) PRIMARY KEY,
Expand All @@ -273,11 +289,13 @@ CREATE TABLE IF NOT EXISTS deployments (
organization_uuid VARCHAR(40) NOT NULL,
gateway_uuid VARCHAR(40) NOT NULL,
base_deployment_uuid VARCHAR(40),
build_uuid VARCHAR(40),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
content BLOB NOT NULL,
metadata BLOB,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
created_by VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (build_uuid) REFERENCES builds(uuid) ON DELETE NO ACTION,
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE,
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE,
Expand Down Expand Up @@ -488,6 +506,8 @@ CREATE INDEX IF NOT EXISTS idx_subscription_plans_status ON subscription_plans(s
CREATE INDEX IF NOT EXISTS idx_subscription_plan_limits_plan ON subscription_plan_limits(subscription_plan_uuid);

CREATE INDEX IF NOT EXISTS idx_artifact_subscription_plans_plan ON artifact_subscription_plans(subscription_plan_uuid);
CREATE INDEX IF NOT EXISTS idx_builds_artifact ON builds(artifact_uuid, organization_uuid, created_at);
CREATE INDEX IF NOT EXISTS idx_deployments_build ON deployments(build_uuid);

-- EventHub tables for multi-replica HA sync
CREATE TABLE IF NOT EXISTS gateway_states (
Expand Down
29 changes: 29 additions & 0 deletions platform-api/internal/database/schema.sqlserver.sql
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,26 @@ CREATE TABLE dbo.gateway_tokens (
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE
);

-- Builds table (immutable rendered snapshots of an API's definition)
IF OBJECT_ID(N'dbo.builds', N'U') IS NULL
CREATE TABLE dbo.builds (
Comment thread
coderabbitai[bot] marked this conversation as resolved.
uuid VARCHAR(40) PRIMARY KEY,
build_id VARCHAR(40) NOT NULL,
artifact_uuid VARCHAR(40) NOT NULL,
organization_uuid VARCHAR(40) NOT NULL,
content VARBINARY(MAX) NOT NULL,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
metadata VARBINARY(MAX),
created_by VARCHAR(200),
created_at DATETIME2(7) DEFAULT SYSUTCDATETIME(),
UNIQUE (artifact_uuid, build_id),
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
-- NO ACTION to avoid the SQL Server multiple-cascade-paths restriction
-- (error 1785); organization deletes still reach builds through
-- organizations -> artifacts -> builds.
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE NO ACTION
);

-- Artifact Deployments table (immutable deployment artifacts)
IF OBJECT_ID(N'dbo.deployments', N'U') IS NULL
CREATE TABLE dbo.deployments (
Expand All @@ -302,11 +322,16 @@ CREATE TABLE dbo.deployments (
organization_uuid VARCHAR(40) NOT NULL,
gateway_uuid VARCHAR(40) NOT NULL,
base_deployment_uuid VARCHAR(40),
build_uuid VARCHAR(40),
content VARBINARY(MAX) NOT NULL,
metadata VARBINARY(MAX),
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
created_by VARCHAR(200),
created_at DATETIME2(7) DEFAULT SYSUTCDATETIME(),
-- NO ACTION, with references cleared explicitly before a build is pruned:
-- cleanup here is done in code, in dependency order, rather than left to the
-- database (SQL Server also forbids further cascade paths onto this table).
FOREIGN KEY (build_uuid) REFERENCES builds(uuid) ON DELETE NO ACTION,
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
-- NO ACTION to avoid the SQL Server multiple-cascade-paths restriction
-- (error 1785). Organization deletes still reach deployments through
Expand Down Expand Up @@ -585,6 +610,10 @@ CREATE INDEX idx_subscription_plan_limits_plan ON dbo.subscription_plan_limits(s

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'idx_artifact_subscription_plans_plan' AND object_id = OBJECT_ID(N'dbo.artifact_subscription_plans'))
CREATE INDEX idx_artifact_subscription_plans_plan ON dbo.artifact_subscription_plans(subscription_plan_uuid);
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'idx_builds_artifact' AND object_id = OBJECT_ID(N'dbo.builds'))
CREATE INDEX idx_builds_artifact ON dbo.builds(artifact_uuid, organization_uuid, created_at);
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'idx_deployments_build' AND object_id = OBJECT_ID(N'dbo.deployments'))
CREATE INDEX idx_deployments_build ON dbo.deployments(build_uuid);

-- EventHub tables for multi-replica HA sync and gateway event propagation.
-- Keyed columns are bounded NVARCHAR to stay within SQL Server index-key limits.
Expand Down
Loading
Loading