Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

task: persist simulation states in the UI #1653

Merged
merged 19 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<div>
<i class="pi pi-spin pi-spinner"></i>
<span>{{ props.status }}...{{ props.value ? '(' + props.value + '%)' : null }}</span>
<ProgressBar v-if="props.value" class="progress-bar" :value="props.value"></ProgressBar>
mwdchang marked this conversation as resolved.
Show resolved Hide resolved
</div>
</template>

<script setup lang="ts">
import { ProgressState } from '@/types/workflow';
import ProgressBar from 'primevue/progressbar';

const props = defineProps<{
status: ProgressState;
value: number;
}>();
</script>
mwdchang marked this conversation as resolved.
Show resolved Hide resolved

<style scoped>
.progress-bar {
width: 100%;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -35,44 +35,47 @@
</section>
</section>
<section v-else>
<div>loading...</div>
<tera-progress-bar :value="progress.value" :status="progress.status"></tera-progress-bar>
</section>
</template>

<script setup lang="ts">
import _ from 'lodash';
import { ref, watch, computed, ComputedRef } from 'vue';
import { ref, watch, computed, ComputedRef, onMounted } from 'vue';
// import { csvParse } from 'd3';
// import { ModelConfiguration } from '@/types/Types';
// import { getRunResult } from '@/services/models/simulation-service';
import { WorkflowNode, WorkflowStatus } from '@/types/workflow';
import {
ProgressState,
SimulationStateOperation,
WorkflowNode,
WorkflowStatus
} from '@/types/workflow';
// import { getModelConfigurationById } from '@/services/model-configurations';
import { workflowEventBus } from '@/services/workflow';
import {
EnsembleCalibrationCiemssRequest,
Simulation,
TimeSpan,
EnsembleModelConfigs
} from '@/types/Types';
import { EnsembleCalibrationCiemssRequest, TimeSpan, EnsembleModelConfigs } from '@/types/Types';
import {
getSimulation,
makeEnsembleCiemssCalibration,
getRunResultCiemss
getRunResultCiemss,
handleSimulationsInProgress
} from '@/services/models/simulation-service';
import Button from 'primevue/button';
import { ChartConfig, RunResults } from '@/types/SimulateConfig';
import { setupDatasetInput } from '@/services/calibrate-workflow';
import { Poller, PollerState } from '@/api/api';
import {
CalibrateEnsembleCiemssOperationState,
CalibrateEnsembleCiemssOperation,
EnsembleCalibrateExtraCiemss
} from './calibrate-ensemble-ciemss-operation';
import TeraSimulateChart from './tera-simulate-chart.vue';
import TeraProgressBar from '../widgets/tera-progress-bar.vue';

const props = defineProps<{
node: WorkflowNode;
}>();
const emit = defineEmits(['append-output-port']);
const emit = defineEmits(['append-output-port', 'update-state']);

const showSpinner = ref(false);
const modelConfigIds = computed<string[]>(() => props.node.inputs[0].value as string[]);
Expand All @@ -93,6 +96,14 @@ const simulationIds: ComputedRef<any | undefined> = computed(
<any | undefined>(() => props.node.outputs[0]?.value)
);
const datasetColumnNames = ref<string[]>();
const progress = ref({ status: ProgressState.QUEUED, value: 0 });

onMounted(() => {
const runIds = handleSimulationsInProgress(SimulationStateOperation.QUERY, props.node);
if (runIds.length > 0) {
getStatus(runIds[0]);
}
});

const runEnsemble = async () => {
if (!datasetId.value || !currentDatasetFileName.value) return;
Expand All @@ -113,30 +124,83 @@ const runEnsemble = async () => {
};
const response = await makeEnsembleCiemssCalibration(params);
startedRunId.value = response.simulationId;
if (response.simulationId) {
getStatus(response.simulationId);
}
};

const getStatus = async (simulationId: string) => {
showSpinner.value = true;
getStatus();
};
if (!simulationId) return;

const poller = new Poller<object>()
.setInterval(3000)
.setThreshold(300)
.setPollAction(async () => {
const response = await getSimulation(simulationId);
if (response?.status === ProgressState.COMPLETE) {
const newState = handleSimulationsInProgress(
SimulationStateOperation.DELETE,
props.node,
simulationId
);
if (newState) {
emit('update-state', newState);
}
return {
data: response,
progress: null,
error: null
};
}
if (response?.status === ProgressState.RUNNING) {
const newState = handleSimulationsInProgress(
SimulationStateOperation.ADD,
props.node,
simulationId
);
if (newState) {
emit('update-state', newState);
}
progress.value = {
status: ProgressState.RUNNING,
value: 0
};
}

const getStatus = async () => {
if (!startedRunId.value) return;
if (response?.status === ProgressState.QUEUED) {
const newState = handleSimulationsInProgress(
SimulationStateOperation.ADD,
props.node,
simulationId
);
if (newState) {
emit('update-state', newState);
}
progress.value = {
status: ProgressState.QUEUED,
value: 0
};
}

const currentSimulation: Simulation | null = await getSimulation(startedRunId.value); // get TDS's simulation object
const ongoingStatusList = ['running', 'queued'];
return {
data: null,
progress: null,
error: null
};
});
const pollerResults = await poller.start();

if (currentSimulation && currentSimulation.status === 'complete') {
completedRunId.value = startedRunId.value;
updateOutputPorts(completedRunId);
addChart();
showSpinner.value = false;
} else if (currentSimulation && ongoingStatusList.includes(currentSimulation.status)) {
// recursively call until all runs retrieved
setTimeout(getStatus, 3000);
} else {
if (pollerResults.state !== PollerState.Done || !pollerResults.data) {
// throw if there are any failed runs for now
console.error('Failed', startedRunId.value);
console.error('Failed', simulationId);
showSpinner.value = false;
throw Error('Failed Runs');
}
completedRunId.value = simulationId;
updateOutputPorts(completedRunId);
addChart();
showSpinner.value = false;
};

const updateOutputPorts = async (runId) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,48 +99,50 @@
/>
</section>
<section v-else>
<div><i class="pi pi-spin pi-spinner"></i> loading...</div>
<tera-progress-bar :value="progress.value" :status="progress.status"></tera-progress-bar>
</section>
</template>

<script setup lang="ts">
import { computed, shallowRef, watch, ref, ComputedRef } from 'vue';
import { WorkflowNode } from '@/types/workflow';
import { computed, shallowRef, watch, ref, ComputedRef, onMounted } from 'vue';
import { ProgressState, SimulationStateOperation, WorkflowNode } from '@/types/workflow';
import DataTable from 'primevue/datatable';
import Button from 'primevue/button';
import Dropdown from 'primevue/dropdown';
import Column from 'primevue/column';
import Accordion from 'primevue/accordion';
import AccordionTab from 'primevue/accordiontab';
import InputNumber from 'primevue/inputnumber';
import { CalibrationRequestCiemss, CsvAsset, Simulation, ModelConfiguration } from '@/types/Types';
import { CalibrationRequestCiemss, CsvAsset, ModelConfiguration } from '@/types/Types';
import {
makeCalibrateJobCiemss,
getSimulation,
getRunResultCiemss
getRunResultCiemss,
handleSimulationsInProgress
} from '@/services/models/simulation-service';
import { setupModelInput, setupDatasetInput } from '@/services/calibrate-workflow';
import { ChartConfig, RunResults } from '@/types/SimulateConfig';
import { workflowEventBus } from '@/services/workflow';
import _ from 'lodash';
import { Poller, PollerState } from '@/api/api';
import {
CalibrationOperationCiemss,
CalibrationOperationStateCiemss,
CalibrateMap
} from './calibrate-operation-ciemss';
import TeraSimulateChart from './tera-simulate-chart.vue';
import TeraProgressBar from '../widgets/tera-progress-bar.vue';

const props = defineProps<{
node: WorkflowNode;
}>();

const emit = defineEmits(['append-output-port']);
const emit = defineEmits(['append-output-port', 'update-state']);

const modelConfigId = computed(() => props.node.inputs[0].value?.[0] as string | undefined);
const datasetId = computed(() => props.node.inputs[1].value?.[0] as string | undefined);
const currentDatasetFileName = ref<string>();
const modelConfig = ref<ModelConfiguration>();
const startedRunId = ref<string>();
const completedRunId = ref<string>();
const parameterResult = ref<{ [index: string]: any }>();

Expand All @@ -154,6 +156,7 @@ const simulationIds: ComputedRef<any | undefined> = computed(
const mapping = ref<CalibrateMap[]>(props.node.state.mapping);
const csvAsset = shallowRef<CsvAsset | undefined>(undefined);
const showSpinner = ref(false);
const progress = ref({ status: ProgressState.QUEUED, value: 0 });

// EXTRA section
const numSamples = ref(100);
Expand All @@ -170,6 +173,13 @@ const disableRunButton = computed(
!datasetId.value
);

onMounted(() => {
const runIds = handleSimulationsInProgress(SimulationStateOperation.QUERY, props.node);
if (runIds.length > 0) {
getStatus(runIds[0]);
}
});

const runCalibrate = async () => {
if (
!modelConfigId.value ||
Expand Down Expand Up @@ -221,31 +231,82 @@ const runCalibrate = async () => {
};
const response = await makeCalibrateJobCiemss(calibrationRequest);

startedRunId.value = response.simulationId;
getStatus();
showSpinner.value = true;
if (response.simulationId) {
getStatus(response.simulationId);
}
};
// Retrieve run ids
// FIXME: Replace with API.poller
const getStatus = async () => {
if (!startedRunId.value) return;

const currentSimulation: Simulation | null = await getSimulation(startedRunId.value); // get TDS's simulation object
const ongoingStatusList = ['running', 'queued'];
const getStatus = async (simulationId: string) => {
showSpinner.value = true;
if (!simulationId) return;

const poller = new Poller<object>()
.setInterval(3000)
.setThreshold(300)
.setPollAction(async () => {
const response = await getSimulation(simulationId);
if (response?.status === ProgressState.COMPLETE) {
const newState = handleSimulationsInProgress(
SimulationStateOperation.DELETE,
props.node,
simulationId
);
if (newState) {
emit('update-state', newState);
}
return {
data: response,
progress: null,
error: null
};
}
if (response?.status === ProgressState.RUNNING) {
const newState = handleSimulationsInProgress(
SimulationStateOperation.ADD,
props.node,
simulationId
);
if (newState) {
emit('update-state', newState);
}
progress.value = {
status: ProgressState.RUNNING,
value: 0
};
}

if (currentSimulation && currentSimulation.status === 'complete') {
completedRunId.value = startedRunId.value;
updateOutputPorts(completedRunId);
showSpinner.value = false;
} else if (currentSimulation && ongoingStatusList.includes(currentSimulation.status)) {
// recursively call until all runs retrieved
setTimeout(getStatus, 3000);
} else {
if (response?.status === ProgressState.QUEUED) {
const newState = handleSimulationsInProgress(
SimulationStateOperation.ADD,
props.node,
simulationId
);
if (newState) {
emit('update-state', newState);
}
progress.value = {
status: ProgressState.QUEUED,
value: 0
};
}

return {
data: null,
progress: null,
error: null
};
});
const pollerResults = await poller.start();

if (pollerResults.state !== PollerState.Done || !pollerResults.data) {
// throw if there are any failed runs for now
console.error('Failed', startedRunId.value);
console.error('Failed', simulationId);
showSpinner.value = false;
throw Error('Failed Runs');
}
completedRunId.value = simulationId;
updateOutputPorts(completedRunId);
showSpinner.value = false;
};

const updateOutputPorts = async (runId) => {
Expand Down
Loading