A function is Python code that you deploy to Chalk and call from anywhere: a script, a notebook, or another function. In this tutorial you will:

  • Deploy a function and call it
  • Call it many times at once
  • Retry calls that fail
  • Delete what you deployed

​
Before you start

You need:

  • A Chalk account and an environment to work in.
  • A role that can deploy and call functions: the deploy.create and deploy.redeploy permissions. If you created your Chalk team yourself, you already have them. Otherwise, ask an admin for a role that includes them. See Permissions.
  • A function queue in that environment. Steps 2 and 3 call functions through it. If your environment does not have one, see Function Queue Setup.

You do not need a Chalk project or chalk init, and you do not deploy anything with chalk apply. Every function in this tutorial is deployed by the tutorial and deleted in the last step.

Set up the Python environment that will run the tutorial:

  • If you followed the Setup Guide, chalk init already installed chalkcompute in your project. Run the tutorial’s files from your project folder with uv run python.

  • Otherwise, install the Chalk CLI, run chalk login, and install chalkcompute in a virtual environment:

    python3 -m venv .venv
    source .venv/bin/activate
    pip install chalkcompute
    

    On Windows, activate the environment with .venv\Scripts\activate instead. Run the tutorial’s files with python, from the folder where you ran chalk login, so that chalkcompute finds your login. See Logins and environments.


​
Step 1: Deploy a function and call it

Save this file as functions_tutorial.py:

import chalkcompute

@chalkcompute.function
def word_count(text: str) -> int:
    return len(text.split())

if __name__ == "__main__":
    print(word_count.remote("Chalk deploys this function and runs it"))

Run it with python functions_tutorial.py. While the function deploys, the script prints its progress, and then the result:

7

Running the file deploys word_count. The first deploy can take a few minutes. Later runs deploy again only if the function has changed. .remote(...) waits until the deployed function is ready, calls it, and returns its result. word_count("..."), without .remote, would run the Python body on your own machine instead.

Chalk imports this file inside the deployed function, and that runs its top-level code. Keep functions at the top level of the file, and put the code that calls them under if __name__ == "__main__":, so that it runs only when you run the file.


​
Step 2: Call it many times at once

Suppose each call does slower work, such as calling a model. To process a list of texts quickly, start every call at once and collect the results afterward.

Replace the contents of functions_tutorial.py with:

import time

import chalkcompute

@chalkcompute.function(concurrency=10)
def word_count(text: str) -> int:
    time.sleep(2)  # Stands in for slower work, such as calling a model.
    return len(text.split())

if __name__ == "__main__":
    texts = [
        "one",
        "one two",
        "one two three",
        "one two three four",
        "one two three four five",
        "one two three four five six",
        "one two three four five six seven",
        "one two three four five six seven eight",
        "one two three four five six seven eight nine",
        "one two three four five six seven eight nine ten",
    ]
    word_count.wait_ready()  # Waits until the new version is deployed and ready.

    start = time.time()
    handles = [word_count.defer(text) for text in texts]
    print(chalkcompute.gather(handles))
    print(f"{time.time() - start:.0f} seconds")

Run it again:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
4 seconds

Your time will differ a little. The changed function deploys as a new version, and wait_ready() waits until that version can take calls, so the timing covers only the calls.

.defer(...) sends a call to the function queue and returns a handle right away, without waiting for the result. chalkcompute.gather(...) waits for all the handles and returns their results in the same order as the calls.

concurrency=10 lets ten calls run at the same time. A function runs one call at a time unless you set concurrency, so without it these ten calls would run one after another, taking 20 seconds or more. See Rate and Concurrency Limits.


​
Step 3: Retry calls that fail

Calls can fail for reasons that go away on their own, such as a network error in a service the function calls. retries runs a failed call again.

To see a retry happen, the function below fails on its first two attempts for each request. It counts the attempts in a file inside the deployed function.

Replace the contents of functions_tutorial.py with:

import time
import uuid

import chalkcompute

@chalkcompute.function(concurrency=10)
def word_count(text: str) -> int:
    time.sleep(2)  # Stands in for slower work, such as calling a model.
    return len(text.split())

@chalkcompute.function(retries=3)
def flaky_word_count(request_id: str, text: str) -> str:
    import os

    path = f"/tmp/attempts-{request_id}"
    attempt = int(open(path).read()) + 1 if os.path.exists(path) else 1
    with open(path, "w") as f:
        f.write(str(attempt))
    if attempt < 3:
        raise ConnectionError(f"Attempt {attempt} failed")
    return f"{len(text.split())} words, on attempt {attempt}"

if __name__ == "__main__":
    flaky_word_count.wait_ready()  # Waits until the new function is deployed and ready.
    handle = flaky_word_count.defer(str(uuid.uuid4()), "This call fails twice before it works")
    print(handle.get())

Run it again. This step takes a minute or two, because flaky_word_count is deployed for the first time and each retry waits before it runs:

7 words, on attempt 3

retries=3 allows up to three more attempts after the first one fails. The first two attempts raised ConnectionError, and the third returned a result.

Retries apply to calls made with .defer(...), which go through the function queue. A call made with .remote(...) raises the first failure to the caller.


​
Step 4: Clean up

A deployed function keeps running until you delete it. Save this file as cleanup.py and run it with python cleanup.py:

import chalkcompute

for name in ["word_count", "flaky_word_count"]:
    chalkcompute.RemoteFunction.from_name(name).delete()

delete() removes each function and all of its versions.


​
Next steps