Execute the process and monitor the execution
To submit an execution request of a deployed process and monitor it, the OGC API Processes API uses the resource highlighted in the table below:
Resource | Path | Purpose | Part |
---|---|---|---|
Landing page | / |
Top-level resource serving as an entry point. | Part 1 |
Conformance declaration | /conformance |
Information about the functionality supported by the server. | Part 1 |
API Definition | /api |
Metadata about the API itself. | Part 1 |
Process list | /processes |
Lists available processes with identifiers and links to descriptions. | Part 1 |
Process description | /processes/{processID} |
Retrieves detailed information about a specific process. | Part 1 |
Process execution | /processes/{processID}/execution (POST) |
Executes a process, creating a job. | Part 1 |
Deploy Process | /processes (POST) |
Deploys a new process on the server. | Part 2 |
Replace Process | /processes/{processID} (PUT) |
Replaces an existing process with a new version. | Part 2 |
Undeploy Process | /processes/{processID} (DELETE) |
Removes an existing process from the server. | Part 2 |
EO Application Package | /processes/{processID}/package |
Get the EOAP associated with a deployed process. | Part 2 |
Job status info | /jobs/{jobID} |
Retrieves the current status of a job. | Part 1 |
Job results | /jobs/{jobID}/results |
Retrieves the results of a job. | Part 1 |
Job list | /jobs |
Retrieves a list of submitted jobs. | Part 1 |
Job deletion | /jobs/{jobID} (DELETE) |
Cancels and deletes a job. | Part 1 |
import os
from pprint import pprint
import requests
import time
import json
from pystac.item_collection import ItemCollection
from urllib.parse import urljoin, urlparse
from ogc_api_client.api_client import Configuration
from ogc_api_client.api_client_wrapper import ApiClientWrapper
from ogc_api_client.models.status_info import StatusInfo, StatusCode
from typing import Dict, Optional
from fs_s3fs import S3FS
from loguru import logger
import rasterio
namespace = "acme"
ogc_api_endpoint = f"http://zoo-project-dru-service/{namespace}/ogc-api"
Define the input data for the execution:
data = {
"inputs": {
"stac_items": [
"https://planetarycomputer.microsoft.com/api/stac/v1/collections/landsat-c2-l2/items/LC08_L2SP_044032_20231208_02_T1",
"https://planetarycomputer.microsoft.com/api/stac/v1/collections/landsat-c2-l2/items/LC08_L2SP_043033_20231201_02_T1"
],
"aoi": "-121.399,39.834,-120.74,40.472",
"epsg": "EPSG:4326",
"bands": [
"green",
"nir08"
]
}
}
In the cell below, the user will configure the API client settings and initialize a client object using ApiClientWrapper. A request header will also be specified.
configuration = Configuration(
host=ogc_api_endpoint,
)
client = ApiClientWrapper(configuration=configuration)
headers = {
"accept": "*/*",
"Prefer": "respond-async;return=representation",
"Content-Type": "application/json"
}
Submit a water-bodies detection job to the OGC API endpoint and retrieve the job ID for monitoring
process_id = "water-bodies" # Replace with your process ID if different
# Submit the processing request
content = client.execute_simple(process_id=process_id, execute=data, _headers=headers)
pprint(content)
if isinstance(content, StatusInfo):
# Parse the response to get the job ID
job_id = content.job_id
print(f"Job submitted successfully. Job ID: {job_id}")
status_location = next((link.href for link in content.links if link.rel == 'monitor'), None)
if not status_location:
status_location = f"{ogc_api_endpoint}/jobs/{job_id}"
print(f"Monitor job status at: {status_location}")
else:
print(f"Failed to submit job. Status code: {content.status}")
print("Response:", content.text)
raise ValueError(f"Failed to submit job. Status code: {content.status}")
Job submitted successfully. Job ID: 68046976-7dcb-11f0-90ac-2a20aea25780
Monitor job status at: http://zoo-project-dru-service/acme/ogc-api/jobs/68046976-7dcb-11f0-90ac-2a20aea25780
Monitor the Job Status
print(f"\nMonitoring job status (job ID: {job_id})...")
while True:
status = client.get_status(job_id=job_id)
if status:
print(f"Job status: {status.status}")
# Check if the job is completed (either successful or failed)
if status.status in [StatusCode.SUCCESSFUL, StatusCode.FAILED]:
break
else:
print(f"Failed to get job status.")
break
# Wait for a few seconds before checking again
time.sleep(10)
if status and status.status == StatusCode.SUCCESSFUL:
# print(status)
print("\nJob completed successfully. Retrieving results...")
result = client.get_result(job_id=job_id)
print(result)
stac_feature_collection = result.get("stac_catalog").actual_instance.value.oneof_schema_2_validator
print("STAC item collection:", stac_feature_collection)
else:
print("\nJob did not complete successfully.")
Monitoring job status...
Job status: running
Job status: running
Job status: running
Job status: running
Job status: running
Job status: running
Job status: running
Job status: running
Job status: running
Job status: successful
Job completed successfully. Retrieving results...
STAC Catalog URI: {'type': 'FeatureCollection', 'features': [{'type': 'Feature', 'stac_version': '1.0.0', 'id': 'LC08_L2SP_044032_20231208_02_T1', 'properties': {'proj:epsg': 32610, 'proj:geometry': {'type': 'Polygon', 'coordinates': [[[636975.0, 4410555.0], [691605.0, 4410555.0], [691605.0, 4482615.0], [636975.0, 4482615.0], [636975.0, 4410555.0]]]}, 'proj:bbox': [636975.0, 4410555.0, 691605.0, 4482615.0], 'proj:shape': [2402, 1821], 'proj:transform': [30.0, 0.0, 636975.0, 0.0, -30.0, 4482615.0, 0.0, 0.0, 1.0], 'datetime': '2023-12-08T18:45:23.598169Z'}, 'geometry': {'type': 'Polygon', 'coordinates': [[[-121.39922829056682, 39.83396419450036], [-120.76118304700903, 39.82340258564599], [-120.73977187420928, 40.47213091315636], [-121.38391140352763, 40.482936393990066], [-121.39922829056682, 39.83396419450036]]]}, 'links': [{'rel': 'collection', 'href': 's3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/collection.json', 'type': 'application/json', 'title': 'Processing results'}, {'rel': 'root', 'href': 's3://results/68046976-7dcb-11f0-90ac-2a20aea25780/catalog.json', 'type': 'application/json'}, {'rel': 'self', 'href': 's3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/LC08_L2SP_044032_20231208_02_T1/LC08_L2SP_044032_20231208_02_T1.json', 'type': 'application/json'}, {'rel': 'parent', 'href': 's3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/collection.json', 'type': 'application/json', 'title': 'Processing results'}], 'assets': {'data': {'href': 's3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/LC08_L2SP_044032_20231208_02_T1/otsu.tif', 'type': 'image/tiff; application=geotiff', 'raster:bands': [{'data_type': 'uint8', 'scale': 1.0, 'offset': 0.0, 'sampling': 'area', 'nodata': 0.0, 'statistics': {'mean': 1.0, 'minimum': 1, 'maximum': 1, 'stddev': 0.0, 'valid_percent': 60.46467784749034}, 'histogram': {'count': 11, 'min': 0.5, 'max': 1.5, 'buckets': [0, 0, 0, 0, 0, 481086, 0, 0, 0, 0]}}], 'storage:platform': 'eoap', 'storage:requester_pays': False, 'storage:tier': 'Standard', 'storage:region': 'us-east-1', 'storage:endpoint': 'http://eoap-zoo-project-localstack.eoap-zoo-project.svc.cluster.local:4566', 'roles': ['data', 'visual']}}, 'bbox': [-121.39922829056682, 39.82340258564599, -120.73977187420928, 40.482936393990066], 'stac_extensions': ['https://stac-extensions.github.io/projection/v1.1.0/schema.json', 'https://stac-extensions.github.io/raster/v1.1.0/schema.json'], 'collection': '68046976-7dcb-11f0-90ac-2a20aea25780'}, {'type': 'Feature', 'stac_version': '1.0.0', 'id': 'LC08_L2SP_043033_20231201_02_T1', 'properties': {'proj:epsg': 32610, 'proj:geometry': {'type': 'Polygon', 'coordinates': [[[636975.0, 4410555.0], [691605.0, 4410555.0], [691605.0, 4425015.0], [636975.0, 4425015.0], [636975.0, 4410555.0]]]}, 'proj:bbox': [636975.0, 4410555.0, 691605.0, 4425015.0], 'proj:shape': [482, 1821], 'proj:transform': [30.0, 0.0, 636975.0, 0.0, -30.0, 4425015.0, 0.0, 0.0, 1.0], 'datetime': '2023-12-01T18:39:41.392050Z'}, 'geometry': {'type': 'Polygon', 'coordinates': [[[-121.39922829056682, 39.83396419450036], [-120.76118304700903, 39.82340258564599], [-120.75694206934209, 39.95358698004168], [-121.3961944444915, 39.96419715990018], [-121.39922829056682, 39.83396419450036]]]}, 'links': [{'rel': 'collection', 'href': 's3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/collection.json', 'type': 'application/json', 'title': 'Processing results'}, {'rel': 'root', 'href': 's3://results/68046976-7dcb-11f0-90ac-2a20aea25780/catalog.json', 'type': 'application/json'}, {'rel': 'self', 'href': 's3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/LC08_L2SP_043033_20231201_02_T1/LC08_L2SP_043033_20231201_02_T1.json', 'type': 'application/json'}, {'rel': 'parent', 'href': 's3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/collection.json', 'type': 'application/json', 'title': 'Processing results'}], 'assets': {'data': {'href': 's3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/LC08_L2SP_043033_20231201_02_T1/otsu.tif', 'type': 'image/tiff; application=geotiff', 'raster:bands': [{'data_type': 'uint8', 'scale': 1.0, 'offset': 0.0, 'sampling': 'area', 'nodata': 0.0, 'statistics': {'mean': 1.0, 'minimum': 1, 'maximum': 1, 'stddev': 0.0, 'valid_percent': 12.31976677389706}, 'histogram': {'count': 11, 'min': 0.5, 'max': 1.5, 'buckets': [0, 0, 0, 0, 0, 34314, 0, 0, 0, 0]}}], 'storage:platform': 'eoap', 'storage:requester_pays': False, 'storage:tier': 'Standard', 'storage:region': 'us-east-1', 'storage:endpoint': 'http://eoap-zoo-project-localstack.eoap-zoo-project.svc.cluster.local:4566', 'roles': ['data', 'visual']}}, 'bbox': [-121.39922829056682, 39.82340258564599, -120.75694206934209, 39.96419715990018], 'stac_extensions': ['https://stac-extensions.github.io/projection/v1.1.0/schema.json', 'https://stac-extensions.github.io/raster/v1.1.0/schema.json'], 'collection': '68046976-7dcb-11f0-90ac-2a20aea25780'}], 'id': '68046976-7dcb-11f0-90ac-2a20aea25780'}
Creating ItemCollection
stac_items = ItemCollection.from_dict(stac_feature_collection).items
Exploit the results
for item in stac_items:
print(item.get_assets()["data"].href)
print(json.dumps(item.get_assets()["data"].to_dict(), sort_keys=True, indent=4))
s3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/LC08_L2SP_044032_20231208_02_T1/otsu.tif
{
"href": "s3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/LC08_L2SP_044032_20231208_02_T1/otsu.tif",
"raster:bands": [
{
"data_type": "uint8",
"histogram": {
"buckets": [
0,
0,
0,
0,
0,
481086,
0,
0,
0,
0
],
"count": 11,
"max": 1.5,
"min": 0.5
},
"nodata": 0.0,
"offset": 0.0,
"sampling": "area",
"scale": 1.0,
"statistics": {
"maximum": 1,
"mean": 1.0,
"minimum": 1,
"stddev": 0.0,
"valid_percent": 60.46467784749034
}
}
],
"roles": [
"data",
"visual"
],
"storage:endpoint": "http://eoap-zoo-project-localstack.eoap-zoo-project.svc.cluster.local:4566",
"storage:platform": "eoap",
"storage:region": "us-east-1",
"storage:requester_pays": false,
"storage:tier": "Standard",
"type": "image/tiff; application=geotiff"
}
s3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/LC08_L2SP_043033_20231201_02_T1/otsu.tif
{
"href": "s3://results/68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/LC08_L2SP_043033_20231201_02_T1/otsu.tif",
"raster:bands": [
{
"data_type": "uint8",
"histogram": {
"buckets": [
0,
0,
0,
0,
0,
34314,
0,
0,
0,
0
],
"count": 11,
"max": 1.5,
"min": 0.5
},
"nodata": 0.0,
"offset": 0.0,
"sampling": "area",
"scale": 1.0,
"statistics": {
"maximum": 1,
"mean": 1.0,
"minimum": 1,
"stddev": 0.0,
"valid_percent": 12.31976677389706
}
}
],
"roles": [
"data",
"visual"
],
"storage:endpoint": "http://eoap-zoo-project-localstack.eoap-zoo-project.svc.cluster.local:4566",
"storage:platform": "eoap",
"storage:region": "us-east-1",
"storage:requester_pays": false,
"storage:tier": "Standard",
"type": "image/tiff; application=geotiff"
}
In the cell below, the user opens a GeoTIFF file produced by the water-bodies
job using rasterio
region_name = os.environ.get("AWS_DEFAULT_REGION")
endpoint_url = os.environ.get("AWS_ENDPOINT_URL", "http://eoap-zoo-project-localstack:4566")
aws_access_key_id = os.environ.get("AWS_ACCESS_KEY_ID")
aws_secret_access_key = os.environ.get("AWS_SECRET_ACCESS_KEY")
region_name, endpoint_url, aws_access_key_id, aws_secret_access_key
# Extract image name using os.path.basename
full_path = item.get_assets()["data"].href
parsed_url = urlparse(full_path)
# Extract the bucket name from the "netloc" part
bucket_name = parsed_url.netloc
# Extract the full path (excluding 's3://bucket_name')
full_path = parsed_url.path.lstrip("/")
# Extract image name using os.path.basename
image_name = os.path.basename(full_path)
# Extract directory path using os.path.dirname
dir_path = os.path.dirname(full_path)
fs_opener = S3FS(
bucket_name="results",
dir_path=dir_path,
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
endpoint_url=endpoint_url,
region=region_name,
)
if fs_opener.region:
pass
else:
logger.error(
"File system opener is not configurated properly to open file from s3 bucket"
)
with rasterio.open(image_name, opener=fs_opener.open) as src:
profile = src.profile
print(profile)
68046976-7dcb-11f0-90ac-2a20aea25780/68046976-7dcb-11f0-90ac-2a20aea25780/LC08_L2SP_044032_20231208_02_T1/otsu.tif
{'driver': 'GTiff', 'dtype': 'uint8', 'nodata': 0.0, 'width': 1821, 'height': 2402, 'count': 1, 'crs': CRS.from_wkt('PROJCS["WGS 84 / UTM zone 10N",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-123],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","32610"]]'), 'transform': Affine(30.0, 0.0, 636975.0,
0.0, -30.0, 4482615.0), 'blockxsize': 512, 'blockysize': 512, 'tiled': True, 'compress': 'lzw', 'interleave': 'band'}
Inspecting the job result using cli
!aws s3 ls s3://results/{job_id}/{job_id}/{os.path.basename(data["inputs"]["stac_items"][0])}/
2025-08-20 13:42:57 3447 LC08_L2SP_044032_20231208_02_T1.json
2025-08-20 13:42:57 406547 otsu.tif