Skip to content

Commit db8669c

Browse files
ElayAharoniHumairAKElay Aharoni (EXT-Nokia)gregsheremeta
authored
feat(frontend/backend): Allow the ability to sort experiments by last run creation. Fixes #10884 (#11163)
* UPSTREAM: <carry>: add last_run_creation Signed-off-by: Humair Khan <[email protected]> * Allow-the-ability-to-sort-Experiments-by-last-run-creation-#10884 Signed-off-by: Elay Aharoni (EXT-Nokia) <[email protected]> * UPSTREAM: <carry>: chore(backend): Rename UpdateLastRun -> SetLastRunTimestamp follup up to bf77909. Rename UpdateLastRun -> SetLastRunTimestamp also tweak a related log message Signed-off-by: Greg Sheremeta <[email protected]> * UPSTREAM: <carry>: chore(backend): Rename UpdateLastRun -> SetLastRunTimestamp follup up to bf77909. Rename UpdateLastRun -> SetLastRunTimestamp also tweak a related log message Signed-off-by: Greg Sheremeta <[email protected]> --------- Signed-off-by: Humair Khan <[email protected]> Signed-off-by: Elay Aharoni (EXT-Nokia) <[email protected]> Signed-off-by: Greg Sheremeta <[email protected]> Co-authored-by: Humair Khan <[email protected]> Co-authored-by: Elay Aharoni (EXT-Nokia) <[email protected]> Co-authored-by: Greg Sheremeta <[email protected]>
1 parent 3f49522 commit db8669c

15 files changed

+496
-297
lines changed

backend/api/v2beta1/experiment.proto

+3
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ message Experiment {
104104

105105
// Output. Specifies whether this experiment is in archived or available state.
106106
StorageState storage_state = 6;
107+
108+
// Output. The creation time of the last run in this experiment.
109+
google.protobuf.Timestamp last_run_created_at = 7;
107110
}
108111

109112
message CreateExperimentRequest {

backend/api/v2beta1/go_client/experiment.pb.go

+167-156
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/api/v2beta1/go_http_client/experiment_model/v2beta1_experiment.go

+21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/api/v2beta1/swagger/experiment.swagger.json

+5
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,11 @@
299299
"storage_state": {
300300
"$ref": "#/definitions/v2beta1ExperimentStorageState",
301301
"description": "Output. Specifies whether this experiment is in archived or available state."
302+
},
303+
"last_run_created_at": {
304+
"type": "string",
305+
"format": "date-time",
306+
"description": "Output. The time the created time of the last run in this experiment."
302307
}
303308
}
304309
},

backend/api/v2beta1/swagger/kfp_api_single_file.swagger.json

+5
Original file line numberDiff line numberDiff line change
@@ -1613,6 +1613,11 @@
16131613
"storage_state": {
16141614
"$ref": "#/definitions/v2beta1ExperimentStorageState",
16151615
"description": "Output. Specifies whether this experiment is in archived or available state."
1616+
},
1617+
"last_run_created_at": {
1618+
"type": "string",
1619+
"format": "date-time",
1620+
"description": "Output. The time the created time of the last run in this experiment."
16161621
}
16171622
}
16181623
},

backend/src/apiserver/model/experiment.go

+18-14
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
package model
1616

1717
type Experiment struct {
18-
UUID string `gorm:"column:UUID; not null; primary_key;"`
19-
Name string `gorm:"column:Name; not null; unique_index:idx_name_namespace;"`
20-
Description string `gorm:"column:Description; not null;"`
21-
CreatedAtInSec int64 `gorm:"column:CreatedAtInSec; not null;"`
22-
Namespace string `gorm:"column:Namespace; not null; unique_index:idx_name_namespace;"`
23-
StorageState StorageState `gorm:"column:StorageState; not null;"`
18+
UUID string `gorm:"column:UUID; not null; primary_key;"`
19+
Name string `gorm:"column:Name; not null; unique_index:idx_name_namespace;"`
20+
Description string `gorm:"column:Description; not null;"`
21+
CreatedAtInSec int64 `gorm:"column:CreatedAtInSec; not null;"`
22+
LastRunCreatedAtInSec int64 `gorm:"column:LastRunCreatedAtInSec; not null;"`
23+
Namespace string `gorm:"column:Namespace; not null; unique_index:idx_name_namespace;"`
24+
StorageState StorageState `gorm:"column:StorageState; not null;"`
2425
}
2526

2627
// Note: Experiment.StorageState can have values: "STORAGE_STATE_UNSPECIFIED", "AVAILABLE" or "ARCHIVED"
@@ -44,14 +45,15 @@ func (e *Experiment) DefaultSortField() string {
4445
}
4546

4647
var experimentAPIToModelFieldMap = map[string]string{
47-
"id": "UUID", // v1beta1 API
48-
"experiment_id": "UUID", // v2beta1 API
49-
"name": "Name", // v1beta1 API
50-
"display_name": "Name", // v2beta1 API
51-
"created_at": "CreatedAtInSec",
52-
"description": "Description",
53-
"namespace": "Namespace", // v2beta1 API
54-
"storage_state": "StorageState",
48+
"id": "UUID", // v1beta1 API
49+
"experiment_id": "UUID", // v2beta1 API
50+
"name": "Name", // v1beta1 API
51+
"display_name": "Name", // v2beta1 API
52+
"created_at": "CreatedAtInSec",
53+
"last_run_created_at": "LastRunCreatedAtInSec", // v2beta1 API
54+
"description": "Description",
55+
"namespace": "Namespace", // v2beta1 API
56+
"storage_state": "StorageState",
5557
}
5658

5759
// APIToModelFieldMap returns a map from API names to field names for model
@@ -80,6 +82,8 @@ func (e *Experiment) GetFieldValue(name string) interface{} {
8082
return e.Name
8183
case "CreatedAtInSec":
8284
return e.CreatedAtInSec
85+
case "LastRunCreatedAtInSec":
86+
return e.LastRunCreatedAtInSec
8387
case "Description":
8488
return e.Description
8589
case "Namespace":

backend/src/apiserver/resource/resource_manager.go

+11
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,13 @@ func (r *ResourceManager) CreateRun(ctx context.Context, run *model.Run) (*model
564564
if err != nil {
565565
return nil, util.Wrap(err, "Failed to create a run")
566566
}
567+
568+
// Upon run creation, update owning experiment
569+
err = r.experimentStore.SetLastRunTimestamp(newRun)
570+
if err != nil {
571+
return nil, util.Wrap(err, fmt.Sprintf("Failed to set last run timestamp on experiment %s for run %s", newRun.ExperimentId, newRun.UUID))
572+
}
573+
567574
return newRun, nil
568575
}
569576

@@ -1245,6 +1252,10 @@ func (r *ResourceManager) ReportWorkflowResource(ctx context.Context, execSpec u
12451252
} else {
12461253
runId = run.UUID
12471254
}
1255+
// Upon run creation, update owning experiment
1256+
if updateError = r.experimentStore.SetLastRunTimestamp(run); updateError != nil {
1257+
return nil, util.Wrapf(updateError, "Failed to report a workflow for existing run %s during updating the owning experiment.", runId)
1258+
}
12481259
}
12491260
if execStatus.IsInFinalState() {
12501261
err := addWorkflowLabel(ctx, r.getWorkflowClient(execSpec.ExecutionNamespace()), execSpec.ExecutionName(), util.LabelKeyWorkflowPersistedFinalState, "true")

backend/src/apiserver/server/api_converter.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,13 @@ func toApiExperiment(experiment *model.Experiment) *apiv2beta1.Experiment {
113113
storageState = apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["STORAGE_STATE_UNSPECIFIED"])
114114
}
115115
return &apiv2beta1.Experiment{
116-
ExperimentId: experiment.UUID,
117-
DisplayName: experiment.Name,
118-
Description: experiment.Description,
119-
CreatedAt: &timestamp.Timestamp{Seconds: experiment.CreatedAtInSec},
120-
Namespace: experiment.Namespace,
121-
StorageState: storageState,
116+
ExperimentId: experiment.UUID,
117+
DisplayName: experiment.Name,
118+
Description: experiment.Description,
119+
CreatedAt: &timestamp.Timestamp{Seconds: experiment.CreatedAtInSec},
120+
LastRunCreatedAt: &timestamp.Timestamp{Seconds: experiment.LastRunCreatedAtInSec},
121+
Namespace: experiment.Namespace,
122+
StorageState: storageState,
122123
}
123124
}
124125

backend/src/apiserver/server/api_converter_test.go

+60-50
Original file line numberDiff line numberDiff line change
@@ -1974,77 +1974,87 @@ func TestToApiExperimentsV1(t *testing.T) {
19741974

19751975
func TestToApiExperiments(t *testing.T) {
19761976
exp1 := &model.Experiment{
1977-
UUID: "exp1",
1978-
CreatedAtInSec: 1,
1979-
Name: "experiment1",
1980-
Description: "My name is experiment1",
1981-
StorageState: "AVAILABLE",
1977+
UUID: "exp1",
1978+
CreatedAtInSec: 1,
1979+
LastRunCreatedAtInSec: 1,
1980+
Name: "experiment1",
1981+
Description: "My name is experiment1",
1982+
StorageState: "AVAILABLE",
19821983
}
19831984
exp2 := &model.Experiment{
1984-
UUID: "exp2",
1985-
CreatedAtInSec: 2,
1986-
Name: "experiment2",
1987-
Description: "My name is experiment2",
1988-
StorageState: "ARCHIVED",
1985+
UUID: "exp2",
1986+
CreatedAtInSec: 2,
1987+
LastRunCreatedAtInSec: 2,
1988+
Name: "experiment2",
1989+
Description: "My name is experiment2",
1990+
StorageState: "ARCHIVED",
19891991
}
19901992
exp3 := &model.Experiment{
1991-
UUID: "exp3",
1992-
CreatedAtInSec: 1,
1993-
Name: "experiment3",
1994-
Description: "experiment3 was created using V1 APIV1BETA1",
1995-
StorageState: "STORAGESTATE_AVAILABLE",
1993+
UUID: "exp3",
1994+
CreatedAtInSec: 1,
1995+
LastRunCreatedAtInSec: 1,
1996+
Name: "experiment3",
1997+
Description: "experiment3 was created using V1 APIV1BETA1",
1998+
StorageState: "STORAGESTATE_AVAILABLE",
19961999
}
19972000
exp4 := &model.Experiment{
1998-
UUID: "exp4",
1999-
CreatedAtInSec: 2,
2000-
Name: "experiment4",
2001-
Description: "experiment4 was created using V1 APIV1BETA1",
2002-
StorageState: "STORAGESTATE_ARCHIVED",
2001+
UUID: "exp4",
2002+
CreatedAtInSec: 2,
2003+
LastRunCreatedAtInSec: 2,
2004+
Name: "experiment4",
2005+
Description: "experiment4 was created using V1 APIV1BETA1",
2006+
StorageState: "STORAGESTATE_ARCHIVED",
20032007
}
20042008
exp5 := &model.Experiment{
2005-
UUID: "exp5",
2006-
CreatedAtInSec: 1,
2007-
Name: "experiment5",
2008-
Description: "My name is experiment5",
2009-
StorageState: "this is invalid storage state",
2009+
UUID: "exp5",
2010+
CreatedAtInSec: 1,
2011+
LastRunCreatedAtInSec: 1,
2012+
Name: "experiment5",
2013+
Description: "My name is experiment5",
2014+
StorageState: "this is invalid storage state",
20102015
}
20112016
apiExps := toApiExperiments([]*model.Experiment{exp1, exp2, exp3, exp4, nil, exp5})
20122017
expectedApiExps := []*apiv2beta1.Experiment{
20132018
{
2014-
ExperimentId: "exp1",
2015-
DisplayName: "experiment1",
2016-
Description: "My name is experiment1",
2017-
CreatedAt: &timestamp.Timestamp{Seconds: 1},
2018-
StorageState: apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["AVAILABLE"]),
2019+
ExperimentId: "exp1",
2020+
DisplayName: "experiment1",
2021+
Description: "My name is experiment1",
2022+
CreatedAt: &timestamp.Timestamp{Seconds: 1},
2023+
LastRunCreatedAt: &timestamp.Timestamp{Seconds: 1},
2024+
StorageState: apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["AVAILABLE"]),
20192025
},
20202026
{
2021-
ExperimentId: "exp2",
2022-
DisplayName: "experiment2",
2023-
Description: "My name is experiment2",
2024-
CreatedAt: &timestamp.Timestamp{Seconds: 2},
2025-
StorageState: apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["ARCHIVED"]),
2027+
ExperimentId: "exp2",
2028+
DisplayName: "experiment2",
2029+
Description: "My name is experiment2",
2030+
CreatedAt: &timestamp.Timestamp{Seconds: 2},
2031+
LastRunCreatedAt: &timestamp.Timestamp{Seconds: 2},
2032+
StorageState: apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["ARCHIVED"]),
20262033
},
20272034
{
2028-
ExperimentId: "exp3",
2029-
DisplayName: "experiment3",
2030-
Description: "experiment3 was created using V1 APIV1BETA1",
2031-
CreatedAt: &timestamp.Timestamp{Seconds: 1},
2032-
StorageState: apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["AVAILABLE"]),
2035+
ExperimentId: "exp3",
2036+
DisplayName: "experiment3",
2037+
Description: "experiment3 was created using V1 APIV1BETA1",
2038+
CreatedAt: &timestamp.Timestamp{Seconds: 1},
2039+
LastRunCreatedAt: &timestamp.Timestamp{Seconds: 1},
2040+
StorageState: apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["AVAILABLE"]),
20332041
},
20342042
{
2035-
ExperimentId: "exp4",
2036-
DisplayName: "experiment4",
2037-
Description: "experiment4 was created using V1 APIV1BETA1",
2038-
CreatedAt: &timestamp.Timestamp{Seconds: 2},
2039-
StorageState: apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["ARCHIVED"]),
2043+
ExperimentId: "exp4",
2044+
DisplayName: "experiment4",
2045+
Description: "experiment4 was created using V1 APIV1BETA1",
2046+
CreatedAt: &timestamp.Timestamp{Seconds: 2},
2047+
LastRunCreatedAt: &timestamp.Timestamp{Seconds: 2},
2048+
StorageState: apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["ARCHIVED"]),
20402049
},
20412050
{},
20422051
{
2043-
ExperimentId: "exp5",
2044-
DisplayName: "experiment5",
2045-
Description: "My name is experiment5",
2046-
CreatedAt: &timestamp.Timestamp{Seconds: 1},
2047-
StorageState: apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["STORAGE_STATE_UNSPECIFIED"]),
2052+
ExperimentId: "exp5",
2053+
DisplayName: "experiment5",
2054+
Description: "My name is experiment5",
2055+
CreatedAt: &timestamp.Timestamp{Seconds: 1},
2056+
LastRunCreatedAt: &timestamp.Timestamp{Seconds: 1},
2057+
StorageState: apiv2beta1.Experiment_StorageState(apiv2beta1.Experiment_StorageState_value["STORAGE_STATE_UNSPECIFIED"]),
20482058
},
20492059
}
20502060
assert.Equal(t, expectedApiExps, apiExps)

0 commit comments

Comments
 (0)