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
482 changes: 457 additions & 25 deletions openapi/openapiv2.json

Large diffs are not rendered by default.

434 changes: 401 additions & 33 deletions openapi/openapiv3.yaml

Large diffs are not rendered by default.

31 changes: 25 additions & 6 deletions temporal/api/compute/v1/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,34 @@ option csharp_namespace = "Temporalio.Api.Compute.V1";

import "temporal/api/compute/v1/provider.proto";
import "temporal/api/compute/v1/scaler.proto";
import "temporal/api/enums/v1/task_queue.proto";

// ComputeConfig stores configuration that helps a worker control plane
// controller understand *when* and *how* to respond to worker lifecycle
// events.
message ComputeConfig {
// Stores instructions for a worker control plane controller how to respond
// to worker lifeycle events.
temporal.api.compute.v1.ComputeProvider provider = 1;
// Informs a worker lifecycle controller *when* and *how often* to perform
// certain worker lifecycle actions like starting a serverless worker.
temporal.api.compute.v1.ComputeScaler scaler = 2;
message ScalingGroup {
Copy link
Member

Choose a reason for hiding this comment

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

nit: I would flatten this out to a top level message if there's any chance that this message will be reused in the future.

// Optional. The set of task queue types this scaling group serves.
// If not provided, this scaling group serves all not otherwise defined
// task types.
repeated temporal.api.enums.v1.TaskQueueType task_queue_types = 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Would empty list be supported? if so, would it mean a catch-all?
Also clarify that same region cannot have more than one scaling group for the same tq type.

Copy link
Author

Choose a reason for hiding this comment

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

yes empty would be supported and catch-all - updated the text


// Stores instructions for a worker control plane controller how to respond
// to worker lifeycle events.
temporal.api.compute.v1.ComputeProvider provider = 3;

// Informs a worker lifecycle controller *when* and *how often* to perform
// certain worker lifecycle actions like starting a serverless worker.
temporal.api.compute.v1.ComputeScaler scaler = 4;
}

// Each scaling group describes a compute config for a specific subset of the worker
// deployment version: covering a specific set of task types and/or regions.
// Having different configurations for different task types, allows independent
// tuning of activity and workflow task processing (for example).
//
// The key of the map is the ID of the scaling group used to reference it in subsequent
// update calls.
map<string, ScalingGroup> scaling_groups = 1;
}

8 changes: 3 additions & 5 deletions temporal/api/compute/v1/provider.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@ message ComputeProvider {
string type = 1;
// Contains provider-specific instructions and configuration.
oneof detail {
// will be an unencrypted, JSON-encoded object of provider-specific
// information
// Unencrypted, JSON-encoded object of provider-specific information
// (-- api-linter: core::0146::any=disabled
// aip.dev/not-precedent: This needs to be extensible to
// externally-written compute providers --)
string detail_json = 2;
// will be an encrypted, encoded bytestring containing
// provider-specific information. The implementation must understand
// how to decrypt the payload.
// Encrypted, encoded bytestring containing provider-specific
Copy link
Member

Choose a reason for hiding this comment

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

This would be optionally encrypted.

// information. The implementation must understand how to decrypt the payload.
temporal.api.common.v1.Payload detail_payload = 3;
Copy link
Member

Choose a reason for hiding this comment

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

Use only payload please, there's a straightforward way of expressing plain JSON in a payload.

Copy link
Author

Choose a reason for hiding this comment

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

@bergundy got a pointer by any chance?

}
// Optional. If the compute provider is a Nexus service, this should point
Expand Down
26 changes: 19 additions & 7 deletions temporal/api/compute/v1/scaler.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,26 @@ option java_outer_classname = "ScalerProto";
option ruby_package = "Temporalio::Api::Compute::V1";
option csharp_namespace = "Temporalio.Api.Compute.V1";

import "temporal/api/common/v1/message.proto";

// ComputeScaler instructs the Temporal Service when to scale up or down the number of
// Workers that comprise a WorkerDeployment.
message ComputeScaler {
// The lower limit for the number of Workers (in the WorkerDeployment) to
// which the ComputeScaler can scale down.
int32 min_instances = 1;
// The upper limit for the number of Workers (in the WorkerDeployment) to
// which the ComputeScaler can scale up. Must be greater than or equal to
// min_instances.
int32 max_instances = 2;
// Type of the compute scaler. this string is implementation-specific and
// can be used by implementations to understand how to interpret the
// contents of the scaler_details field.
string type = 1;
Copy link
Member

Choose a reason for hiding this comment

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

nit: use upper case letters when starting sentences to be consistent with the rest of the API.

Copy link
Author

Choose a reason for hiding this comment

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

done


// Contains scaler-specific instructions and configuration.
oneof detail {
// Unencrypted, JSON-encoded object of scaler-specific information
// (-- api-linter: core::0146::any=disabled
// aip.dev/not-precedent: This needs to be extensible to
// externally-written compute scalers --)
string detail_json = 2;
Copy link
Member

Choose a reason for hiding this comment

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

Why not use payload always? Payload with metdata["encoding"] = "json/plain" achieves what you want here.

Copy link
Author

Choose a reason for hiding this comment

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

The detail_json is consumed by the server (i.e. parsed and understood), while the payload is meant to be used with remote providers and passed onward as-is without the server inspecting it.

If even with that context, you believe this should always be a payload, happy to change it (this was specific feedback we had received on the first API PR).


// Encrypted, encoded bytestring containing scaler-specific
// information. The implementation must understand how to decrypt the payload.
temporal.api.common.v1.Payload detail_payload = 3;
Comment on lines +28 to +32
Copy link
Member

Choose a reason for hiding this comment

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

Same here, no need for both of these fields.

}
}
8 changes: 4 additions & 4 deletions temporal/api/deployment/v1/message.proto
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ message WorkerDeploymentVersionInfo {

// Arbitrary user-provided metadata attached to this version.
VersionMetadata metadata = 10;

// Optional. Contains the new worker compute configuration for the Worker
// Deployment. Used for worker scale management.
temporal.api.compute.v1.ComputeConfig compute_config = 16;
}

// Information about workflow drainage to help the user determine when it is safe
Expand Down Expand Up @@ -212,10 +216,6 @@ message WorkerDeploymentInfo {
// relevant task queues and their partitions.
temporal.api.enums.v1.RoutingConfigUpdateState routing_config_update_state = 7;

// Contains information used by worker control plane controllers to handle
// scale events.
temporal.api.compute.v1.ComputeConfig compute_config = 20;

message WorkerDeploymentVersionSummary {
// Deprecated. Use `deployment_version`.
string version = 1 [deprecated = true];
Expand Down
88 changes: 81 additions & 7 deletions temporal/api/workflowservice/v1/request_response.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1268,10 +1268,10 @@ message GetSystemInfoResponse {
// This flag is dependent both on server version and for Nexus to be enabled via server configuration.
bool nexus = 11;

// True if the server supports serverless deployments.
// This flag is dependent both on server version and for serverless deployments
// True if the server supports server-scaled deployments.
// This flag is dependent both on server version and for server-scaled deployments
// to be enabled via server configuration.
bool serverless_deployments = 12;
bool server_scaled_deployments = 12;

}
}
Expand Down Expand Up @@ -2353,10 +2353,6 @@ message CreateWorkerDeploymentRequest {
// this name already exists, an error will be returned.
string deployment_name = 2;

// Optional. Contains the new worker compute configuration for the Worker
// Deployment. Used for worker scale management.
temporal.api.compute.v1.ComputeConfig compute_config = 3;

// Optional. The identity of the client who initiated this request.
string identity = 4;
// A unique identifier for this create request for idempotence. Typically UUIDv4.
Expand Down Expand Up @@ -2396,6 +2392,32 @@ message ListWorkerDeploymentsResponse {
}
}

// Creates a new WorkerDeploymentVersion.
message CreateWorkerDeploymentVersionRequest {
string namespace = 1;
// Required.
temporal.api.deployment.v1.WorkerDeploymentVersion deployment_version = 2;

// Optional. Contains the new worker compute configuration for the Worker
// Deployment. Used for worker scale management.
temporal.api.compute.v1.ComputeConfig compute_config = 4;

// Optional. The identity of the client who initiated this request.
string identity = 3;

// A unique identifier for this create request for idempotence. Typically UUIDv4.
Copy link
Member

Choose a reason for hiding this comment

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

Worth noting how this is used, does the server dedupe requests with the same idempotency key?

Copy link
Author

Choose a reason for hiding this comment

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

@ShahabT can you confirm the details so I am not mis-representing here?

Copy link
Contributor

Choose a reason for hiding this comment

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

here is the behavior, we can document:

  • Retrying with same request id is a successful no-op.
  • Retrying with different request id is an error.
  • One the object is deleted, any request id (even one used for a previous creation) will re-create it.

Copy link
Author

Choose a reason for hiding this comment

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

Updated the comment with Shahab's notes

// If a second request with the same ID is recieved, it is considered a successful no-op.
// Retrying with a different request ID for the same deployment name + build ID is an error.
string request_id = 5;
}

message CreateWorkerDeploymentVersionResponse {
// This value is returned so that it can be optionally passed to APIs that
// write to the WorkerDeployment state to ensure that the state did not
// change between this API call and a future write.
bytes conflict_token = 1;
}

// Used for manual deletion of Versions. User can delete a Version only when all the
// following conditions are met:
// - It is not the Current or Ramping Version of its Deployment.
Expand Down Expand Up @@ -2430,6 +2452,58 @@ message DeleteWorkerDeploymentRequest {
message DeleteWorkerDeploymentResponse {
}

// Used to update the compute config of a Worker Deployment Version.
message UpdateWorkerDeploymentVersionComputeConfigRequest {
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this take a conflict token and a ComputeConfig object?

Copy link
Member

Choose a reason for hiding this comment

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

What about a request ID?

Copy link
Author

Choose a reason for hiding this comment

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

done - both

string namespace = 1;

// Required.
temporal.api.deployment.v1.WorkerDeploymentVersion deployment_version = 2;

// Optional. Contains the compute config scaling groups to add or updated for the Worker
// Deployment.
map<string, temporal.api.compute.v1.ComputeConfig.ScalingGroup> compute_config_scaling_groups = 6;
Copy link
Member

Choose a reason for hiding this comment

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

I would recommend using field masks for update APIs. We've done that in a few places (see UpdateActivityOptions). This way if you add fields that the client is not aware of they will not accidentally be deleted on update.

Copy link
Author

Choose a reason for hiding this comment

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

@ShahabT ?

This was what other APIs around here already used.


// Optional. Contains the compute config scaling groups to remove from the Worker Deployment.
repeated string remove_compute_config_scaling_groups = 7;
Comment on lines +2466 to +2467

Choose a reason for hiding this comment

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

I'm not a huge fan of separating out a "remove" list from an "add/update" list, but if this is a pattern used elsewhere in the API, ok :) I prefer a Replace-style pattern where the user passes the exact desired state, including any existing list or map fields and the server simply replaces those fields with the supplied values. Additionally, having a add or remove separate API call to add/remove individual list items from a list field is a good idea. So, in this case, we'd add AddWorkerDeploymentVersionScalingGroup and RemoveWorkerDeploymentVersionScalingGroup API calls...

But again, if this is not a pattern used in the existing API, so be it :)

Copy link
Author

Choose a reason for hiding this comment

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

Yeah, this was changed from replace-style to add/update based on feedback what is used elsewhere in the API


// Optional. The identity of the client who initiated this request.
string identity = 3;

// A unique identifier for this create request for idempotence. Typically UUIDv4.
// If a second request with the same ID is recieved, it is considered a successful no-op.
// Retrying with a different request ID for the same deployment name + build ID is an error.
string request_id = 4;

// This value is returned so that it can be optionally passed to APIs
// that write to the Worker Deployment state to ensure that the state
// did not change between this API call and a future write.
bytes conflict_token = 5;
}

message UpdateWorkerDeploymentVersionComputeConfigResponse {
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to return a conflict token here?

Copy link
Author

Choose a reason for hiding this comment

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

done

// This value is returned so that it can be optionally passed to APIs that
// write to the WorkerDeployment state to ensure that the state did not
// change between this API call and a future write.
bytes conflict_token = 1;
}

// Used to validate the compute config without attaching it to a Worker Deployment Version.
message ValidateWorkerDeploymentVersionComputeConfigRequest {
string namespace = 1;

// Required.
temporal.api.deployment.v1.WorkerDeploymentVersion deployment_version = 2;

// Required. Contains the new worker compute configuration for the Worker Deployment.
temporal.api.compute.v1.ComputeConfig compute_config = 4;

// Optional. The identity of the client who initiated this request.
string identity = 3;
}

message ValidateWorkerDeploymentVersionComputeConfigResponse {
}

// Used to update the user-defined metadata of a Worker Deployment Version.
message UpdateWorkerDeploymentVersionMetadataRequest {
string namespace = 1;
Expand Down
41 changes: 41 additions & 0 deletions temporal/api/workflowservice/v1/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,47 @@ service WorkflowService {
};
}

// Creates a new Worker Deployment Version.
//
// Experimental. This API might significantly change or be removed in a
// future release.
rpc CreateWorkerDeploymentVersion (CreateWorkerDeploymentVersionRequest) returns (CreateWorkerDeploymentVersionResponse) {
option (google.api.http) = {
post: "/namespaces/{namespace}/worker-deployment-versions/{deployment_version.deployment_name}"
body: "*"
additional_bindings {
post: "/api/v1/namespaces/{namespace}/worker-deployment-versions/{deployment_version.deployment_name}"
body: "*"
}
};
}

// Updates the compute config attached to a Worker Deployment Version.
// Experimental. This API might significantly change or be removed in a future release.
rpc UpdateWorkerDeploymentVersionComputeConfig (UpdateWorkerDeploymentVersionComputeConfigRequest) returns (UpdateWorkerDeploymentVersionComputeConfigResponse) {
option (google.api.http) = {
post: "/namespaces/{namespace}/worker-deployment-versions/{deployment_version.deployment_name}/{deployment_version.build_id}/update-compute-config"
body: "*"
additional_bindings {
post: "/api/v1/namespaces/{namespace}/worker-deployment-versions/{deployment_version.deployment_name}/{deployment_version.build_id}/update-compute-config"
body: "*"
}
};
}

// Validates the compute config without attaching it to a Worker Deployment Version.
// Experimental. This API might significantly change or be removed in a future release.
rpc ValidateWorkerDeploymentVersionComputeConfig (ValidateWorkerDeploymentVersionComputeConfigRequest) returns (ValidateWorkerDeploymentVersionComputeConfigResponse) {
option (google.api.http) = {
post: "/namespaces/{namespace}/worker-deployment-versions/{deployment_version.deployment_name}/{deployment_version.build_id}/validate-compute-config"
body: "*"
additional_bindings {
post: "/api/v1/namespaces/{namespace}/worker-deployment-versions/{deployment_version.deployment_name}/{deployment_version.build_id}/validate-compute-config"
body: "*"
}
};
}

// Updates the user-given metadata attached to a Worker Deployment Version.
// Experimental. This API might significantly change or be removed in a future release.
rpc UpdateWorkerDeploymentVersionMetadata (UpdateWorkerDeploymentVersionMetadataRequest) returns (UpdateWorkerDeploymentVersionMetadataResponse) {
Expand Down
Loading