Skip to content

Commit 470d4f8

Browse files
dalpassoCopilot
andcommitted
feat: add provider status info to landing page
Co-authored-by: Copilot <copilot@github.com>
1 parent 5bac245 commit 470d4f8

3 files changed

Lines changed: 84 additions & 1 deletion

File tree

stac_fastapi/eodag/config.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ class Settings(ApiSettings):
7171
alias="validate",
7272
)
7373

74+
provider_online_status_threshold: float = Field(
75+
default=0.8,
76+
description="Threshold for considering a provider as online based"
77+
"on the statuses of the all collections provided",
78+
alias="provider_online_status_threshold",
79+
)
80+
7481

7582
@lru_cache(maxsize=1)
7683
def get_settings() -> Settings:

stac_fastapi/eodag/dag.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@
2929
TimeOutError,
3030
)
3131
from eodag.utils.requests import fetch_json
32+
from stac_fastapi.eodag.config import get_settings
3233

3334
if TYPE_CHECKING:
34-
from typing import Any
35+
from typing import Any, Optional
3536

3637
from fastapi import FastAPI
3738

@@ -69,6 +70,73 @@ def fetch_external_stac_collections(
6970
return ext_stac_collections
7071

7172

73+
def get_providers_status(collections_list: CollectionsList) -> dict[str, dict[str, Any]]:
74+
"""Get the status of all providers based on their collections' status.
75+
76+
:param collections_list: list of EODAG collections
77+
:return: Dictionary of providers' status indexed by provider ID
78+
"""
79+
settings = get_settings()
80+
online_threshold = settings.provider_online_status_threshold
81+
# the key of providers_status is the provider ID
82+
providers_status: dict[str, dict[str, Any]] = {}
83+
84+
def _get_last_check(status_1: dict[str, Any], status_2: dict[str, Any], key: str) -> Optional[str]:
85+
"""Get the most recent check date between two status dictionaries
86+
87+
The comparision handle possible `None` values in the dates.
88+
89+
:param status_1: First status dictionary
90+
:param status_2: Second status dictionary
91+
:param key: Key to check in the status dictionaries (e.g. "last_status_check" or "last_successful_check")
92+
:return: Most recent check date as string, or None if not available in both dictionaries
93+
"""
94+
check_1 = status_1.get(key)
95+
check_2 = status_2.get(key)
96+
if check_1 and check_2:
97+
return max(check_1, check_2)
98+
elif check_1:
99+
return check_1
100+
elif check_2:
101+
return check_2
102+
else:
103+
return None
104+
105+
# count how many online/offline collections for each provider and keep the last check dates
106+
for collection in collections_list:
107+
if not getattr(collection, "federation", None):
108+
continue
109+
for provider_id, status in collection.federation.items():
110+
d = {"online": 0, "offline": 0, "last_status_check": None, "last_successful_check": None}
111+
ps = providers_status.setdefault(provider_id, d)
112+
ps["last_status_check"] = _get_last_check(ps, status, "last_status_check")
113+
ps["last_successful_check"] = _get_last_check(ps, status, "last_successful_check")
114+
if status["status"] == "online":
115+
ps["online"] += 1
116+
else:
117+
ps["offline"] += 1
118+
119+
# determine provider's status based on online/offline collections count and threshold
120+
ret_providers_status = {}
121+
for provider_id, status in providers_status.items():
122+
online = status["online"]
123+
offline = status["offline"]
124+
total = online + offline
125+
if total == 0:
126+
provider_status = "offline"
127+
elif online / total >= online_threshold:
128+
provider_status = "online"
129+
else:
130+
provider_status = "offline"
131+
ret_providers_status[provider_id] = {
132+
"status": provider_status,
133+
"last_status_check": status["last_status_check"],
134+
"last_successful_check": status["last_successful_check"],
135+
}
136+
137+
return ret_providers_status
138+
139+
72140
def init_dag(app: FastAPI) -> None:
73141
"""Init EODataAccessGateway server instance, pre-running all time consuming tasks"""
74142
dag = EODataAccessGateway()
@@ -86,6 +154,9 @@ def init_dag(app: FastAPI) -> None:
86154

87155
dag.db.upsert_collections(CollectionsDict.from_configs(collections))
88156

157+
# store providers status in app state
158+
app.state.providers_status = get_providers_status(dag.list_collections())
159+
89160
# pre-build search plugins
90161
for provider in dag.providers:
91162
next(dag._plugins_manager.get_search_plugins(provider=provider))

stac_fastapi/eodag/models/stac_metadata.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,15 @@ def get_federation_backend_dict(request: Request, provider_name: str) -> dict[st
211211
for p in request.app.state.dag.providers.values()
212212
if provider_name in [p.name, p.metadata.get("group", None)]
213213
)
214+
provider_status = next(
215+
(status for p_id, status in request.app.state.providers_status.items() if provider.name == p_id),
216+
{},
217+
)
214218
return {
215219
"title": provider.metadata.get("group", None) or provider.name,
216220
"description": provider.metadata.get("description", None),
217221
"url": provider.metadata.get("url", None),
222+
**provider_status,
218223
}
219224

220225

0 commit comments

Comments
 (0)