Skip to content

Build your first feature

Almost every feature on PEACH — trending lists, recommendations, related content, search — is the same shape:

[Raw data]    [Task: process + store]    [Storage]    [Endpoint: read + serve]
  • Tasks run on a schedule. They do the heavy lifting: query the raw events, run the algorithm, and write the result somewhere fast to read.
  • Storage — usually Redis, sometimes Milvus for vectors — holds the pre-computed result.
  • Endpoints serve HTTP requests by reading what the task already computed. They stay lightweight, because they run on the critical path of somebody's page load.

The important part is the split. Anything expensive happens on the task's schedule, not in the request. An endpoint that queries raw data itself will be too slow, and will get slower as your traffic grows.

A worked example

The peach-templates repository has this as a complete, runnable feature — Trending Content:

  1. A task runs hourly, queries the last 24 hours of media events, ranks content by how many distinct users engaged with it, and writes the top 10 to Redis.
  2. An endpoint reads that list back and returns it as JSON.

That is the whole pattern, in about a hundred lines. Start there:

Folder What it shows
demo/ the feature built with peach.conf + notebooks
demo_decorators/ the same feature built with @peach.task / @peach.endpoint

The two ways to write it

Both routes are supported, and they produce the same running system.

With peach.conf and notebooks

The logic lives in a library package; the notebooks are thin wrappers that define a task() and an endpoint() function calling into it; YAML files say when the task runs and where the endpoint is served.

peach.conf/
    tasks.yaml          # when the task runs
    endpoints.yaml      # the endpoint's url and components
demo_libs/
    trending.py         # the actual logic
notebooks/
    task_compute_trending.ipynb      # thin wrapper -> demo_libs
    endpoint_get_trending.ipynb      # thin wrapper -> demo_libs

Keeping the notebooks thin is worth the discipline: the logic stays testable, and a change to it produces a readable git diff rather than a re-serialised notebook.

# peach.conf/tasks.yaml
codops: your_codops

py_environments:
  analytics:
    dependencies:
      - duckdb
      - is-bot

tasks:
  compute-trending:
    notebook: notebooks/task_compute_trending.ipynb
    method: task
    py_env: analytics
    cron: "0 * * * *"
# peach.conf/endpoints.yaml
codops: your_codops

endpoints:
  get-trending:
    url: /trending
    py_env: analytics
    components:
      main:
        notebook: notebooks/endpoint_get_trending.ipynb
        method: endpoint

See Tasks and scheduling and Recommendation API for everything these files can express, and Python environments for py_environments.

dependencies: is gone

Older examples — including the ones currently in peach-templates — declare a top-level dependencies: list. That form has been removed and is now rejected by the config schema. Declare dependencies under py_environments and select one with py_env, as above.

With the decorators

The newer route collapses all of that into one plain Python file under a peach/ folder — no YAML, no notebook:

peach/
    codops.txt      # a single line naming your codops
    trending.py     # logic + @peach.task + @peach.endpoint
from pipe_algorithms_lib.compute import peach

def compute_trending(days: int = 1):
    ...            # the logic, same as the library version

@peach.task(py_env="analytics", cron="0 * * * *")
def compute_trending_task():
    compute_trending(days=1)

@peach.endpoint(name="get-trending", route_prefix="/trending", py_env="analytics")
def get_trending_endpoint(amount: int = 10):
    ...

Three things to know before choosing this route:

  • Helpers have to live in the same file. Generation copies the whole source file, and only peach/*.py is scanned — so a function shared by the task and the endpoint sits alongside them rather than in a package they import.
  • A py_env still has to be declared in a peach.conf. The decorators can select an environment but not create one, so anything beyond base needs a peach.conf file somewhere in the same codops declaring it.
  • A scheduled task is called with no arguments, so its inputs come from inside the function or its defaults.

Full detail on both: Decorator tasks and Decorator endpoints.

Getting it running

  1. Write and try the logic in PEACH Lab, where your codops' data and credentials are already available.
  2. Push to your repository's default branch. The CI validates the configuration, builds an image, and deploys the tag to your dev environment — see Going to Production.
  3. Check the task ran in Prefect, and the endpoint answers.
  4. Promote the tag to production from the ops dashboard or /ops in Slack.

Where to go next