2929 TimeOutError ,
3030)
3131from eodag .utils .requests import fetch_json
32+ from stac_fastapi .eodag .config import get_settings
3233
3334if 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+
72140def 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 ))
0 commit comments