Skip to content

Commit

Permalink
Fix [Models] App crash on deploy a model (#2263)
Browse files Browse the repository at this point in the history
  • Loading branch information
mariana-furyk authored Feb 8, 2024
1 parent 17e046d commit aa1f3c9
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 49 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"final-form-arrays": "^3.0.2",
"fs-extra": "^10.0.0",
"identity-obj-proxy": "^3.0.0",
"iguazio.dashboard-react-controls": "1.8.6",
"iguazio.dashboard-react-controls": "1.8.7",
"is-wsl": "^1.1.0",
"js-base64": "^2.5.2",
"js-yaml": "^3.13.1",
Expand Down
36 changes: 30 additions & 6 deletions src/components/ModelsPage/Models/Models.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ such restriction.
*/
import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'
import { connect, useDispatch, useSelector } from 'react-redux'
import { isEmpty } from 'lodash'
import { chain, isEmpty } from 'lodash'
import { useLocation, useNavigate, useParams } from 'react-router-dom'

import AddArtifactTagPopUp from '../../../elements/AddArtifactTagPopUp/AddArtifactTagPopUp'
Expand All @@ -29,6 +29,7 @@ import RegisterModelModal from '../../../elements/RegisterModelModal/RegisterMod
import JobWizard from '../../JobWizard/JobWizard'

import {
fetchArtifactsFunctions,
fetchArtifactTags,
fetchModel,
fetchModels,
Expand All @@ -45,7 +46,8 @@ import {
MODELS_FILTERS,
REQUEST_CANCELED,
MODEL_TYPE,
SHOW_ITERATIONS
SHOW_ITERATIONS,
FUNCTION_TYPE_SERVING
} from '../../../constants'
import {
checkForSelectedModel,
Expand All @@ -54,7 +56,8 @@ import {
generateActionsMenu,
generatePageData,
getFeatureVectorData,
handleApplyDetailsChanges
handleApplyDetailsChanges,
handleDeployModelFailure
} from './models.util'
import detailsActions from '../../../actions/details'
import { createModelsRowData } from '../../../utils/createArtifactsContent'
Expand Down Expand Up @@ -141,9 +144,30 @@ const Models = ({ fetchModelFeatureVector }) => {
[dispatch, setModels, params.projectName]
)

const handleDeployModel = useCallback(model => {
openPopUp(DeployModelPopUp, { model })
}, [])
const handleDeployModel = useCallback(
model => {
dispatch(fetchArtifactsFunctions({ project: model.project, filters: {} }))
.unwrap()
.then(functions => {
const functionOptions = chain(functions)
.filter(func => func.type === FUNCTION_TYPE_SERVING && func.graph?.kind === 'router')
.uniqBy('name')
.map(func => ({ label: func.name, id: func.name }))
.value()

if (functionOptions.length > 0) {
openPopUp(DeployModelPopUp, {
model,
functionList: functions,
functionOptionList: functionOptions
})
} else {
handleDeployModelFailure(params.projectName)
}
})
},
[dispatch, params.projectName]
)

const handleRefresh = useCallback(
filters => {
Expand Down
51 changes: 51 additions & 0 deletions src/components/ModelsPage/Models/models.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ such restriction.
*/
import React from 'react'
import { cloneDeep, isEmpty, omit } from 'lodash'
import Prism from 'prismjs'

import { PopUpDialog } from 'igz-controls/components'

import {
ITERATIONS_FILTER,
Expand Down Expand Up @@ -50,6 +53,7 @@ import { searchArtifactItem } from '../../../utils/searchArtifactItem'
import { setDownloadItem, setShowDownloadsList } from '../../../reducers/downloadReducer'
import { showErrorNotification } from '../../../utils/notifications.util'
import { sortListByDate } from '../../../utils'
import { openPopUp } from 'igz-controls/utils/common.util'

import { ReactComponent as TagIcon } from 'igz-controls/images/tag-icon.svg'
import { ReactComponent as YamlIcon } from 'igz-controls/images/yaml.svg'
Expand Down Expand Up @@ -392,3 +396,50 @@ export const generateActionsMenu = (
]
]
}

export const handleDeployModelFailure = projectName => {
const codeSnippet = `project = mlrun.get_or_create_project(${projectName}, context="./")
serving_function_image = "mlrun/mlrun"
serving_model_class_name = "mlrun.frameworks.sklearn.SklearnModelServer"
# Create a serving function
serving_fn = mlrun.new_function("serving", project=${projectName}, kind="serving", image=serving_function_image)
serving_fn.deploy()`

openPopUp(PopUpDialog, {
children: (
<>
<div>
See how to create a serving function in{' '}
<a
className="link"
href="https://docs.mlrun.org/en/stable/serving/built-in-model-serving.html"
rel="noreferrer"
target="_blank"
>
https://docs.mlrun.org/en/stable/serving/built-in-model-serving.html
</a>{' '}
and{' '}
<a
className="link"
href="https://docs.mlrun.org/en/stable/tutorials/03-model-serving.html"
rel="noreferrer"
target="_blank"
>
https://docs.mlrun.org/en/stable/tutorials/03-model-serving.html
</a>
</div>
<pre>
<code
dangerouslySetInnerHTML={{
__html: Prism.highlight(codeSnippet, Prism.languages.py, 'py')
}}
/>
</pre>
</>
),
className: 'deploy-model-failure-popup',
headerText: 'Failed to deploy model'
})
}
11 changes: 11 additions & 0 deletions src/components/ModelsPage/modelsPage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,14 @@
}
}
}

.deploy-model-failure-popup {
.pop-up-dialog {
width: 900px;

pre {
width: 800px;
overflow-x: scroll;
}
}
}
59 changes: 17 additions & 42 deletions src/elements/DeployModelPopUp/DeployModelPopUp.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,11 @@ import arrayMutators from 'final-form-arrays'
import { OnChange } from 'react-final-form-listeners'
import { useLocation } from 'react-router-dom'

import Loader from '../../common/Loader/Loader'
import { Button, FormInput, FormKeyValueTable, FormSelect, Modal } from 'igz-controls/components'

import { FUNCTION_TYPE_SERVING, MODELS_TAB } from '../../constants'
import { MODELS_TAB } from '../../constants'
import { MODAL_SM, SECONDARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants'
import { buildFunction, fetchArtifactsFunctions } from '../../reducers/artifactsReducer'
import { buildFunction } from '../../reducers/artifactsReducer'
import { generateUri } from '../../utils/resources'
import { getValidationRules } from 'igz-controls/utils/validation.util'
import { setFieldState } from 'igz-controls/utils/form.util'
Expand All @@ -44,18 +43,15 @@ import { ReactComponent as QuestionMarkIcon } from 'igz-controls/images/question

import './deployModelPopUp.scss'

const DeployModelPopUp = ({ isOpen, model, onResolve }) => {
const [functionList, setFunctionList] = useState([])
const [functionOptionList, setFunctionOptionList] = useState([])
const DeployModelPopUp = ({ functionList, functionOptionList, isOpen, model, onResolve }) => {
const [tagOptionList, setTagOptionList] = useState([])
const [initialValues, setInitialValues] = useState({
modelName: '',
className: '',
selectedTag: '',
selectedFunctionName: '',
selectedFunctionName: functionOptionList?.[0].id ?? '',
arguments: []
})
const [showLoader, setShowLoader] = useState(false)
const dispatch = useDispatch()

const formRef = React.useRef(
Expand All @@ -77,29 +73,6 @@ const DeployModelPopUp = ({ isOpen, model, onResolve }) => {
.value()
}, [])

useEffect(() => {
if (functionOptionList.length === 0) {
setShowLoader(true)
dispatch(fetchArtifactsFunctions({ project: model.project, filters: {} }))
.unwrap()
.then(functions => {
const functionOptions = chain(functions)
.filter(func => func.type === FUNCTION_TYPE_SERVING && func.graph?.kind === 'router')
.uniqBy('name')
.map(func => ({ label: func.name, id: func.name }))
.value()

if (functionOptions.length !== 0) {
setFunctionList(functions)
setFunctionOptionList(functionOptions)
setInitialValues(prev => ({ ...prev, selectedFunctionName: functionOptions[0].id }))
}

setShowLoader(false)
})
}
}, [dispatch, functionOptionList.length, initialValues.selectedFunctionName, model.project])

useEffect(() => {
setInitialValues(prev => ({ ...prev, modelName: model?.db_key }))
}, [model])
Expand Down Expand Up @@ -134,8 +107,6 @@ const DeployModelPopUp = ({ isOpen, model, onResolve }) => {

useEffect(() => {
return () => {
setFunctionList([])
setFunctionOptionList([])
setTagOptionList([])
}
}, [])
Expand All @@ -147,13 +118,18 @@ const DeployModelPopUp = ({ isOpen, model, onResolve }) => {
const classArguments = mapValues(keyBy(values.arguments, 'key'), 'value')
const servingFunctionCopy = cloneDeep(servingFunction.ui.originalContent)

servingFunctionCopy.spec.graph.routes[values.modelName] = {
class_args: {
model_path: generateUri(model, MODELS_TAB),
...classArguments
},
class_name: values.className,
kind: 'task'
servingFunctionCopy.spec.graph = {
...servingFunctionCopy.spec.graph,
routes: {
[values.modelName]: {
class_args: {
model_path: generateUri(model, MODELS_TAB),
...classArguments
},
class_name: values.className,
kind: 'task'
}
}
}

return dispatch(buildFunction({ funcData: { function: servingFunctionCopy } }))
Expand Down Expand Up @@ -206,7 +182,6 @@ const DeployModelPopUp = ({ isOpen, model, onResolve }) => {

return (
<>
{showLoader && <Loader />}
<Form
form={formRef.current}
initialValues={initialValues}
Expand All @@ -225,7 +200,7 @@ const DeployModelPopUp = ({ isOpen, model, onResolve }) => {
title="Deploy model"
>
<div className="form">
{functionOptionList.length === 0 && !showLoader && (
{functionOptionList.length === 0 && (
<div className="form-row">
<div className="form-text info-container">
<QuestionMarkIcon />
Expand Down

0 comments on commit aa1f3c9

Please sign in to comment.