Functions and Scaling Groups
Roll a new revision onto a scaling group, list its revisions, and roll back to an earlier one.
Each deploy of a scaling group records an immutable revision of the group’s spec. The group keeps
the same ID, name, and web_url across revisions, and serves one revision at a
time.
Redeploying with the same name from ScalingGroup(...).deploy() or
chalk scaling-group create records a new revision and selects it to serve all
traffic. That is how you roll a new image or spec onto a running group. To record a
new revision from the CLI without serving it, add --no-traffic. The group
keeps serving its current revision until you select the new one.
To roll back, select an earlier revision. Selecting a revision routes all traffic to it and does not record a new revision.
When you select a revision, the group starts a replica of it before it stops a replica of the previous one. The previous revision keeps serving until the new replica is ready, which takes as long as your server takes to start: seconds for a small web app, or several minutes for a server that loads a model onto a GPU. During the rollout the group runs one more replica than usual, so the cluster needs room for it, including one more GPU for a group that requests GPUs. Revision history is also on the scaling group’s Revisions tab in the dashboard.
This example uses the app.py file from the
Quick start, saved in the same directory. It
deploys two revisions of a group, lists them, and rolls back to the first:
import chalkcompute
img = (
chalkcompute.Image.debian_slim("3.12")
.pip_install(["flask"])
.add_local_file("./app.py", "/app/app.py")
.entrypoint(["python", "/app/app.py"])
)
sg = chalkcompute.ScalingGroup(
image=img,
name="hello-api",
port=8080,
env={"APP_VERSION": "1"},
).deploy()
# Deploying again under the same name records a second revision.
sg = chalkcompute.ScalingGroup(
image=img,
name="hello-api",
port=8080,
env={"APP_VERSION": "2"},
).deploy()
revisions = sg.revisions()
for rev in revisions:
print(rev.id, rev.status, rev.is_current)
sg.rollback(revisions[1].id)
print(sg.refresh().current_revision_id)
revisions() returns the group’s revisions, newest first. The serving revision
has is_current set to True, and the others report the Superseded status.
deploy() and rollback(revision_id) return once the group has a ready
replica. During a rollout, that replica can be running the previous revision.
revisions() reports the selected revision as current as soon as you select
it, while the previous revision is still answering requests. Pass
wait_ready=False to rollback() to return without waiting, or timeout to
change the wait from its default of 300 seconds.
To check that the selected revision is serving, call an endpoint whose response
differs between revisions. For example, add a route to app.py, above
app.run(...), that returns the APP_VERSION variable the example sets:
import os
@app.get("/version")
def version():
return {"version": os.environ.get("APP_VERSION")}
After rollback() returns, call the route until it reports the first revision:
import time
while True:
resp = sg.call("/version", method="GET")
if resp.status == 200 and resp.json()["version"] == "1":
break
time.sleep(5)
List a group’s revisions, inspect one, and route traffic to it:
$ chalk scaling-group revisions list --name=hello-api
$ chalk scaling-group revisions get --name=hello-api --revision-id=<revision-id>
$ chalk scaling-group update-traffic --name=hello-api --revision-id=<revision-id>
update-traffic routes all of the group’s traffic to the revision you name.
Use it to roll back, or to start serving a revision you recorded with
--no-traffic. As with the SDK, the previous revision keeps serving until a
replica of the selected revision is ready. Each command also accepts --id in place of --name.