Skip to content

Commit fc7b39e

Browse files
committed
implement function job status endpoint
1 parent 50695b3 commit fc7b39e

File tree

6 files changed

+80
-15
lines changed

6 files changed

+80
-15
lines changed

packages/models-library/src/models_library/functions_errors.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,3 @@ class FunctionJobCollectionsExecuteApiAccessDeniedError(FunctionBaseError):
163163
class FunctionJobPatchModelIncompatibleError(FunctionBaseError):
164164
msg_template = "Incompatible patch model for Function '{function_id}' in product '{product_name}'."
165165
status_code: int = 422
166-
167-
168-
class FunctionJobCacheNotFoundError(FunctionBaseError):
169-
msg_template: str = "No cached function job found."
170-
status_code: int = 404 # Not Found

services/api-server/src/simcore_service_api_server/_service_function_jobs.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
from models_library.functions_errors import (
2727
FunctionExecuteAccessDeniedError,
2828
FunctionInputsValidationError,
29-
FunctionJobCacheNotFoundError,
3029
FunctionsExecuteApiAccessDeniedError,
3130
UnsupportedFunctionClassError,
3231
UnsupportedFunctionFunctionJobClassCombinationError,
@@ -41,6 +40,10 @@
4140
from pydantic import ValidationError
4241

4342
from ._service_jobs import JobService
43+
from .exceptions.function_errors import (
44+
FunctionJobCacheNotFoundError,
45+
FunctionJobProjectMissingError,
46+
)
4447
from .models.api_resources import JobLinks
4548
from .models.domain.functions import PreRegisteredFunctionJobData
4649
from .models.schemas.jobs import (
@@ -127,7 +130,7 @@ async def validate_function_inputs(
127130
async def inspect_function_job(
128131
self, function: RegisteredFunction, function_job: RegisteredFunctionJob
129132
) -> FunctionJobStatus:
130-
133+
"""Raises FunctionJobProjectNotRegisteredError if no project is associated with job"""
131134
stored_job_status = await self._web_rpc_client.get_function_job_status(
132135
function_job_id=function_job.uid,
133136
user_id=self.user_id,
@@ -141,14 +144,16 @@ async def inspect_function_job(
141144
function.function_class == FunctionClass.PROJECT
142145
and function_job.function_class == FunctionClass.PROJECT
143146
):
144-
assert function_job.project_job_id is not None # nosec
147+
if function_job.project_job_id is None:
148+
raise FunctionJobProjectMissingError()
145149
job_status = await self._job_service.inspect_study_job(
146150
job_id=function_job.project_job_id,
147151
)
148152
elif (function.function_class == FunctionClass.SOLVER) and (
149153
function_job.function_class == FunctionClass.SOLVER
150154
):
151-
assert function_job.solver_job_id is not None # nosec
155+
if function_job.solver_job_id is None:
156+
raise FunctionJobProjectMissingError()
152157
job_status = await self._job_service.inspect_solver_job(
153158
solver_key=function.solver_key,
154159
version=function.solver_version,

services/api-server/src/simcore_service_api_server/api/dependencies/celery.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from celery_library.task_manager import CeleryTaskManager
55
from celery_library.types import register_celery_types, register_pydantic_types
66
from fastapi import FastAPI
7-
from servicelib.celery.task_manager import TaskManager
87
from settings_library.celery import CelerySettings
98

109
from ...celery.worker_tasks.tasks import pydantic_types_to_register
@@ -24,7 +23,7 @@ async def on_startup() -> None:
2423
app.add_event_handler("startup", on_startup)
2524

2625

27-
def get_task_manager(app: FastAPI) -> TaskManager:
26+
def get_task_manager(app: FastAPI) -> CeleryTaskManager:
2827
assert hasattr(app.state, "task_manager") # nosec
2928
task_manager = app.state.task_manager
3029
assert isinstance(task_manager, CeleryTaskManager) # nosec

services/api-server/src/simcore_service_api_server/api/routes/function_jobs_routes.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from logging import getLogger
12
from typing import Annotated, Final
23

4+
from common_library.error_codes import create_error_code
35
from fastapi import APIRouter, Depends, FastAPI, HTTPException, status
46
from fastapi_pagination.api import create_page
57
from fastapi_pagination.bases import AbstractPage
@@ -15,23 +17,28 @@
1517
from models_library.functions import RegisteredFunction
1618
from models_library.functions_errors import (
1719
UnsupportedFunctionClassError,
20+
UnsupportedFunctionFunctionJobClassCombinationError,
1821
)
1922
from models_library.products import ProductName
2023
from models_library.users import UserID
24+
from servicelib.celery.models import TaskUUID
2125
from servicelib.fastapi.dependencies import get_app
26+
from servicelib.logging_errors import create_troubleshootting_log_kwargs
2227
from simcore_service_api_server.models.schemas.functions_filters import (
2328
FunctionJobsListFilters,
2429
)
2530
from sqlalchemy.ext.asyncio import AsyncEngine
2631

2732
from ..._service_function_jobs import FunctionJobService
2833
from ..._service_jobs import JobService
34+
from ...exceptions.function_errors import FunctionJobProjectMissingError
2935
from ...models.pagination import Page, PaginationParams
3036
from ...models.schemas.errors import ErrorGet
3137
from ...services_http.storage import StorageApi
3238
from ...services_http.webserver import AuthSession
3339
from ...services_rpc.wb_api_server import WbApiRpcClient
3440
from ..dependencies.authentication import get_current_user_id, get_product_name
41+
from ..dependencies.celery import get_task_manager
3542
from ..dependencies.database import get_db_asyncpg_engine
3643
from ..dependencies.functions import (
3744
get_function_from_functionjob,
@@ -52,6 +59,9 @@
5259
FMSG_CHANGELOG_NEW_IN_VERSION,
5360
create_route_description,
5461
)
62+
from .tasks import _get_task_filter
63+
64+
_logger = getLogger(__name__)
5565

5666
# pylint: disable=too-many-arguments
5767
# pylint: disable=cyclic-import
@@ -196,6 +206,9 @@ async def delete_function_job(
196206
),
197207
)
198208
async def function_job_status(
209+
app: Annotated[FastAPI, Depends(get_app)],
210+
user_id: Annotated[UserID, Depends(get_current_user_id)],
211+
product_name: Annotated[ProductName, Depends(get_product_name)],
199212
function_job: Annotated[
200213
RegisteredFunctionJob, Depends(get_function_job_dependency)
201214
],
@@ -204,10 +217,46 @@ async def function_job_status(
204217
FunctionJobService, Depends(get_function_job_service)
205218
],
206219
) -> FunctionJobStatus:
220+
try:
221+
return await function_job_service.inspect_function_job(
222+
function=function, function_job=function_job
223+
)
224+
except FunctionJobProjectMissingError as exc:
225+
if (
226+
function.function_class == FunctionClass.PROJECT
227+
and function_job.function_class == FunctionClass.PROJECT
228+
) or (
229+
function.function_class == FunctionClass.SOLVER
230+
and function_job.function_class == FunctionClass.SOLVER
231+
):
232+
if task_id := function_job.job_creation_task_id:
233+
task_manager = get_task_manager(app)
234+
task_filter = _get_task_filter(user_id, product_name)
235+
task_status = await task_manager.get_task_status(
236+
task_uuid=TaskUUID(task_id), task_filter=task_filter
237+
)
238+
return FunctionJobStatus(
239+
status=f"JOB_CREATION_TASK_STATUS_{task_status.task_state}"
240+
)
241+
user_error_msg = f"The creation of job {function_job.uid} failed"
242+
support_id = create_error_code(Exception())
243+
_logger.exception(
244+
**create_troubleshootting_log_kwargs(
245+
user_error_msg,
246+
error=Exception(),
247+
error_code=support_id,
248+
tip="Initial call to run metamodeling function must have failed",
249+
)
250+
)
251+
raise HTTPException(
252+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
253+
detail="Function job is not in a valid state",
254+
) from exc
207255

208-
return await function_job_service.inspect_function_job(
209-
function=function, function_job=function_job
210-
)
256+
raise UnsupportedFunctionFunctionJobClassCombinationError(
257+
function_class=function.function_class,
258+
function_job_class=function_job.function_class,
259+
)
211260

212261

213262
async def get_function_from_functionjobid(

services/api-server/src/simcore_service_api_server/api/routes/functions_routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
RegisteredFunctionJobCollection,
1818
)
1919
from models_library.api_schemas_rpc_async_jobs.async_jobs import AsyncJobFilter
20-
from models_library.functions_errors import FunctionJobCacheNotFoundError
2120
from models_library.products import ProductName
2221
from models_library.projects import ProjectID
2322
from models_library.projects_nodes_io import NodeID
@@ -28,6 +27,7 @@
2827
from ..._service_function_jobs import FunctionJobService
2928
from ..._service_functions import FunctionService
3029
from ...celery.worker_tasks.functions_tasks import run_function as run_function_task
30+
from ...exceptions.function_errors import FunctionJobCacheNotFoundError
3131
from ...models.pagination import Page, PaginationParams
3232
from ...models.schemas.errors import ErrorGet
3333
from ...models.schemas.jobs import JobPricingSpecification
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from fastapi import status
2+
3+
from .backend_errors import BaseBackEndError
4+
5+
6+
class BaseFunctionBackendError(BaseBackEndError):
7+
pass
8+
9+
10+
class FunctionJobCacheNotFoundError(BaseBackEndError):
11+
msg_template: str = "No cached function job found."
12+
status_code: int = 404 # Not Found
13+
14+
15+
class FunctionJobProjectMissingError(BaseBackEndError):
16+
msg_template: str = "Could not process function job"
17+
status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR # Not Found

0 commit comments

Comments
 (0)