Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
]

ScalingMetricName = Literal[
"active_sessions",
"inflight_requests",
"gpu_utilization",
"token_utilization",
Expand All @@ -33,6 +34,7 @@

# Fixed type per metric name (see examples/internal-team-guides/autoscaling.md).
_METRIC_TYPES: dict[ScalingMetricName, MetricType] = {
"active_sessions": "METRIC_TARGET_TYPE_VALUE",
"inflight_requests": "METRIC_TARGET_TYPE_AVERAGE_VALUE",
"gpu_utilization": "METRIC_TARGET_TYPE_UTILIZATION",
"token_utilization": "METRIC_TARGET_TYPE_UTILIZATION",
Expand Down
1 change: 1 addition & 0 deletions src/together/lib/cli/api/beta/endpoints/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ async def deploy(
help=(
"""Autoscaling metric. Must be set with --scaling-target; --scaling-percentile is optional and only applies to latency metrics.

- active_sessions: Active sessions across the deployment.
- inflight_requests: Concurrent in-flight requests per replica.
- gpu_utilization: GPU compute utilization (%).
- token_utilization: KV-cache utilization (%).
Expand Down
41 changes: 41 additions & 0 deletions tests/cli/test_beta_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,47 @@ def test_deploy_onto_existing_endpoint(self, respx_mock: MockRouter, cli_runner:
assert result.exit_code == 0, result.output
assert create_deployment_route.call_count == 1

@pytest.mark.respx(base_url=base_url)
def test_deploy_accepts_active_sessions_scaling_metric(self, respx_mock: MockRouter, cli_runner: CliRunner) -> None:
_mock_model_and_config(respx_mock)
respx_mock.get("/projects/proj/endpoints/ep_1").mock(return_value=httpx.Response(200, json=_endpoint_body()))
create_deployment_route = respx_mock.post("/projects/proj/endpoints/ep_1/deployments").mock(
return_value=httpx.Response(200, json=_deployment_body())
)

result = cli_runner.invoke(
[
"beta",
"endpoints",
"deploy",
"--project",
"proj",
"--endpoint",
"ep_1",
"--model",
"ml_1",
"--config",
"cr_1",
"--deployment-name",
"my-dep",
"--scaling-metric",
"active_sessions",
"--scaling-target",
"25",
"--json",
]
)

assert result.exit_code == 0, result.output
deployment_body = json.loads(cast(Call, create_deployment_route.calls[0]).request.content.decode())
assert deployment_body["autoscaling"]["scalingMetrics"] == [
{
"name": "active_sessions",
"type": "METRIC_TARGET_TYPE_VALUE",
"target": 25.0,
}
]

@pytest.mark.respx(base_url=base_url)
def test_deploy_reuses_endpoint_when_name_already_exists(
self, respx_mock: MockRouter, cli_runner: CliRunner
Expand Down
26 changes: 26 additions & 0 deletions tests/cli/test_beta_endpoints_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,32 @@ def test_update_by_deployment_id(self, respx_mock: MockRouter, cli_runner: CliRu
"autoscaling": {"minReplicas": 1, "maxReplicas": 2},
}

@pytest.mark.respx(base_url=base_url)
def test_update_accepts_active_sessions_scaling_metric(self, respx_mock: MockRouter, cli_runner: CliRunner) -> None:
_mock_endpoint_list(respx_mock)
route = respx_mock.patch("/projects/proj/endpoints/ep_1/deployments/dep_control").mock(
return_value=httpx.Response(200, json=_deployment_body())
)

result = cli_runner.invoke(
_update_args("dep_control", "--scaling-metric", "active_sessions", "--scaling-target", "25")
)

assert result.exit_code == 0, result.output
req = cast(Call, route.calls[0]).request
assert "updateMask=autoscaling" in str(req.url)
assert json.loads(req.content.decode()) == {
"autoscaling": {
"scalingMetrics": [
{
"name": "active_sessions",
"type": "METRIC_TARGET_TYPE_VALUE",
"target": 25.0,
}
]
},
}

@pytest.mark.respx(base_url=base_url)
def test_update_idle_deployment(self, respx_mock: MockRouter, cli_runner: CliRunner) -> None:
_mock_endpoint_list(respx_mock)
Expand Down
10 changes: 10 additions & 0 deletions tests/cli/test_build_autoscaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ def test_build_scaling_metrics_utilization() -> None:
]


def test_build_scaling_metrics_active_sessions() -> None:
assert build_scaling_metrics(scaling_metric="active_sessions", scaling_target=25) == [
{
"name": "active_sessions",
"type": "METRIC_TARGET_TYPE_VALUE",
"target": 25,
}
]


def test_build_scaling_metrics_latency_with_percentile() -> None:
assert build_scaling_metrics(
scaling_metric="ttft",
Expand Down
Loading