Skip to main content
@cycls.function is the bottom layer. It takes a Python function, packages it with the dependencies you declare, and runs it wherever you point it.
simulate.py
Three verbs decide where it runs:

How the code gets there

The function is serialized with cloudpickle, bytecode, closures and captured variables included, then executed inside a container built from your Image. The same pickle runs locally and in the cloud, so what you tested is what ships. Two version rules keep that safe, and both are enforced for you:
  • The container’s Python matches your host’s major and minor version.
  • The container’s cloudpickle matches your host’s exact version.
Functions defined in the file you deploy travel by value. Functions imported from another module travel by reference, so the container needs that module. Bundle it with cycls.Image().copy("helpers.py"), and anything copied lands in /app, which is on sys.path.

Running locally

The image is built or reused, the function executes, and the return value comes back. Print statements stream to your terminal while it runs. To look around inside the exact environment the function sees:

The development loop

Trailing --name value arguments bind to the function’s parameters. Annotated parameters convert through their annotation, so n: int gets an int. Unannotated ones are parsed as Python literals, so --data "[1,2]" becomes a list. Anything else stays a string. A save during a run queues the next run instead of killing the current one. For anything with several calls, a fan-out, or a mix of local and remote, mark a driver:
The entrypoint runs on your machine on every save, and the verbs inside it decide where the work happens. Keep driver calls inside it. A top-level simulate.remote(...) fires on every import, including during cycls deploy.

Running in the cloud with current code

remote() ships the live bytecode to an executor, which is a small service provisioned once per image and shared by every function using that image. The first call for a given image takes about ninety seconds while it provisions. After that, a call costs network plus compute. Edit the function, call again, and the new code runs. There is no redeploy step. map() fans one call per item across autoscaled instances and returns results in input order. It raises on the first failure, so return errors as data when you want per-item tolerance:

Deploying

Deploy reads the function’s shape. A function that takes a port parameter is a server and gets its own URL. A bare function becomes a named endpoint, frozen at deploy time and callable from any machine that has your API key:
The difference matters. f.remote() runs your current code, which is what you want while developing. cycls.remote("name") calls what was deployed, which is what a caller without your source needs.

Serving instead of returning

Any function that binds a port is a server:
For a service with auth and per-user storage, use @cycls.app, which is this pattern with the plumbing already done.

Sizing and limits

Keeping state warm

The process lives across calls on an instance, so expensive setup can be paid once per instance using a mutable default:
First call loads the model, every call after is warm. That is a self-hosted embedding API in ten lines.

Method reference

Next

Images

Declare packages, system libraries and bundled files.