Create a custom flow¶
This page explains how to use the rs_client library and how to write, test and deploy your own Prefect flows.
It assumes that you know the basics of Prefect
and that your environment is set up.
Working environment¶
- JupyterHub (recommended to start): the libraries and the environment variables are already set up. Try your
code first in a notebook, then move it to a Python module to make a flow of it. The
rs-demo repository contains tutorials, e.g.
notebooks/tutorials/prefect+dask/prefect.ipynbthat shows the different ways to run and deploy a flow. - Your IDE (e.g. Visual Studio Code): see the coding environment and the local mode, that allows to debug your flows with breakpoints.
Use the rs_client library¶
Initialise the clients¶
import os
from rs_client.rs_client import RsClient
# With your API key (recommended, mandatory for the flows)
rs_client = RsClient(os.environ["RSPY_WEBSITE"], rs_server_api_key=os.environ["RSPY_APIKEY"])
# Or, from a JupyterHub notebook only, with your OAuth2 session cookie read from the RSPY_OAUTH2_COOKIE environment
# variable. It has a short lifespan, so don't use it for long processing.
rs_client = RsClient(os.environ["RSPY_WEBSITE"])
auxip_client = rs_client.get_auxip_client()
cadip_client = rs_client.get_cadip_client()
prip_client = rs_client.get_prip_client()
catalog_client = rs_client.get_catalog_client()
staging_client = rs_client.get_staging_client()
dpr_client = rs_client.get_dpr_client()
osam_client = rs_client.get_osam_client()
Browse the products¶
The STAC clients (AuxipClient, CadipClient, PripClient, CatalogClient, CdseClient, EarthDataHubClient)
share the same methods, based on pystac-client:
collections = list(auxip_client.get_collections())
collection = auxip_client.get_collection("adgs")
queryables = auxip_client.get_queryables()
# Search with a CQL2 filter (JSON or text), a time interval, sorting and paging
items = auxip_client.search(
collections=["adgs"],
stac_filter={"op": "=", "args": [{"property": "product:type"}, "AUX_PP1"]},
timestamp="2026-08-01T00:00:00Z/2026-08-02T00:00:00Z",
sortby="-created",
limit=10,
)
for item in items:
print(item.id, item.properties["start_datetime"], list(item.assets))
The search parameters and the CQL2 filters are described in Browse products.
Manage your catalog collections¶
from datetime import datetime
from pystac import Collection, Extent, SpatialExtent, TemporalExtent
collection = Collection(
id="my-collection",
description="My collection",
extent=Extent(SpatialExtent([[-180, -90, 180, 90]]), TemporalExtent([[datetime(2026, 1, 1), None]])),
)
catalog_client.add_collection(collection) # created as "<your login>:my-collection"
items = list(catalog_client.get_items("my-collection"))
catalog_client.remove_collection("my-collection") # also removes its items
add_item, update_item, patch_item and remove_item manage the items. The assets of an item must be written
in the object storage before the item is added, see Catalog.
Stage products¶
jobs = staging_client.run_staging(items.to_dict(), "my-collection") # one job per station
final_status = staging_client.wait_for_jobs(jobs)
Follow the DPR jobs¶
The processing is usually run by the process-generic flow (see
Customise the DPR processing). With the DprClient, you can follow or cancel the jobs:
jobs = dpr_client.get_jobs()
job = dpr_client.get_job_info("<job id>")
dpr_client.delete_job("<job id>")
Get your object storage credentials¶
credentials = await osam_client.get_credentials()
print(credentials.endpoint, credentials.region, credentials.access_key)
Write a flow¶
A flow is a Python function decorated with @flow. The RS-Python flows take an env parameter and create a
FlowEnv to get an authenticated RsClient instance and OpenTelemetry spans (see
Authentication):
# my_flows.py
from prefect import flow, task
from pystac import ItemCollection
from rs_workflows.flow_utils import FlowEnv, FlowEnvArgs
from rs_workflows.utils.prefect import get_logger
@task(name="count-items")
def count_items(items: ItemCollection) -> int:
return len(items)
@flow(name="search-my-collection")
async def search_my_collection(env: FlowEnvArgs, collection: str) -> int:
"""Search all the items of one of my catalog collections and count them."""
logger = get_logger()
flow_env = FlowEnv(env)
with flow_env.start_span(__name__, "search-my-collection"):
catalog_client = flow_env.rs_client.get_catalog_client()
items = catalog_client.search(collections=[collection], limit=100)
count = count_items(items)
logger.info(f"{count} items found in {collection!r}")
return count
Reuse the existing flows as sub-flows or tasks rather than re-implementing them, e.g. the
search and staging flows or process-generic with call_dpr_flow (see
Customise the DPR processing).
Run and deploy your flow¶
-
Run it directly, as a Python function, from a notebook or a script. The flow and its tasks run in your own environment (your JupyterHub session), and the run is visible in the Prefect dashboard. This is the fastest way to test your code:
-
Deploy it to run it on the cluster, from the dashboard or from automations. Use the
PREFECT_WORK_POOL_SANDBOXwork pool for your own flows. The deployment tells the workers where to get your code, e.g. from a git repository, with a prefect.yaml file:prefect-version: "3" pull: - prefect.deployments.steps.git_clone: repository: https://github.com/<your organisation>/<your repository>.git branch: main deployments: - name: Search My Collection tags: ["searching", "custom"] entrypoint: ./my_flows.py:search_my_collection work_pool: name: "{{ PREFECT_WORK_POOL_SANDBOX }}"While developing, you can also upload your code to an S3 bucket instead of a git repository, so you don't have to push each modification: see the
deploy-yaml-s3.yamlexample of the rs-demo tutorials. -
Share it: push your flow to your own git repository, or propose it to RS-Python with a pull request to rs-client-libraries (see Contributing). The flows of rs-client-libraries are deployed on all the platforms by rs-workflow-deployment.
Follow the naming conventions for your flows, deployments and tags.