From 3c29c9ddd8312a89fbc98dd1ee6e289bbe39f625 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Mon, 9 Feb 2026 15:01:03 +0700 Subject: [PATCH 01/26] feat: initial implementation of estimated finish time --- .../service/job_estimator_service.go | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 core/scheduler/service/job_estimator_service.go diff --git a/core/scheduler/service/job_estimator_service.go b/core/scheduler/service/job_estimator_service.go new file mode 100644 index 0000000000..94e41fc076 --- /dev/null +++ b/core/scheduler/service/job_estimator_service.go @@ -0,0 +1,154 @@ +package service + +import ( + "context" + "time" + + "github.com/goto/optimus/core/scheduler" + "github.com/goto/optimus/core/tenant" + "github.com/goto/salt/log" +) + +type JobEstimatorService struct { + l log.Logger + bufferTime time.Duration + jobDetailsGetter JobDetailsGetter + jobLineageFetcher JobLineageFetcher + durationEstimator DurationEstimator +} + +func NewJobEstimatorService( + logger log.Logger, + jobDetailsGetter JobDetailsGetter, + jobLineageFetcher JobLineageFetcher, + durationEstimator DurationEstimator, +) *JobEstimatorService { + return &JobEstimatorService{ + l: logger, + bufferTime: 10 * time.Minute, + jobDetailsGetter: jobDetailsGetter, + jobLineageFetcher: jobLineageFetcher, + durationEstimator: durationEstimator, + } +} + +func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string, referenceTime time.Time, scheduleRangeInHours time.Duration) (map[scheduler.JobSchedule]time.Time, error) { + jobRunEstimatedFinishTimes := make(map[scheduler.JobSchedule]time.Time) + + if len(jobNames) == 0 && len(labels) == 0 { + s.l.Warn("no job names or labels provided, skipping estimated finish time generation") + return jobRunEstimatedFinishTimes, nil + } + + // fetch job details + jobsWithDetails, err := s.getJobWithDetails(ctx, projectName, jobNames, labels) + if err != nil { + return nil, err + } + if len(jobsWithDetails) == 0 { + return jobRunEstimatedFinishTimes, nil + } + + // get scheduled at + jobSchedules := s.getJobSchedules(jobsWithDetails, scheduleRangeInHours, referenceTime) + if len(jobSchedules) == 0 { + s.l.Warn("no job schedules found for the given jobs in the next schedule range, skipping estimated finish time generation") + return jobRunEstimatedFinishTimes, nil + } + + // get lineage + jobsWithLineageMap, err := s.jobLineageFetcher.GetJobLineage(ctx, jobSchedules) + if err != nil { + s.l.Error("failed to get job lineage, skipping estimated finish time generation", "error", err) + return nil, err + } + + uniqueJobNames := collectJobNames(jobsWithLineageMap) + + // get job durations estimation + jobDurationsEstimation, err := s.durationEstimator.GetPercentileDurationByJobNames(ctx, referenceTime, uniqueJobNames) + if err != nil { + s.l.Error("failed to estimate job durations, skipping estimated finish time generation", "error", err) + return nil, err + } + + // calculate estimated finish time for each job + for _, jobSchedule := range jobSchedules { + key := *jobSchedule + if _, ok := jobRunEstimatedFinishTimes[key]; ok { // already calculated + continue + } + err := s.populateEstimatedFinishTime(ctx, jobSchedule, jobSchedule, jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) + if err != nil { + s.l.Error("failed to populate estimated finish time for job", "job", jobSchedule.JobName, "error", err) + return nil, err + } + } + + return jobRunEstimatedFinishTimes, nil +} + +func (s *JobEstimatorService) populateEstimatedFinishTime(ctx context.Context, jobTarget, jobSchedule *scheduler.JobSchedule, jobRunEstimatedFinishTimes map[scheduler.JobSchedule]time.Time, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { + key := *jobSchedule + estimatedDuration, ok := jobDurationsEstimation[jobSchedule.JobName] + if !ok { + // if no estimation found, we cannot proceed + s.l.Warn("no duration estimation found for job, cannot calculate estimated finish time", "job", jobSchedule.JobName) + return nil + } + + // termination condition + // 1. cache if already calculated + if _, ok := jobRunEstimatedFinishTimes[key]; ok { + return nil + } + // 2. if end_time is nil and scheduled_time+duration Date: Mon, 9 Feb 2026 15:05:55 +0700 Subject: [PATCH 02/26] refactor: use existing function from sla predictor service --- .../service/job_estimator_service.go | 17 ++------- .../service/job_sla_predictor_service.go | 38 +++++++++---------- 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/core/scheduler/service/job_estimator_service.go b/core/scheduler/service/job_estimator_service.go index 94e41fc076..36b88789d6 100644 --- a/core/scheduler/service/job_estimator_service.go +++ b/core/scheduler/service/job_estimator_service.go @@ -25,7 +25,7 @@ func NewJobEstimatorService( ) *JobEstimatorService { return &JobEstimatorService{ l: logger, - bufferTime: 10 * time.Minute, + bufferTime: 10 * time.Minute, // TODO: make this configurable jobDetailsGetter: jobDetailsGetter, jobLineageFetcher: jobLineageFetcher, durationEstimator: durationEstimator, @@ -41,7 +41,7 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, } // fetch job details - jobsWithDetails, err := s.getJobWithDetails(ctx, projectName, jobNames, labels) + jobsWithDetails, err := getJobWithDetails(ctx, s.l, s.jobDetailsGetter, projectName, jobNames, labels) if err != nil { return nil, err } @@ -50,7 +50,7 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, } // get scheduled at - jobSchedules := s.getJobSchedules(jobsWithDetails, scheduleRangeInHours, referenceTime) + jobSchedules := getJobSchedules(s.l, jobsWithDetails, scheduleRangeInHours, referenceTime) if len(jobSchedules) == 0 { s.l.Warn("no job schedules found for the given jobs in the next schedule range, skipping estimated finish time generation") return jobRunEstimatedFinishTimes, nil @@ -141,14 +141,3 @@ func maxTime(t1, t2 time.Time) time.Time { } return t2 } - -// TODO: refactor this to a common place since it's also used in SLA service -func (s *JobEstimatorService) getJobWithDetails(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string) ([]*scheduler.JobWithDetails, error) { - // TODO: same as in sla_service.go, refactor to common place - return []*scheduler.JobWithDetails{}, nil -} - -// TODO: refactor this to a common place since it's also used in SLA service -func (s *JobEstimatorService) getJobSchedules(jobs []*scheduler.JobWithDetails, scheduleRangeInHours time.Duration, referenceTime time.Time) map[scheduler.JobName]*scheduler.JobSchedule { - return map[scheduler.JobName]*scheduler.JobSchedule{} -} diff --git a/core/scheduler/service/job_sla_predictor_service.go b/core/scheduler/service/job_sla_predictor_service.go index c765c15c4e..c48596b724 100644 --- a/core/scheduler/service/job_sla_predictor_service.go +++ b/core/scheduler/service/job_sla_predictor_service.go @@ -117,7 +117,7 @@ func (s *JobSLAPredictorService) IdentifySLABreaches(ctx context.Context, projec } // get jobs with details - jobsWithDetails, err := s.getJobWithDetails(ctx, projectName, jobNames, labels) + jobsWithDetails, err := getJobWithDetails(ctx, s.l, s.jobDetailsGetter, projectName, jobNames, labels) if err != nil { s.l.Error("failed to get jobs with details, skipping SLA prediction", "error", err) return nil, err @@ -127,7 +127,7 @@ func (s *JobSLAPredictorService) IdentifySLABreaches(ctx context.Context, projec } // get scheduled at - jobSchedules := s.getJobSchedules(jobsWithDetails, reqConfig.ScheduleRangeInHours, reqConfig.ReferenceTime) + jobSchedules := getJobSchedules(s.l, jobsWithDetails, reqConfig.ScheduleRangeInHours, reqConfig.ReferenceTime) if len(jobSchedules) == 0 { s.l.Warn("no job schedules found for the given jobs in the next schedule range, skipping SLA prediction") return jobBreachCauses, nil @@ -244,7 +244,7 @@ func (s *JobSLAPredictorService) IdentifySLABreach(ctx context.Context, jobTarge return breachesCauses, fullBreachesCauses } -func (s JobSLAPredictorService) getJobWithDetails(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string) ([]*scheduler.JobWithDetails, error) { +func getJobWithDetails(ctx context.Context, l log.Logger, jobDetailsGetter JobDetailsGetter, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string) ([]*scheduler.JobWithDetails, error) { filteredJobsByName := map[scheduler.JobName]*scheduler.JobWithDetails{} filteredJobByLabel := map[scheduler.JobName]*scheduler.JobWithDetails{} filteredJobMerged := map[scheduler.JobName]*scheduler.JobWithDetails{} @@ -254,7 +254,7 @@ func (s JobSLAPredictorService) getJobWithDetails(ctx context.Context, projectNa for _, jn := range jobNames { jobNameStr = append(jobNameStr, string(jn)) } - jobsWithDetails, err := s.jobDetailsGetter.GetJobs(ctx, projectName, jobNameStr) + jobsWithDetails, err := jobDetailsGetter.GetJobs(ctx, projectName, jobNameStr) if err != nil { return nil, err } @@ -262,12 +262,12 @@ func (s JobSLAPredictorService) getJobWithDetails(ctx context.Context, projectNa filteredJobsByName[job.Name] = job filteredJobMerged[job.Name] = job } - s.l.Info("fetched jobs by names", "count", len(filteredJobsByName)) - s.l.Info("jobs fetched by names", "jobs", filteredJobsByName) + l.Info("fetched jobs by names", "count", len(filteredJobsByName)) + l.Info("jobs fetched by names", "jobs", filteredJobsByName) } if len(labels) > 0 { - jobsWithDetails, err := s.jobDetailsGetter.GetJobsByLabels(ctx, projectName, labels) + jobsWithDetails, err := jobDetailsGetter.GetJobsByLabels(ctx, projectName, labels) if err != nil { return nil, err } @@ -275,15 +275,15 @@ func (s JobSLAPredictorService) getJobWithDetails(ctx context.Context, projectNa filteredJobByLabel[job.Name] = job filteredJobMerged[job.Name] = job } - s.l.Info("fetched jobs by labels", "count", len(filteredJobByLabel)) - s.l.Info("jobs fetched by labels", "jobs", filteredJobByLabel) + l.Info("fetched jobs by labels", "count", len(filteredJobByLabel)) + l.Info("jobs fetched by labels", "jobs", filteredJobByLabel) } filteredJobSchedules := []*scheduler.JobWithDetails{} for _, job := range filteredJobMerged { filteredJobSchedules = append(filteredJobSchedules, job) } - s.l.Info("total jobs fetched after merging by names and labels", "count", len(filteredJobSchedules)) + l.Info("total jobs fetched after merging by names and labels", "count", len(filteredJobSchedules)) return filteredJobSchedules, nil } @@ -328,36 +328,36 @@ func (s *JobSLAPredictorService) getTargetedSLA(jobs []*scheduler.JobWithDetails return targetedSLAByJobName } -func (s *JobSLAPredictorService) getJobSchedules(jobs []*scheduler.JobWithDetails, scheduleRangeInHours time.Duration, referenceTime time.Time) map[scheduler.JobName]*scheduler.JobSchedule { +func getJobSchedules(l log.Logger, jobs []*scheduler.JobWithDetails, scheduleRangeInHours time.Duration, referenceTime time.Time) map[scheduler.JobName]*scheduler.JobSchedule { jobSchedules := make(map[scheduler.JobName]*scheduler.JobSchedule) - s.l.Info("jobs to get schedules for", "count", len(jobs)) + l.Info("jobs to get schedules for", "count", len(jobs)) for _, job := range jobs { if job.Schedule == nil { continue } nextScheduledAt, err := job.Schedule.GetNextSchedule(referenceTime) if err != nil { - s.l.Warn("failed to get scheduled at for job, skipping SLA prediction", "job", job.Name, "error", err) + l.Warn("failed to get scheduled at for job, skipping SLA prediction", "job", job.Name, "error", err) continue } prevScheduledAt, err := job.Schedule.GetPreviousSchedule(referenceTime) if err != nil { - s.l.Warn("failed to get previous scheduled at for job, skipping SLA prediction", "job", job.Name, "error", err) + l.Warn("failed to get previous scheduled at for job, skipping SLA prediction", "job", job.Name, "error", err) continue } var scheduledAt time.Time if nextScheduledAt.Sub(referenceTime).Milliseconds() < scheduleRangeInHours.Milliseconds() { - s.l.Debug("using next scheduled at for job within schedule range", "job", job.Name) + l.Debug("using next scheduled at for job within schedule range", "job", job.Name) scheduledAt = nextScheduledAt } else if referenceTime.Sub(prevScheduledAt).Milliseconds() < scheduleRangeInHours.Milliseconds() { - s.l.Debug("using previous scheduled at for job within schedule range", "job", job.Name) + l.Debug("using previous scheduled at for job within schedule range", "job", job.Name) scheduledAt = prevScheduledAt } if scheduledAt.IsZero() { - s.l.Warn("no scheduled at found for job in the next schedule range, skipping SLA prediction", "job", job.Name) + l.Warn("no scheduled at found for job in the next schedule range, skipping SLA prediction", "job", job.Name) continue } @@ -366,7 +366,7 @@ func (s *JobSLAPredictorService) getJobSchedules(jobs []*scheduler.JobWithDetail ScheduledAt: scheduledAt, } } - s.l.Info("total job schedules found", "count", len(jobSchedules)) + l.Info("total job schedules found", "count", len(jobSchedules)) // jobs not having schedule within the range will be skipped jobsSkipped := []string{} for _, job := range jobs { @@ -375,7 +375,7 @@ func (s *JobSLAPredictorService) getJobSchedules(jobs []*scheduler.JobWithDetail } } if len(jobsSkipped) > 0 { - s.l.Info("jobs skipped due to no schedule within the range", "jobs", jobsSkipped) + l.Info("jobs skipped due to no schedule within the range", "jobs", jobsSkipped) } return jobSchedules } From 22c83f2bf45499a55e778ff52007d38ec6466a6f Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Mon, 9 Feb 2026 15:14:59 +0700 Subject: [PATCH 03/26] feat: store estimated duration to db --- .../service/job_estimator_service.go | 23 +++++++++++++++++++ ...0080_create_job_run_details_table.down.sql | 1 + ...000080_create_job_run_details_table.up.sql | 9 ++++++++ .../postgres/scheduler/job_run_repository.go | 11 +++++++++ 4 files changed, 44 insertions(+) create mode 100644 internal/store/postgres/migrations/000080_create_job_run_details_table.down.sql create mode 100644 internal/store/postgres/migrations/000080_create_job_run_details_table.up.sql diff --git a/core/scheduler/service/job_estimator_service.go b/core/scheduler/service/job_estimator_service.go index 36b88789d6..c63deb9d4f 100644 --- a/core/scheduler/service/job_estimator_service.go +++ b/core/scheduler/service/job_estimator_service.go @@ -9,9 +9,14 @@ import ( "github.com/goto/salt/log" ) +type JobRunDetailsRepository interface { + UpsertEstimatedFinishTime(ctx context.Context, projectName tenant.ProjectName, jobName scheduler.JobName, scheduledAt time.Time, estimatedFinishTime time.Time) error +} + type JobEstimatorService struct { l log.Logger bufferTime time.Duration + jobRunDetailsRepo JobRunDetailsRepository jobDetailsGetter JobDetailsGetter jobLineageFetcher JobLineageFetcher durationEstimator DurationEstimator @@ -19,6 +24,7 @@ type JobEstimatorService struct { func NewJobEstimatorService( logger log.Logger, + jobRunDetailsRepo JobRunDetailsRepository, jobDetailsGetter JobDetailsGetter, jobLineageFetcher JobLineageFetcher, durationEstimator DurationEstimator, @@ -26,6 +32,7 @@ func NewJobEstimatorService( return &JobEstimatorService{ l: logger, bufferTime: 10 * time.Minute, // TODO: make this configurable + jobRunDetailsRepo: jobRunDetailsRepo, jobDetailsGetter: jobDetailsGetter, jobLineageFetcher: jobLineageFetcher, durationEstimator: durationEstimator, @@ -85,6 +92,22 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, } } + // save to db + for _, jobSchedule := range jobSchedules { + key := *jobSchedule + estimatedFinishTime, ok := jobRunEstimatedFinishTimes[key] + if !ok { + s.l.Warn("estimated finish time not found for job schedule", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) + continue + } + s.l.Info("estimated finish time calculated", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt, "estimated_finish_time", estimatedFinishTime) + err := s.jobRunDetailsRepo.UpsertEstimatedFinishTime(ctx, projectName, jobSchedule.JobName, jobSchedule.ScheduledAt, estimatedFinishTime) + if err != nil { + s.l.Error("failed to upsert estimated finish time for job schedule", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt, "error", err) + return nil, err + } + } + return jobRunEstimatedFinishTimes, nil } diff --git a/internal/store/postgres/migrations/000080_create_job_run_details_table.down.sql b/internal/store/postgres/migrations/000080_create_job_run_details_table.down.sql new file mode 100644 index 0000000000..a598deb3a3 --- /dev/null +++ b/internal/store/postgres/migrations/000080_create_job_run_details_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS job_run_details; \ No newline at end of file diff --git a/internal/store/postgres/migrations/000080_create_job_run_details_table.up.sql b/internal/store/postgres/migrations/000080_create_job_run_details_table.up.sql new file mode 100644 index 0000000000..c087ce266b --- /dev/null +++ b/internal/store/postgres/migrations/000080_create_job_run_details_table.up.sql @@ -0,0 +1,9 @@ +CREATE TABLE job_run_details ( + project_name TEXT NOT NULL, + job_name TEXT NOT NULL, + scheduled_at TIMESTAMPTZ NOT NULL, + estimated_finish_time TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + PRIMARY KEY (project_name, job_name, scheduled_at) +); \ No newline at end of file diff --git a/internal/store/postgres/scheduler/job_run_repository.go b/internal/store/postgres/scheduler/job_run_repository.go index 835967ebda..53822e3aa2 100644 --- a/internal/store/postgres/scheduler/job_run_repository.go +++ b/internal/store/postgres/scheduler/job_run_repository.go @@ -614,6 +614,17 @@ ORDER BY scheduled_at DESC return summaries, nil } +func (j *JobRunRepository) UpsertEstimatedFinishTime(ctx context.Context, projectName tenant.ProjectName, jobName scheduler.JobName, scheduledAt time.Time, estimatedFinishTime time.Time) error { + upsertQuery := ` + INSERT INTO job_run_estimated_finish_time (project_name, job_name, scheduled_at, estimated_finish_time, created_at, updated_at) + VALUES ($1, $2, $3, $4, NOW(), NOW()) + ON CONFLICT (project_name, job_name, scheduled_at) + DO UPDATE SET estimated_finish_time = EXCLUDED.estimated_finish_time, updated_at = NOW() + ` + _, err := j.db.Exec(ctx, upsertQuery, projectName, jobName, scheduledAt, estimatedFinishTime) + return errors.WrapIfErr(scheduler.EntityJobRun, "unable to upsert estimated finish time", err) +} + func NewJobRunRepository(pool *pgxpool.Pool, l log.Logger) *JobRunRepository { return &JobRunRepository{ db: pool, From da0c03d5780a90ff78233da37f3f611fb050a639 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Mon, 9 Feb 2026 15:16:17 +0700 Subject: [PATCH 04/26] fix: lint --- core/scheduler/service/job_estimator_service.go | 5 +++-- internal/store/postgres/scheduler/job_run_repository.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/scheduler/service/job_estimator_service.go b/core/scheduler/service/job_estimator_service.go index c63deb9d4f..67f7c0582d 100644 --- a/core/scheduler/service/job_estimator_service.go +++ b/core/scheduler/service/job_estimator_service.go @@ -4,13 +4,14 @@ import ( "context" "time" + "github.com/goto/salt/log" + "github.com/goto/optimus/core/scheduler" "github.com/goto/optimus/core/tenant" - "github.com/goto/salt/log" ) type JobRunDetailsRepository interface { - UpsertEstimatedFinishTime(ctx context.Context, projectName tenant.ProjectName, jobName scheduler.JobName, scheduledAt time.Time, estimatedFinishTime time.Time) error + UpsertEstimatedFinishTime(ctx context.Context, projectName tenant.ProjectName, jobName scheduler.JobName, scheduledAt, estimatedFinishTime time.Time) error } type JobEstimatorService struct { diff --git a/internal/store/postgres/scheduler/job_run_repository.go b/internal/store/postgres/scheduler/job_run_repository.go index 53822e3aa2..435967049c 100644 --- a/internal/store/postgres/scheduler/job_run_repository.go +++ b/internal/store/postgres/scheduler/job_run_repository.go @@ -614,7 +614,7 @@ ORDER BY scheduled_at DESC return summaries, nil } -func (j *JobRunRepository) UpsertEstimatedFinishTime(ctx context.Context, projectName tenant.ProjectName, jobName scheduler.JobName, scheduledAt time.Time, estimatedFinishTime time.Time) error { +func (j *JobRunRepository) UpsertEstimatedFinishTime(ctx context.Context, projectName tenant.ProjectName, jobName scheduler.JobName, scheduledAt, estimatedFinishTime time.Time) error { upsertQuery := ` INSERT INTO job_run_estimated_finish_time (project_name, job_name, scheduled_at, estimated_finish_time, created_at, updated_at) VALUES ($1, $2, $3, $4, NOW(), NOW()) From 6bde8fe1583a965d8ac8abba60fe1e44104c7e4c Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Mon, 9 Feb 2026 15:34:12 +0700 Subject: [PATCH 05/26] feat: update proto --- Makefile | 2 +- .../optimus/core/v1beta1/backup.pb.go | 14 +- .../optimus/core/v1beta1/job_run.pb.go | 745 +++++++++++------- .../optimus/core/v1beta1/job_run.pb.gw.go | 115 +++ .../optimus/core/v1beta1/job_run.swagger.json | 75 +- .../optimus/core/v1beta1/job_run_grpc.pb.go | 38 + .../optimus/core/v1beta1/job_spec.pb.go | 94 +-- .../optimus/core/v1beta1/namespace.pb.go | 8 +- .../optimus/core/v1beta1/project.pb.go | 4 +- .../optimus/core/v1beta1/replay.pb.go | 16 +- .../optimus/core/v1beta1/resource.pb.go | 84 +- .../core/v1beta1/resource.swagger.json | 2 +- .../optimus/core/v1beta1/runtime.pb.go | 4 +- .../optimus/core/v1beta1/secret.pb.go | 20 +- 14 files changed, 831 insertions(+), 390 deletions(-) diff --git a/Makefile b/Makefile index 58fea85a3c..296221cda3 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ NAME = "github.com/goto/optimus" LAST_COMMIT := $(shell git rev-parse --short HEAD) LAST_TAG := "$(shell git rev-list --tags --max-count=1)" OPMS_VERSION := "$(shell git describe --tags ${LAST_TAG})-next" -PROTON_COMMIT := "8e1c00250e4a3ef62086f513d52c43c790946eff" +PROTON_COMMIT := "977983ef13d406a54a1859aa419907d634272686" .PHONY: build test test-ci generate-proto unit-test-ci integration-test vet coverage clean install lint diff --git a/protos/gotocompany/optimus/core/v1beta1/backup.pb.go b/protos/gotocompany/optimus/core/v1beta1/backup.pb.go index 641cf97a13..082d8c6d7f 100644 --- a/protos/gotocompany/optimus/core/v1beta1/backup.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/backup.pb.go @@ -648,13 +648,13 @@ var file_gotocompany_optimus_core_v1beta1_backup_proto_rawDesc = []byte{ 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x67, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x61, 0x3a, 0x01, 0x2a, 0x22, 0x5c, 0x2f, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, - 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0xe0, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x61, 0x22, 0x5c, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, + 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x01, 0x2a, 0x12, 0xe0, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, diff --git a/protos/gotocompany/optimus/core/v1beta1/job_run.pb.go b/protos/gotocompany/optimus/core/v1beta1/job_run.pb.go index b16a5c2fce..7210b30bba 100644 --- a/protos/gotocompany/optimus/core/v1beta1/job_run.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/job_run.pb.go @@ -2802,6 +2802,132 @@ func (x *UpstreamJobsStatus) GetJobsStatus() []*UpstreamJobStatus { return nil } +type GenerateEstimatedFinishTimeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProjectName string `protobuf:"bytes,1,opt,name=project_name,json=projectName,proto3" json:"project_name,omitempty"` + JobNames []string `protobuf:"bytes,2,rep,name=job_names,json=jobNames,proto3" json:"job_names,omitempty"` + JobLabels map[string]string `protobuf:"bytes,3,rep,name=job_labels,json=jobLabels,proto3" json:"job_labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + ScheduledRangeInHours int32 `protobuf:"varint,4,opt,name=scheduled_range_in_hours,json=scheduledRangeInHours,proto3" json:"scheduled_range_in_hours,omitempty"` + ReferenceTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=reference_time,json=referenceTime,proto3" json:"reference_time,omitempty"` // RFC3339 format +} + +func (x *GenerateEstimatedFinishTimeRequest) Reset() { + *x = GenerateEstimatedFinishTimeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenerateEstimatedFinishTimeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateEstimatedFinishTimeRequest) ProtoMessage() {} + +func (x *GenerateEstimatedFinishTimeRequest) ProtoReflect() protoreflect.Message { + mi := &file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateEstimatedFinishTimeRequest.ProtoReflect.Descriptor instead. +func (*GenerateEstimatedFinishTimeRequest) Descriptor() ([]byte, []int) { + return file_gotocompany_optimus_core_v1beta1_job_run_proto_rawDescGZIP(), []int{40} +} + +func (x *GenerateEstimatedFinishTimeRequest) GetProjectName() string { + if x != nil { + return x.ProjectName + } + return "" +} + +func (x *GenerateEstimatedFinishTimeRequest) GetJobNames() []string { + if x != nil { + return x.JobNames + } + return nil +} + +func (x *GenerateEstimatedFinishTimeRequest) GetJobLabels() map[string]string { + if x != nil { + return x.JobLabels + } + return nil +} + +func (x *GenerateEstimatedFinishTimeRequest) GetScheduledRangeInHours() int32 { + if x != nil { + return x.ScheduledRangeInHours + } + return 0 +} + +func (x *GenerateEstimatedFinishTimeRequest) GetReferenceTime() *timestamppb.Timestamp { + if x != nil { + return x.ReferenceTime + } + return nil +} + +type GenerateEstimatedFinishTimeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Jobs map[string]*timestamppb.Timestamp `protobuf:"bytes,1,rep,name=jobs,proto3" json:"jobs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *GenerateEstimatedFinishTimeResponse) Reset() { + *x = GenerateEstimatedFinishTimeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenerateEstimatedFinishTimeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateEstimatedFinishTimeResponse) ProtoMessage() {} + +func (x *GenerateEstimatedFinishTimeResponse) ProtoReflect() protoreflect.Message { + mi := &file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[41] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateEstimatedFinishTimeResponse.ProtoReflect.Descriptor instead. +func (*GenerateEstimatedFinishTimeResponse) Descriptor() ([]byte, []int) { + return file_gotocompany_optimus_core_v1beta1_job_run_proto_rawDescGZIP(), []int{41} +} + +func (x *GenerateEstimatedFinishTimeResponse) GetJobs() map[string]*timestamppb.Timestamp { + if x != nil { + return x.Jobs + } + return nil +} + var File_gotocompany_optimus_core_v1beta1_job_run_proto protoreflect.FileDescriptor var file_gotocompany_optimus_core_v1beta1_job_run_proto_rawDesc = []byte{ @@ -3375,160 +3501,215 @@ var file_gotocompany_optimus_core_v1beta1_job_run_proto_rawDesc = []byte{ 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0a, 0x6a, 0x6f, 0x62, 0x73, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x32, 0xfc, 0x11, 0x0a, 0x0d, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xbf, 0x01, 0x0a, 0x0b, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, - 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, - 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, - 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, - 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3d, 0x3a, 0x01, 0x2a, 0x22, 0x38, 0x2f, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, - 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, - 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x75, - 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x12, 0xa7, 0x01, 0x0a, 0x06, 0x4a, 0x6f, 0x62, 0x52, - 0x75, 0x6e, 0x12, 0x2f, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, - 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, - 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, - 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x75, - 0x6e, 0x12, 0xd2, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, - 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x39, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, - 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, - 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, - 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x12, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x2f, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0xdb, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x3c, + 0x74, 0x75, 0x73, 0x22, 0x92, 0x03, 0x0a, 0x22, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, + 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, + 0x09, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x08, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x72, 0x0a, 0x0a, 0x6a, 0x6f, + 0x62, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x53, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, - 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x67, + 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, + 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4a, 0x6f, 0x62, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x09, 0x6a, 0x6f, 0x62, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x37, + 0x0a, 0x18, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x61, 0x6e, 0x67, + 0x65, 0x5f, 0x69, 0x6e, 0x5f, 0x68, 0x6f, 0x75, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x15, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, + 0x49, 0x6e, 0x48, 0x6f, 0x75, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x0e, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x1a, 0x3c, 0x0a, 0x0e, 0x4a, 0x6f, + 0x62, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xdf, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, + 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x63, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4f, + 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, + 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x1a, 0x53, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xee, 0x13, 0x0a, 0x0d, 0x4a, + 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xbf, 0x01, 0x0a, + 0x0b, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, - 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x41, 0x22, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, - 0x72, 0x6f, 0x6c, 0x65, 0x12, 0xb8, 0x01, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, - 0x75, 0x6e, 0x73, 0x12, 0x33, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, - 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, - 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4a, - 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x12, 0x37, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x12, - 0xe6, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, - 0x79, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3c, 0x2e, - 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x53, 0x65, - 0x6e, 0x73, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x67, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x53, 0x65, 0x6e, 0x73, - 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4c, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x46, 0x3a, 0x01, 0x2a, 0x1a, 0x41, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x68, 0x69, 0x72, 0x64, 0x2d, 0x70, 0x61, 0x72, 0x74, - 0x79, 0x2d, 0x73, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x12, 0xe5, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x2e, + 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x3d, 0x22, 0x38, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x72, 0x75, 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xa7, + 0x01, 0x0a, 0x06, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x12, 0x2f, 0x2e, 0x67, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, + 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, + 0x62, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x75, 0x6e, 0x12, 0xd2, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, + 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x39, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, + 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, - 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x54, 0x3a, 0x01, 0x2a, 0x22, - 0x4f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, - 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x12, 0xbf, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x6f, 0x53, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, - 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, - 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, - 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x6f, 0x53, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x3a, 0x01, 0x2a, 0x1a, 0x26, 0x2f, 0x76, 0x31, 0x62, + 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x12, 0x3f, 0x2f, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0xdb, 0x01, + 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, + 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x3c, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, + 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x22, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x75, 0x70, 0x6c, 0x6f, - 0x61, 0x64, 0x12, 0xbb, 0x01, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, - 0x61, 0x6c, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0xb8, 0x01, 0x0a, 0x0a, + 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x73, 0x12, 0x33, 0x2e, 0x67, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x12, 0x37, 0x2f, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, + 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, + 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, + 0x62, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x12, 0xe6, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x54, 0x68, + 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x3c, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x69, 0x72, 0x64, + 0x50, 0x61, 0x72, 0x74, 0x79, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, - 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x12, 0x37, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, - 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, - 0x12, 0xcb, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4c, 0x69, - 0x6e, 0x65, 0x61, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x40, 0x2e, 0x67, - 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x67, 0x65, - 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, - 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4c, 0x69, 0x6e, 0x65, 0x61, - 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x3a, 0x01, 0x2a, 0x22, 0x20, 0x2f, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x6a, 0x6f, 0x62, 0x2d, 0x72, 0x75, 0x6e, 0x2d, 0x6c, - 0x69, 0x6e, 0x65, 0x61, 0x67, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0xf1, - 0x01, 0x0a, 0x1a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x50, 0x6f, 0x74, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x53, 0x4c, 0x41, 0x42, 0x72, 0x65, 0x61, 0x63, 0x68, 0x12, 0x43, 0x2e, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, + 0x72, 0x74, 0x79, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x4c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x46, 0x1a, 0x41, 0x2f, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, + 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x68, 0x69, 0x72, 0x64, 0x2d, + 0x70, 0x61, 0x72, 0x74, 0x79, 0x2d, 0x73, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x3a, 0x01, 0x2a, 0x12, + 0xe5, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5a, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x54, 0x22, 0x4f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, + 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xbf, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x50, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x53, 0x4c, 0x41, 0x42, 0x72, 0x65, 0x61, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x44, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x50, 0x6f, - 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x4c, 0x41, 0x42, 0x72, 0x65, 0x61, 0x63, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42, - 0x3a, 0x01, 0x2a, 0x22, 0x3d, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, - 0x6c, 0x61, 0x5f, 0x62, 0x72, 0x65, 0x61, 0x63, 0x68, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x79, 0x42, 0x8f, 0x01, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x42, 0x0d, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x1e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2f, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x92, 0x41, 0x3b, 0x12, 0x05, 0x32, 0x03, 0x30, 0x2e, 0x31, - 0x1a, 0x0e, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x39, 0x31, 0x30, 0x30, - 0x22, 0x04, 0x2f, 0x61, 0x70, 0x69, 0x2a, 0x01, 0x01, 0x72, 0x19, 0x0a, 0x17, 0x4f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x20, 0x4a, 0x6f, 0x62, 0x20, 0x52, 0x75, 0x6e, 0x20, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x67, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x6c, + 0x6f, 0x61, 0x64, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x1a, 0x26, + 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, + 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0xbb, 0x01, 0x0a, 0x0b, 0x47, 0x65, + 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x35, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x12, 0x37, + 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, + 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0xcb, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4a, + 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x12, 0x40, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, + 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, + 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, + 0x75, 0x6e, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, + 0x22, 0x20, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x6a, 0x6f, 0x62, 0x2d, 0x72, + 0x75, 0x6e, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x61, 0x67, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x61, + 0x72, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0xf1, 0x01, 0x0a, 0x1a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x79, 0x50, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x4c, 0x41, 0x42, 0x72, + 0x65, 0x61, 0x63, 0x68, 0x12, 0x43, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, + 0x50, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x4c, 0x41, 0x42, 0x72, 0x65, 0x61, + 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x44, 0x2e, 0x67, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x79, 0x50, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x4c, + 0x41, 0x42, 0x72, 0x65, 0x61, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x48, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42, 0x22, 0x3d, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x5f, 0x73, 0x6c, 0x61, 0x5f, 0x62, 0x72, 0x65, 0x61, 0x63, 0x68, 0x2f, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0xef, 0x01, 0x0a, 0x1b, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x46, + 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x44, 0x2e, 0x67, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, + 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x45, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x73, 0x74, 0x69, 0x6d, + 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3d, 0x22, 0x38, + 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, + 0x65, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x66, 0x69, 0x6e, + 0x69, 0x73, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x3a, 0x01, 0x2a, 0x42, 0x8f, 0x01, 0x0a, 0x1e, + 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x42, 0x0d, + 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x01, 0x5a, + 0x1e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x74, 0x6f, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x92, + 0x41, 0x3b, 0x12, 0x05, 0x32, 0x03, 0x30, 0x2e, 0x31, 0x1a, 0x0e, 0x31, 0x32, 0x37, 0x2e, 0x30, + 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x39, 0x31, 0x30, 0x30, 0x22, 0x04, 0x2f, 0x61, 0x70, 0x69, 0x2a, + 0x01, 0x01, 0x72, 0x19, 0x0a, 0x17, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x20, 0x4a, 0x6f, + 0x62, 0x20, 0x52, 0x75, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3544,150 +3725,160 @@ func file_gotocompany_optimus_core_v1beta1_job_run_proto_rawDescGZIP() []byte { } var file_gotocompany_optimus_core_v1beta1_job_run_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes = make([]protoimpl.MessageInfo, 45) +var file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes = make([]protoimpl.MessageInfo, 49) var file_gotocompany_optimus_core_v1beta1_job_run_proto_goTypes = []interface{}{ - (InstanceSpec_Type)(0), // 0: gotocompany.optimus.core.v1beta1.InstanceSpec.Type - (InstanceSpecData_Type)(0), // 1: gotocompany.optimus.core.v1beta1.InstanceSpecData.Type - (*DexSensorRequest)(nil), // 2: gotocompany.optimus.core.v1beta1.DexSensorRequest - (*DataCompleteness)(nil), // 3: gotocompany.optimus.core.v1beta1.DataCompleteness - (*DexSensorResponse)(nil), // 4: gotocompany.optimus.core.v1beta1.DexSensorResponse - (*GetThirdPartySensorRequest)(nil), // 5: gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest - (*GetThirdPartySensorResponse)(nil), // 6: gotocompany.optimus.core.v1beta1.GetThirdPartySensorResponse - (*GetIntervalRequest)(nil), // 7: gotocompany.optimus.core.v1beta1.GetIntervalRequest - (*GetIntervalResponse)(nil), // 8: gotocompany.optimus.core.v1beta1.GetIntervalResponse - (*UploadToSchedulerRequest)(nil), // 9: gotocompany.optimus.core.v1beta1.UploadToSchedulerRequest - (*UploadToSchedulerResponse)(nil), // 10: gotocompany.optimus.core.v1beta1.UploadToSchedulerResponse - (*RegisterJobEventRequest)(nil), // 11: gotocompany.optimus.core.v1beta1.RegisterJobEventRequest - (*RegisterJobEventResponse)(nil), // 12: gotocompany.optimus.core.v1beta1.RegisterJobEventResponse - (*JobRunInputRequest)(nil), // 13: gotocompany.optimus.core.v1beta1.JobRunInputRequest - (*GetJobRunsRequest)(nil), // 14: gotocompany.optimus.core.v1beta1.GetJobRunsRequest - (*JobRunWithDetail)(nil), // 15: gotocompany.optimus.core.v1beta1.JobRunWithDetail - (*GetJobRunsResponse)(nil), // 16: gotocompany.optimus.core.v1beta1.GetJobRunsResponse - (*JobRunRequest)(nil), // 17: gotocompany.optimus.core.v1beta1.JobRunRequest - (*JobRunResponse)(nil), // 18: gotocompany.optimus.core.v1beta1.JobRunResponse - (*GetSchedulerRoleRequest)(nil), // 19: gotocompany.optimus.core.v1beta1.GetSchedulerRoleRequest - (*GetSchedulerRoleResponse)(nil), // 20: gotocompany.optimus.core.v1beta1.GetSchedulerRoleResponse - (*CreateSchedulerRoleRequest)(nil), // 21: gotocompany.optimus.core.v1beta1.CreateSchedulerRoleRequest - (*CreateSchedulerRoleResponse)(nil), // 22: gotocompany.optimus.core.v1beta1.CreateSchedulerRoleResponse - (*InstanceSpec)(nil), // 23: gotocompany.optimus.core.v1beta1.InstanceSpec - (*InstanceSpecData)(nil), // 24: gotocompany.optimus.core.v1beta1.InstanceSpecData - (*JobRunInputResponse)(nil), // 25: gotocompany.optimus.core.v1beta1.JobRunInputResponse - (*TaskWindow)(nil), // 26: gotocompany.optimus.core.v1beta1.TaskWindow - (*GetJobRunLineageSummaryRequest)(nil), // 27: gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryRequest - (*TargetJobRunIdentifier)(nil), // 28: gotocompany.optimus.core.v1beta1.TargetJobRunIdentifier - (*GetJobRunLineageSummaryResponse)(nil), // 29: gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryResponse - (*JobRunLineageSummary)(nil), // 30: gotocompany.optimus.core.v1beta1.JobRunLineageSummary - (*LineageExecutionSummary)(nil), // 31: gotocompany.optimus.core.v1beta1.LineageExecutionSummary - (*JobWithTaskDuration)(nil), // 32: gotocompany.optimus.core.v1beta1.JobWithTaskDuration - (*LineageDelaySummary)(nil), // 33: gotocompany.optimus.core.v1beta1.LineageDelaySummary - (*JobExecutionSummary)(nil), // 34: gotocompany.optimus.core.v1beta1.JobExecutionSummary - (*JobRunSummary)(nil), // 35: gotocompany.optimus.core.v1beta1.JobRunSummary - (*JobRunDelaySummary)(nil), // 36: gotocompany.optimus.core.v1beta1.JobRunDelaySummary - (*SLAConfig)(nil), // 37: gotocompany.optimus.core.v1beta1.SLAConfig - (*IdentifyPotentialSLABreachRequest)(nil), // 38: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest - (*IdentifyPotentialSLABreachResponse)(nil), // 39: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse - (*UpstreamJobStatus)(nil), // 40: gotocompany.optimus.core.v1beta1.UpstreamJobStatus - (*UpstreamJobsStatus)(nil), // 41: gotocompany.optimus.core.v1beta1.UpstreamJobsStatus - nil, // 42: gotocompany.optimus.core.v1beta1.JobRunInputResponse.EnvsEntry - nil, // 43: gotocompany.optimus.core.v1beta1.JobRunInputResponse.FilesEntry - nil, // 44: gotocompany.optimus.core.v1beta1.JobRunInputResponse.SecretsEntry - nil, // 45: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.JobLabelsEntry - nil, // 46: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry - (*timestamppb.Timestamp)(nil), // 47: google.protobuf.Timestamp - (*JobEvent)(nil), // 48: gotocompany.optimus.core.v1beta1.JobEvent - (*JobRun)(nil), // 49: gotocompany.optimus.core.v1beta1.JobRun - (*durationpb.Duration)(nil), // 50: google.protobuf.Duration + (InstanceSpec_Type)(0), // 0: gotocompany.optimus.core.v1beta1.InstanceSpec.Type + (InstanceSpecData_Type)(0), // 1: gotocompany.optimus.core.v1beta1.InstanceSpecData.Type + (*DexSensorRequest)(nil), // 2: gotocompany.optimus.core.v1beta1.DexSensorRequest + (*DataCompleteness)(nil), // 3: gotocompany.optimus.core.v1beta1.DataCompleteness + (*DexSensorResponse)(nil), // 4: gotocompany.optimus.core.v1beta1.DexSensorResponse + (*GetThirdPartySensorRequest)(nil), // 5: gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest + (*GetThirdPartySensorResponse)(nil), // 6: gotocompany.optimus.core.v1beta1.GetThirdPartySensorResponse + (*GetIntervalRequest)(nil), // 7: gotocompany.optimus.core.v1beta1.GetIntervalRequest + (*GetIntervalResponse)(nil), // 8: gotocompany.optimus.core.v1beta1.GetIntervalResponse + (*UploadToSchedulerRequest)(nil), // 9: gotocompany.optimus.core.v1beta1.UploadToSchedulerRequest + (*UploadToSchedulerResponse)(nil), // 10: gotocompany.optimus.core.v1beta1.UploadToSchedulerResponse + (*RegisterJobEventRequest)(nil), // 11: gotocompany.optimus.core.v1beta1.RegisterJobEventRequest + (*RegisterJobEventResponse)(nil), // 12: gotocompany.optimus.core.v1beta1.RegisterJobEventResponse + (*JobRunInputRequest)(nil), // 13: gotocompany.optimus.core.v1beta1.JobRunInputRequest + (*GetJobRunsRequest)(nil), // 14: gotocompany.optimus.core.v1beta1.GetJobRunsRequest + (*JobRunWithDetail)(nil), // 15: gotocompany.optimus.core.v1beta1.JobRunWithDetail + (*GetJobRunsResponse)(nil), // 16: gotocompany.optimus.core.v1beta1.GetJobRunsResponse + (*JobRunRequest)(nil), // 17: gotocompany.optimus.core.v1beta1.JobRunRequest + (*JobRunResponse)(nil), // 18: gotocompany.optimus.core.v1beta1.JobRunResponse + (*GetSchedulerRoleRequest)(nil), // 19: gotocompany.optimus.core.v1beta1.GetSchedulerRoleRequest + (*GetSchedulerRoleResponse)(nil), // 20: gotocompany.optimus.core.v1beta1.GetSchedulerRoleResponse + (*CreateSchedulerRoleRequest)(nil), // 21: gotocompany.optimus.core.v1beta1.CreateSchedulerRoleRequest + (*CreateSchedulerRoleResponse)(nil), // 22: gotocompany.optimus.core.v1beta1.CreateSchedulerRoleResponse + (*InstanceSpec)(nil), // 23: gotocompany.optimus.core.v1beta1.InstanceSpec + (*InstanceSpecData)(nil), // 24: gotocompany.optimus.core.v1beta1.InstanceSpecData + (*JobRunInputResponse)(nil), // 25: gotocompany.optimus.core.v1beta1.JobRunInputResponse + (*TaskWindow)(nil), // 26: gotocompany.optimus.core.v1beta1.TaskWindow + (*GetJobRunLineageSummaryRequest)(nil), // 27: gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryRequest + (*TargetJobRunIdentifier)(nil), // 28: gotocompany.optimus.core.v1beta1.TargetJobRunIdentifier + (*GetJobRunLineageSummaryResponse)(nil), // 29: gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryResponse + (*JobRunLineageSummary)(nil), // 30: gotocompany.optimus.core.v1beta1.JobRunLineageSummary + (*LineageExecutionSummary)(nil), // 31: gotocompany.optimus.core.v1beta1.LineageExecutionSummary + (*JobWithTaskDuration)(nil), // 32: gotocompany.optimus.core.v1beta1.JobWithTaskDuration + (*LineageDelaySummary)(nil), // 33: gotocompany.optimus.core.v1beta1.LineageDelaySummary + (*JobExecutionSummary)(nil), // 34: gotocompany.optimus.core.v1beta1.JobExecutionSummary + (*JobRunSummary)(nil), // 35: gotocompany.optimus.core.v1beta1.JobRunSummary + (*JobRunDelaySummary)(nil), // 36: gotocompany.optimus.core.v1beta1.JobRunDelaySummary + (*SLAConfig)(nil), // 37: gotocompany.optimus.core.v1beta1.SLAConfig + (*IdentifyPotentialSLABreachRequest)(nil), // 38: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest + (*IdentifyPotentialSLABreachResponse)(nil), // 39: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse + (*UpstreamJobStatus)(nil), // 40: gotocompany.optimus.core.v1beta1.UpstreamJobStatus + (*UpstreamJobsStatus)(nil), // 41: gotocompany.optimus.core.v1beta1.UpstreamJobsStatus + (*GenerateEstimatedFinishTimeRequest)(nil), // 42: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeRequest + (*GenerateEstimatedFinishTimeResponse)(nil), // 43: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeResponse + nil, // 44: gotocompany.optimus.core.v1beta1.JobRunInputResponse.EnvsEntry + nil, // 45: gotocompany.optimus.core.v1beta1.JobRunInputResponse.FilesEntry + nil, // 46: gotocompany.optimus.core.v1beta1.JobRunInputResponse.SecretsEntry + nil, // 47: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.JobLabelsEntry + nil, // 48: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry + nil, // 49: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeRequest.JobLabelsEntry + nil, // 50: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeResponse.JobsEntry + (*timestamppb.Timestamp)(nil), // 51: google.protobuf.Timestamp + (*JobEvent)(nil), // 52: gotocompany.optimus.core.v1beta1.JobEvent + (*JobRun)(nil), // 53: gotocompany.optimus.core.v1beta1.JobRun + (*durationpb.Duration)(nil), // 54: google.protobuf.Duration } var file_gotocompany_optimus_core_v1beta1_job_run_proto_depIdxs = []int32{ - 47, // 0: gotocompany.optimus.core.v1beta1.DataCompleteness.date:type_name -> google.protobuf.Timestamp + 51, // 0: gotocompany.optimus.core.v1beta1.DataCompleteness.date:type_name -> google.protobuf.Timestamp 3, // 1: gotocompany.optimus.core.v1beta1.DexSensorResponse.log:type_name -> gotocompany.optimus.core.v1beta1.DataCompleteness - 47, // 2: gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest.scheduled_at:type_name -> google.protobuf.Timestamp + 51, // 2: gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest.scheduled_at:type_name -> google.protobuf.Timestamp 2, // 3: gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest.dex_sensor_request:type_name -> gotocompany.optimus.core.v1beta1.DexSensorRequest 4, // 4: gotocompany.optimus.core.v1beta1.GetThirdPartySensorResponse.dex_sensor_response:type_name -> gotocompany.optimus.core.v1beta1.DexSensorResponse - 47, // 5: gotocompany.optimus.core.v1beta1.GetIntervalRequest.reference_time:type_name -> google.protobuf.Timestamp - 47, // 6: gotocompany.optimus.core.v1beta1.GetIntervalResponse.start_time:type_name -> google.protobuf.Timestamp - 47, // 7: gotocompany.optimus.core.v1beta1.GetIntervalResponse.end_time:type_name -> google.protobuf.Timestamp - 48, // 8: gotocompany.optimus.core.v1beta1.RegisterJobEventRequest.event:type_name -> gotocompany.optimus.core.v1beta1.JobEvent - 47, // 9: gotocompany.optimus.core.v1beta1.JobRunInputRequest.scheduled_at:type_name -> google.protobuf.Timestamp + 51, // 5: gotocompany.optimus.core.v1beta1.GetIntervalRequest.reference_time:type_name -> google.protobuf.Timestamp + 51, // 6: gotocompany.optimus.core.v1beta1.GetIntervalResponse.start_time:type_name -> google.protobuf.Timestamp + 51, // 7: gotocompany.optimus.core.v1beta1.GetIntervalResponse.end_time:type_name -> google.protobuf.Timestamp + 52, // 8: gotocompany.optimus.core.v1beta1.RegisterJobEventRequest.event:type_name -> gotocompany.optimus.core.v1beta1.JobEvent + 51, // 9: gotocompany.optimus.core.v1beta1.JobRunInputRequest.scheduled_at:type_name -> google.protobuf.Timestamp 0, // 10: gotocompany.optimus.core.v1beta1.JobRunInputRequest.instance_type:type_name -> gotocompany.optimus.core.v1beta1.InstanceSpec.Type - 47, // 11: gotocompany.optimus.core.v1beta1.GetJobRunsRequest.since:type_name -> google.protobuf.Timestamp - 47, // 12: gotocompany.optimus.core.v1beta1.GetJobRunsRequest.until:type_name -> google.protobuf.Timestamp - 47, // 13: gotocompany.optimus.core.v1beta1.JobRunWithDetail.scheduled_at:type_name -> google.protobuf.Timestamp - 47, // 14: gotocompany.optimus.core.v1beta1.JobRunWithDetail.start_time:type_name -> google.protobuf.Timestamp - 47, // 15: gotocompany.optimus.core.v1beta1.JobRunWithDetail.end_time:type_name -> google.protobuf.Timestamp + 51, // 11: gotocompany.optimus.core.v1beta1.GetJobRunsRequest.since:type_name -> google.protobuf.Timestamp + 51, // 12: gotocompany.optimus.core.v1beta1.GetJobRunsRequest.until:type_name -> google.protobuf.Timestamp + 51, // 13: gotocompany.optimus.core.v1beta1.JobRunWithDetail.scheduled_at:type_name -> google.protobuf.Timestamp + 51, // 14: gotocompany.optimus.core.v1beta1.JobRunWithDetail.start_time:type_name -> google.protobuf.Timestamp + 51, // 15: gotocompany.optimus.core.v1beta1.JobRunWithDetail.end_time:type_name -> google.protobuf.Timestamp 15, // 16: gotocompany.optimus.core.v1beta1.GetJobRunsResponse.job_runs:type_name -> gotocompany.optimus.core.v1beta1.JobRunWithDetail - 47, // 17: gotocompany.optimus.core.v1beta1.JobRunRequest.start_date:type_name -> google.protobuf.Timestamp - 47, // 18: gotocompany.optimus.core.v1beta1.JobRunRequest.end_date:type_name -> google.protobuf.Timestamp - 49, // 19: gotocompany.optimus.core.v1beta1.JobRunResponse.job_runs:type_name -> gotocompany.optimus.core.v1beta1.JobRun + 51, // 17: gotocompany.optimus.core.v1beta1.JobRunRequest.start_date:type_name -> google.protobuf.Timestamp + 51, // 18: gotocompany.optimus.core.v1beta1.JobRunRequest.end_date:type_name -> google.protobuf.Timestamp + 53, // 19: gotocompany.optimus.core.v1beta1.JobRunResponse.job_runs:type_name -> gotocompany.optimus.core.v1beta1.JobRun 24, // 20: gotocompany.optimus.core.v1beta1.InstanceSpec.data:type_name -> gotocompany.optimus.core.v1beta1.InstanceSpecData - 47, // 21: gotocompany.optimus.core.v1beta1.InstanceSpec.executed_at:type_name -> google.protobuf.Timestamp + 51, // 21: gotocompany.optimus.core.v1beta1.InstanceSpec.executed_at:type_name -> google.protobuf.Timestamp 0, // 22: gotocompany.optimus.core.v1beta1.InstanceSpec.type:type_name -> gotocompany.optimus.core.v1beta1.InstanceSpec.Type 1, // 23: gotocompany.optimus.core.v1beta1.InstanceSpecData.type:type_name -> gotocompany.optimus.core.v1beta1.InstanceSpecData.Type - 42, // 24: gotocompany.optimus.core.v1beta1.JobRunInputResponse.envs:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.EnvsEntry - 43, // 25: gotocompany.optimus.core.v1beta1.JobRunInputResponse.files:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.FilesEntry - 44, // 26: gotocompany.optimus.core.v1beta1.JobRunInputResponse.secrets:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.SecretsEntry - 50, // 27: gotocompany.optimus.core.v1beta1.TaskWindow.size:type_name -> google.protobuf.Duration - 50, // 28: gotocompany.optimus.core.v1beta1.TaskWindow.offset:type_name -> google.protobuf.Duration + 44, // 24: gotocompany.optimus.core.v1beta1.JobRunInputResponse.envs:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.EnvsEntry + 45, // 25: gotocompany.optimus.core.v1beta1.JobRunInputResponse.files:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.FilesEntry + 46, // 26: gotocompany.optimus.core.v1beta1.JobRunInputResponse.secrets:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.SecretsEntry + 54, // 27: gotocompany.optimus.core.v1beta1.TaskWindow.size:type_name -> google.protobuf.Duration + 54, // 28: gotocompany.optimus.core.v1beta1.TaskWindow.offset:type_name -> google.protobuf.Duration 28, // 29: gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryRequest.target_jobs:type_name -> gotocompany.optimus.core.v1beta1.TargetJobRunIdentifier - 47, // 30: gotocompany.optimus.core.v1beta1.TargetJobRunIdentifier.scheduled_at:type_name -> google.protobuf.Timestamp + 51, // 30: gotocompany.optimus.core.v1beta1.TargetJobRunIdentifier.scheduled_at:type_name -> google.protobuf.Timestamp 30, // 31: gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryResponse.jobs:type_name -> gotocompany.optimus.core.v1beta1.JobRunLineageSummary - 47, // 32: gotocompany.optimus.core.v1beta1.JobRunLineageSummary.scheduled_at:type_name -> google.protobuf.Timestamp + 51, // 32: gotocompany.optimus.core.v1beta1.JobRunLineageSummary.scheduled_at:type_name -> google.protobuf.Timestamp 34, // 33: gotocompany.optimus.core.v1beta1.JobRunLineageSummary.job_runs:type_name -> gotocompany.optimus.core.v1beta1.JobExecutionSummary 31, // 34: gotocompany.optimus.core.v1beta1.JobRunLineageSummary.execution_summary:type_name -> gotocompany.optimus.core.v1beta1.LineageExecutionSummary 33, // 35: gotocompany.optimus.core.v1beta1.LineageExecutionSummary.largest_scheduled_way_too_late_job:type_name -> gotocompany.optimus.core.v1beta1.LineageDelaySummary 33, // 36: gotocompany.optimus.core.v1beta1.LineageExecutionSummary.largest_system_scheduling_delay_job:type_name -> gotocompany.optimus.core.v1beta1.LineageDelaySummary 32, // 37: gotocompany.optimus.core.v1beta1.LineageExecutionSummary.top_longest_task_duration_jobs:type_name -> gotocompany.optimus.core.v1beta1.JobWithTaskDuration 32, // 38: gotocompany.optimus.core.v1beta1.LineageExecutionSummary.top_longest_hook_duration_jobs:type_name -> gotocompany.optimus.core.v1beta1.JobWithTaskDuration - 47, // 39: gotocompany.optimus.core.v1beta1.LineageDelaySummary.scheduled_at:type_name -> google.protobuf.Timestamp - 47, // 40: gotocompany.optimus.core.v1beta1.LineageDelaySummary.upstream_scheduled_at:type_name -> google.protobuf.Timestamp + 51, // 39: gotocompany.optimus.core.v1beta1.LineageDelaySummary.scheduled_at:type_name -> google.protobuf.Timestamp + 51, // 40: gotocompany.optimus.core.v1beta1.LineageDelaySummary.upstream_scheduled_at:type_name -> google.protobuf.Timestamp 37, // 41: gotocompany.optimus.core.v1beta1.JobExecutionSummary.sla:type_name -> gotocompany.optimus.core.v1beta1.SLAConfig 35, // 42: gotocompany.optimus.core.v1beta1.JobExecutionSummary.job_run_summary:type_name -> gotocompany.optimus.core.v1beta1.JobRunSummary 36, // 43: gotocompany.optimus.core.v1beta1.JobExecutionSummary.delay_summary:type_name -> gotocompany.optimus.core.v1beta1.JobRunDelaySummary - 47, // 44: gotocompany.optimus.core.v1beta1.JobRunSummary.scheduled_at:type_name -> google.protobuf.Timestamp - 47, // 45: gotocompany.optimus.core.v1beta1.JobRunSummary.sla_time:type_name -> google.protobuf.Timestamp - 47, // 46: gotocompany.optimus.core.v1beta1.JobRunSummary.job_start_time:type_name -> google.protobuf.Timestamp - 47, // 47: gotocompany.optimus.core.v1beta1.JobRunSummary.job_end_time:type_name -> google.protobuf.Timestamp - 47, // 48: gotocompany.optimus.core.v1beta1.JobRunSummary.wait_start_time:type_name -> google.protobuf.Timestamp - 47, // 49: gotocompany.optimus.core.v1beta1.JobRunSummary.wait_end_time:type_name -> google.protobuf.Timestamp - 47, // 50: gotocompany.optimus.core.v1beta1.JobRunSummary.task_start_time:type_name -> google.protobuf.Timestamp - 47, // 51: gotocompany.optimus.core.v1beta1.JobRunSummary.task_end_time:type_name -> google.protobuf.Timestamp - 47, // 52: gotocompany.optimus.core.v1beta1.JobRunSummary.hook_start_time:type_name -> google.protobuf.Timestamp - 47, // 53: gotocompany.optimus.core.v1beta1.JobRunSummary.hook_end_time:type_name -> google.protobuf.Timestamp - 50, // 54: gotocompany.optimus.core.v1beta1.SLAConfig.duration:type_name -> google.protobuf.Duration - 45, // 55: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.job_labels:type_name -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.JobLabelsEntry - 47, // 56: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.reference_time:type_name -> google.protobuf.Timestamp - 46, // 57: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.jobs:type_name -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry - 47, // 58: gotocompany.optimus.core.v1beta1.UpstreamJobStatus.inferred_sla_time:type_name -> google.protobuf.Timestamp - 47, // 59: gotocompany.optimus.core.v1beta1.UpstreamJobStatus.scheduled_at:type_name -> google.protobuf.Timestamp + 51, // 44: gotocompany.optimus.core.v1beta1.JobRunSummary.scheduled_at:type_name -> google.protobuf.Timestamp + 51, // 45: gotocompany.optimus.core.v1beta1.JobRunSummary.sla_time:type_name -> google.protobuf.Timestamp + 51, // 46: gotocompany.optimus.core.v1beta1.JobRunSummary.job_start_time:type_name -> google.protobuf.Timestamp + 51, // 47: gotocompany.optimus.core.v1beta1.JobRunSummary.job_end_time:type_name -> google.protobuf.Timestamp + 51, // 48: gotocompany.optimus.core.v1beta1.JobRunSummary.wait_start_time:type_name -> google.protobuf.Timestamp + 51, // 49: gotocompany.optimus.core.v1beta1.JobRunSummary.wait_end_time:type_name -> google.protobuf.Timestamp + 51, // 50: gotocompany.optimus.core.v1beta1.JobRunSummary.task_start_time:type_name -> google.protobuf.Timestamp + 51, // 51: gotocompany.optimus.core.v1beta1.JobRunSummary.task_end_time:type_name -> google.protobuf.Timestamp + 51, // 52: gotocompany.optimus.core.v1beta1.JobRunSummary.hook_start_time:type_name -> google.protobuf.Timestamp + 51, // 53: gotocompany.optimus.core.v1beta1.JobRunSummary.hook_end_time:type_name -> google.protobuf.Timestamp + 54, // 54: gotocompany.optimus.core.v1beta1.SLAConfig.duration:type_name -> google.protobuf.Duration + 47, // 55: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.job_labels:type_name -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.JobLabelsEntry + 51, // 56: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.reference_time:type_name -> google.protobuf.Timestamp + 48, // 57: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.jobs:type_name -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry + 51, // 58: gotocompany.optimus.core.v1beta1.UpstreamJobStatus.inferred_sla_time:type_name -> google.protobuf.Timestamp + 51, // 59: gotocompany.optimus.core.v1beta1.UpstreamJobStatus.scheduled_at:type_name -> google.protobuf.Timestamp 40, // 60: gotocompany.optimus.core.v1beta1.UpstreamJobsStatus.jobs_status:type_name -> gotocompany.optimus.core.v1beta1.UpstreamJobStatus - 41, // 61: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.UpstreamJobsStatus - 13, // 62: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:input_type -> gotocompany.optimus.core.v1beta1.JobRunInputRequest - 17, // 63: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:input_type -> gotocompany.optimus.core.v1beta1.JobRunRequest - 19, // 64: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleRequest - 21, // 65: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleRequest - 14, // 66: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunsRequest - 5, // 67: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:input_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest - 11, // 68: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:input_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventRequest - 9, // 69: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:input_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerRequest - 7, // 70: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:input_type -> gotocompany.optimus.core.v1beta1.GetIntervalRequest - 27, // 71: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryRequest - 38, // 72: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:input_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest - 25, // 73: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:output_type -> gotocompany.optimus.core.v1beta1.JobRunInputResponse - 18, // 74: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:output_type -> gotocompany.optimus.core.v1beta1.JobRunResponse - 20, // 75: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleResponse - 22, // 76: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleResponse - 16, // 77: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunsResponse - 6, // 78: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:output_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorResponse - 12, // 79: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:output_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventResponse - 10, // 80: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:output_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerResponse - 8, // 81: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:output_type -> gotocompany.optimus.core.v1beta1.GetIntervalResponse - 29, // 82: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryResponse - 39, // 83: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:output_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse - 73, // [73:84] is the sub-list for method output_type - 62, // [62:73] is the sub-list for method input_type - 62, // [62:62] is the sub-list for extension type_name - 62, // [62:62] is the sub-list for extension extendee - 0, // [0:62] is the sub-list for field type_name + 49, // 61: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeRequest.job_labels:type_name -> gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeRequest.JobLabelsEntry + 51, // 62: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeRequest.reference_time:type_name -> google.protobuf.Timestamp + 50, // 63: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeResponse.jobs:type_name -> gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeResponse.JobsEntry + 41, // 64: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.UpstreamJobsStatus + 51, // 65: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeResponse.JobsEntry.value:type_name -> google.protobuf.Timestamp + 13, // 66: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:input_type -> gotocompany.optimus.core.v1beta1.JobRunInputRequest + 17, // 67: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:input_type -> gotocompany.optimus.core.v1beta1.JobRunRequest + 19, // 68: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleRequest + 21, // 69: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleRequest + 14, // 70: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunsRequest + 5, // 71: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:input_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest + 11, // 72: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:input_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventRequest + 9, // 73: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:input_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerRequest + 7, // 74: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:input_type -> gotocompany.optimus.core.v1beta1.GetIntervalRequest + 27, // 75: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryRequest + 38, // 76: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:input_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest + 42, // 77: gotocompany.optimus.core.v1beta1.JobRunService.GenerateEstimatedFinishTime:input_type -> gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeRequest + 25, // 78: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:output_type -> gotocompany.optimus.core.v1beta1.JobRunInputResponse + 18, // 79: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:output_type -> gotocompany.optimus.core.v1beta1.JobRunResponse + 20, // 80: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleResponse + 22, // 81: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleResponse + 16, // 82: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunsResponse + 6, // 83: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:output_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorResponse + 12, // 84: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:output_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventResponse + 10, // 85: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:output_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerResponse + 8, // 86: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:output_type -> gotocompany.optimus.core.v1beta1.GetIntervalResponse + 29, // 87: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryResponse + 39, // 88: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:output_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse + 43, // 89: gotocompany.optimus.core.v1beta1.JobRunService.GenerateEstimatedFinishTime:output_type -> gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeResponse + 78, // [78:90] is the sub-list for method output_type + 66, // [66:78] is the sub-list for method input_type + 66, // [66:66] is the sub-list for extension type_name + 66, // [66:66] is the sub-list for extension extendee + 0, // [0:66] is the sub-list for field type_name } func init() { file_gotocompany_optimus_core_v1beta1_job_run_proto_init() } @@ -4177,6 +4368,30 @@ func file_gotocompany_optimus_core_v1beta1_job_run_proto_init() { return nil } } + file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GenerateEstimatedFinishTimeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GenerateEstimatedFinishTimeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[3].OneofWrappers = []interface{}{ (*GetThirdPartySensorRequest_DexSensorRequest)(nil), @@ -4191,7 +4406,7 @@ func file_gotocompany_optimus_core_v1beta1_job_run_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_gotocompany_optimus_core_v1beta1_job_run_proto_rawDesc, NumEnums: 2, - NumMessages: 45, + NumMessages: 49, NumExtensions: 0, NumServices: 1, }, diff --git a/protos/gotocompany/optimus/core/v1beta1/job_run.pb.gw.go b/protos/gotocompany/optimus/core/v1beta1/job_run.pb.gw.go index 56278fc38f..966f67386a 100644 --- a/protos/gotocompany/optimus/core/v1beta1/job_run.pb.gw.go +++ b/protos/gotocompany/optimus/core/v1beta1/job_run.pb.gw.go @@ -935,6 +935,74 @@ func local_request_JobRunService_IdentifyPotentialSLABreach_0(ctx context.Contex } +func request_JobRunService_GenerateEstimatedFinishTime_0(ctx context.Context, marshaler runtime.Marshaler, client JobRunServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GenerateEstimatedFinishTimeRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["project_name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "project_name") + } + + protoReq.ProjectName, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project_name", err) + } + + msg, err := client.GenerateEstimatedFinishTime(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_JobRunService_GenerateEstimatedFinishTime_0(ctx context.Context, marshaler runtime.Marshaler, server JobRunServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GenerateEstimatedFinishTimeRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["project_name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "project_name") + } + + protoReq.ProjectName, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project_name", err) + } + + msg, err := server.GenerateEstimatedFinishTime(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterJobRunServiceHandlerServer registers the http handlers for service JobRunService to "mux". // UnaryRPC :call JobRunServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -1194,6 +1262,29 @@ func RegisterJobRunServiceHandlerServer(ctx context.Context, mux *runtime.ServeM }) + mux.Handle("POST", pattern_JobRunService_GenerateEstimatedFinishTime_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateEstimatedFinishTime", runtime.WithHTTPPathPattern("/v1beta1/project/{project_name}/estimate_job_finish_time")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_JobRunService_GenerateEstimatedFinishTime_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_JobRunService_GenerateEstimatedFinishTime_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1455,6 +1546,26 @@ func RegisterJobRunServiceHandlerClient(ctx context.Context, mux *runtime.ServeM }) + mux.Handle("POST", pattern_JobRunService_GenerateEstimatedFinishTime_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateEstimatedFinishTime", runtime.WithHTTPPathPattern("/v1beta1/project/{project_name}/estimate_job_finish_time")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_JobRunService_GenerateEstimatedFinishTime_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_JobRunService_GenerateEstimatedFinishTime_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1480,6 +1591,8 @@ var ( pattern_JobRunService_GetJobRunLineageSummary_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1beta1", "job-run-lineage-summary"}, "")) pattern_JobRunService_IdentifyPotentialSLABreach_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 2, 4}, []string{"v1beta1", "project", "project_name", "potential_sla_breach", "identify"}, "")) + + pattern_JobRunService_GenerateEstimatedFinishTime_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"v1beta1", "project", "project_name", "estimate_job_finish_time"}, "")) ) var ( @@ -1504,4 +1617,6 @@ var ( forward_JobRunService_GetJobRunLineageSummary_0 = runtime.ForwardResponseMessage forward_JobRunService_IdentifyPotentialSLABreach_0 = runtime.ForwardResponseMessage + + forward_JobRunService_GenerateEstimatedFinishTime_0 = runtime.ForwardResponseMessage ) diff --git a/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json b/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json index c8989f2e5b..2c3888e2d7 100644 --- a/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json +++ b/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json @@ -54,6 +54,67 @@ ] } }, + "/v1beta1/project/{projectName}/estimate_job_finish_time": { + "post": { + "summary": "GenerateEstimatedFinishTime generates and stores the estimated finish time for a given job(s)", + "operationId": "JobRunService_GenerateEstimatedFinishTime", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1GenerateEstimatedFinishTimeResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "projectName", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "jobNames": { + "type": "array", + "items": { + "type": "string" + } + }, + "jobLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "scheduledRangeInHours": { + "type": "integer", + "format": "int32" + }, + "referenceTime": { + "type": "string", + "format": "date-time" + } + } + } + } + ], + "tags": [ + "JobRunService" + ] + } + }, "/v1beta1/project/{projectName}/job/{jobName}/interval": { "get": { "summary": "GetInterval gets interval on specific job given reference time.", @@ -627,7 +688,7 @@ "NULL_VALUE" ], "default": "NULL_VALUE", - "description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\nThe JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value." + "description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value." }, "rpcStatus": { "type": "object", @@ -684,6 +745,18 @@ } } }, + "v1beta1GenerateEstimatedFinishTimeResponse": { + "type": "object", + "properties": { + "jobs": { + "type": "object", + "additionalProperties": { + "type": "string", + "format": "date-time" + } + } + } + }, "v1beta1GetIntervalResponse": { "type": "object", "properties": { diff --git a/protos/gotocompany/optimus/core/v1beta1/job_run_grpc.pb.go b/protos/gotocompany/optimus/core/v1beta1/job_run_grpc.pb.go index 82fff29d61..d50c1b9c47 100644 --- a/protos/gotocompany/optimus/core/v1beta1/job_run_grpc.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/job_run_grpc.pb.go @@ -43,6 +43,8 @@ type JobRunServiceClient interface { GetJobRunLineageSummary(ctx context.Context, in *GetJobRunLineageSummaryRequest, opts ...grpc.CallOption) (*GetJobRunLineageSummaryResponse, error) // IdentifyPotentialSLABreach notifies optimus service about potential SLA breach for given job(s) IdentifyPotentialSLABreach(ctx context.Context, in *IdentifyPotentialSLABreachRequest, opts ...grpc.CallOption) (*IdentifyPotentialSLABreachResponse, error) + // GenerateEstimatedFinishTime generates and stores the estimated finish time for a given job(s) + GenerateEstimatedFinishTime(ctx context.Context, in *GenerateEstimatedFinishTimeRequest, opts ...grpc.CallOption) (*GenerateEstimatedFinishTimeResponse, error) } type jobRunServiceClient struct { @@ -152,6 +154,15 @@ func (c *jobRunServiceClient) IdentifyPotentialSLABreach(ctx context.Context, in return out, nil } +func (c *jobRunServiceClient) GenerateEstimatedFinishTime(ctx context.Context, in *GenerateEstimatedFinishTimeRequest, opts ...grpc.CallOption) (*GenerateEstimatedFinishTimeResponse, error) { + out := new(GenerateEstimatedFinishTimeResponse) + err := c.cc.Invoke(ctx, "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateEstimatedFinishTime", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // JobRunServiceServer is the server API for JobRunService service. // All implementations must embed UnimplementedJobRunServiceServer // for forward compatibility @@ -177,6 +188,8 @@ type JobRunServiceServer interface { GetJobRunLineageSummary(context.Context, *GetJobRunLineageSummaryRequest) (*GetJobRunLineageSummaryResponse, error) // IdentifyPotentialSLABreach notifies optimus service about potential SLA breach for given job(s) IdentifyPotentialSLABreach(context.Context, *IdentifyPotentialSLABreachRequest) (*IdentifyPotentialSLABreachResponse, error) + // GenerateEstimatedFinishTime generates and stores the estimated finish time for a given job(s) + GenerateEstimatedFinishTime(context.Context, *GenerateEstimatedFinishTimeRequest) (*GenerateEstimatedFinishTimeResponse, error) mustEmbedUnimplementedJobRunServiceServer() } @@ -217,6 +230,9 @@ func (UnimplementedJobRunServiceServer) GetJobRunLineageSummary(context.Context, func (UnimplementedJobRunServiceServer) IdentifyPotentialSLABreach(context.Context, *IdentifyPotentialSLABreachRequest) (*IdentifyPotentialSLABreachResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method IdentifyPotentialSLABreach not implemented") } +func (UnimplementedJobRunServiceServer) GenerateEstimatedFinishTime(context.Context, *GenerateEstimatedFinishTimeRequest) (*GenerateEstimatedFinishTimeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenerateEstimatedFinishTime not implemented") +} func (UnimplementedJobRunServiceServer) mustEmbedUnimplementedJobRunServiceServer() {} // UnsafeJobRunServiceServer may be embedded to opt out of forward compatibility for this service. @@ -428,6 +444,24 @@ func _JobRunService_IdentifyPotentialSLABreach_Handler(srv interface{}, ctx cont return interceptor(ctx, in, info, handler) } +func _JobRunService_GenerateEstimatedFinishTime_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GenerateEstimatedFinishTimeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(JobRunServiceServer).GenerateEstimatedFinishTime(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateEstimatedFinishTime", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(JobRunServiceServer).GenerateEstimatedFinishTime(ctx, req.(*GenerateEstimatedFinishTimeRequest)) + } + return interceptor(ctx, in, info, handler) +} + // JobRunService_ServiceDesc is the grpc.ServiceDesc for JobRunService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -479,6 +513,10 @@ var JobRunService_ServiceDesc = grpc.ServiceDesc{ MethodName: "IdentifyPotentialSLABreach", Handler: _JobRunService_IdentifyPotentialSLABreach_Handler, }, + { + MethodName: "GenerateEstimatedFinishTime", + Handler: _JobRunService_GenerateEstimatedFinishTime_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "gotocompany/optimus/core/v1beta1/job_run.proto", diff --git a/protos/gotocompany/optimus/core/v1beta1/job_spec.pb.go b/protos/gotocompany/optimus/core/v1beta1/job_spec.pb.go index 87f3ef6e15..ef67eb0c97 100644 --- a/protos/gotocompany/optimus/core/v1beta1/job_spec.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/job_spec.pb.go @@ -6779,11 +6779,11 @@ var file_gotocompany_optimus_core_v1beta1_job_spec_proto_rawDesc = []byte{ 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4b, - 0x3a, 0x01, 0x2a, 0x22, 0x46, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, - 0x6a, 0x6f, 0x62, 0x2f, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x12, 0xe6, 0x01, 0x0a, 0x16, + 0x22, 0x46, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, + 0x2f, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xe6, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, @@ -6794,11 +6794,11 @@ var file_gotocompany_optimus_core_v1beta1_job_spec_proto_rawDesc = []byte{ 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x49, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x43, 0x3a, 0x01, 0x2a, 0x22, 0x3e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, - 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x2f, 0x6a, 0x6f, 0x62, 0x12, 0xe1, 0x01, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x4a, 0x6f, 0x62, 0x53, + 0x43, 0x22, 0x3e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, + 0x62, 0x3a, 0x01, 0x2a, 0x12, 0xe1, 0x01, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3d, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, @@ -6808,11 +6808,11 @@ var file_gotocompany_optimus_core_v1beta1_job_spec_proto_rawDesc = []byte{ 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4a, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x44, 0x3a, 0x01, 0x2a, 0x22, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0xea, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, + 0xe4, 0x93, 0x02, 0x44, 0x22, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, + 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, + 0x2f, 0x6a, 0x6f, 0x62, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0xea, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x40, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, @@ -6823,11 +6823,11 @@ var file_gotocompany_optimus_core_v1beta1_job_spec_proto_rawDesc = []byte{ 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4a, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x44, 0x3a, 0x01, 0x2a, 0x1a, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, - 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x2f, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0xf1, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, + 0x44, 0x1a, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, + 0x62, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0xf1, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x40, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, @@ -6837,12 +6837,12 @@ var file_gotocompany_optimus_core_v1beta1_job_spec_proto_rawDesc = []byte{ 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4b, 0x3a, 0x01, - 0x2a, 0x22, 0x46, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, - 0x62, 0x73, 0x2d, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0xe5, 0x01, 0x0a, 0x13, 0x47, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4b, 0x22, 0x46, + 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x73, 0x2d, + 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xe5, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, @@ -6905,10 +6905,10 @@ var file_gotocompany_optimus_core_v1beta1_job_spec_proto_rawDesc = []byte{ 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x3a, 0x01, 0x2a, 0x22, 0x34, 0x2f, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x2d, 0x6a, 0x6f, 0x62, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x22, 0x34, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x6a, + 0x6f, 0x62, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0xdd, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, @@ -6954,11 +6954,11 @@ var file_gotocompany_optimus_core_v1beta1_job_spec_proto_rawDesc = []byte{ 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x4c, 0x3a, 0x01, 0x2a, 0x22, 0x47, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, - 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x7e, 0x0a, + 0x4c, 0x22, 0x47, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, + 0x62, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x7e, 0x0a, 0x0b, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, @@ -7018,12 +7018,12 @@ var file_gotocompany_optimus_core_v1beta1_job_spec_proto_rawDesc = []byte{ 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x50, 0x3a, 0x01, 0x2a, - 0x32, 0x4b, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x2d, 0x6a, 0x6f, 0x62, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0xd6, 0x01, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x50, 0x32, 0x4b, 0x2f, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, + 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x2d, 0x6a, 0x6f, 0x62, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0xd6, 0x01, 0x0a, 0x0d, 0x53, 0x79, 0x6e, 0x63, 0x4a, 0x6f, 0x62, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x36, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, @@ -7032,12 +7032,12 @@ var file_gotocompany_optimus_core_v1beta1_job_spec_proto_rawDesc = []byte{ 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4a, 0x6f, 0x62, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x54, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4e, 0x3a, 0x01, 0x2a, 0x32, 0x49, 0x2f, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x6a, 0x6f, 0x62, - 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0xbc, 0x01, 0x0a, 0x0e, 0x42, 0x75, 0x6c, 0x6b, 0x44, + 0x22, 0x54, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4e, 0x32, 0x49, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x2d, 0x6a, 0x6f, 0x62, 0x2d, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0xbc, 0x01, 0x0a, 0x0e, 0x42, 0x75, 0x6c, 0x6b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x37, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x42, 0x75, 0x6c, diff --git a/protos/gotocompany/optimus/core/v1beta1/namespace.pb.go b/protos/gotocompany/optimus/core/v1beta1/namespace.pb.go index 5c03eba229..a98c45b6de 100644 --- a/protos/gotocompany/optimus/core/v1beta1/namespace.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/namespace.pb.go @@ -479,10 +479,10 @@ var file_gotocompany_optimus_core_v1beta1_namespace_proto_rawDesc = []byte{ 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x3a, 0x01, 0x2a, 0x22, 0x29, 0x2f, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x12, 0xcb, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x22, 0x29, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x3a, 0x01, 0x2a, 0x12, 0xcb, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x3e, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, diff --git a/protos/gotocompany/optimus/core/v1beta1/project.pb.go b/protos/gotocompany/optimus/core/v1beta1/project.pb.go index 1fed34fb68..605cf48b99 100644 --- a/protos/gotocompany/optimus/core/v1beta1/project.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/project.pb.go @@ -566,8 +566,8 @@ var file_gotocompany_optimus_core_v1beta1_project_proto_rawDesc = []byte{ 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x97, + 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x97, 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x35, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, diff --git a/protos/gotocompany/optimus/core/v1beta1/replay.pb.go b/protos/gotocompany/optimus/core/v1beta1/replay.pb.go index 11e7292d3b..e4c7af56af 100644 --- a/protos/gotocompany/optimus/core/v1beta1/replay.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/replay.pb.go @@ -1095,10 +1095,10 @@ var file_gotocompany_optimus_core_v1beta1_replay_proto_rawDesc = []byte{ 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x3a, 0x01, 0x2a, - 0x22, 0x26, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x12, 0xb8, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x70, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x26, 0x2f, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, + 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, + 0x65, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0xb8, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x35, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x70, @@ -1107,10 +1107,10 @@ var file_gotocompany_optimus_core_v1beta1_replay_proto_rawDesc = []byte{ 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x33, - 0x3a, 0x01, 0x2a, 0x22, 0x2e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x2d, 0x64, 0x72, 0x79, 0x2d, - 0x72, 0x75, 0x6e, 0x12, 0xa7, 0x01, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, + 0x22, 0x2e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x2d, 0x64, 0x72, 0x79, 0x2d, 0x72, 0x75, 0x6e, + 0x3a, 0x01, 0x2a, 0x12, 0xa7, 0x01, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x12, 0x33, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, diff --git a/protos/gotocompany/optimus/core/v1beta1/resource.pb.go b/protos/gotocompany/optimus/core/v1beta1/resource.pb.go index 35963997aa..2174680281 100644 --- a/protos/gotocompany/optimus/core/v1beta1/resource.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/resource.pb.go @@ -2020,13 +2020,13 @@ var file_gotocompany_optimus_core_v1beta1_resource_proto_rawDesc = []byte{ 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x59, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x53, 0x3a, - 0x01, 0x2a, 0x22, 0x4e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x65, - 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2f, 0x73, 0x79, - 0x6e, 0x63, 0x12, 0xee, 0x01, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x59, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x53, 0x22, + 0x4e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, + 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x65, 0x78, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x3a, + 0x01, 0x2a, 0x12, 0xee, 0x01, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x37, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, @@ -2035,13 +2035,13 @@ var file_gotocompany_optimus_core_v1beta1_resource_proto_rawDesc = []byte{ 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x69, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x63, - 0x3a, 0x01, 0x2a, 0x22, 0x5e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, - 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0xf5, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, + 0x22, 0x5e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, + 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x3a, 0x01, 0x2a, 0x12, 0xf5, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x35, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, @@ -2065,13 +2065,13 @@ var file_gotocompany_optimus_core_v1beta1_resource_proto_rawDesc = []byte{ 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x69, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x63, 0x3a, 0x01, 0x2a, 0x1a, 0x5e, 0x2f, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0xf6, 0x01, 0x0a, + 0x65, 0x22, 0x69, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x63, 0x1a, 0x5e, 0x2f, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, + 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, + 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0xf6, 0x01, 0x0a, 0x0e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x37, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, @@ -2080,14 +2080,14 @@ var file_gotocompany_optimus_core_v1beta1_resource_proto_rawDesc = []byte{ 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x71, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x6b, 0x3a, 0x01, 0x2a, 0x22, 0x66, 0x2f, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, - 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2d, 0x75, - 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0xfb, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x73, 0x65, 0x22, 0x71, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x6b, 0x22, 0x66, 0x2f, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2d, 0x75, 0x70, 0x73, 0x65, + 0x72, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xfb, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x37, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, @@ -2113,11 +2113,11 @@ var file_gotocompany_optimus_core_v1beta1_resource_proto_rawDesc = []byte{ 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3e, 0x3a, 0x01, 0x2a, 0x22, - 0x39, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0xf5, 0x01, 0x0a, 0x0e, 0x41, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3e, 0x22, 0x39, 0x2f, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2d, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0xf5, 0x01, 0x0a, 0x0e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x37, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, @@ -2126,14 +2126,14 @@ var file_gotocompany_optimus_core_v1beta1_resource_proto_rawDesc = []byte{ 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x70, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x6a, 0x3a, 0x01, 0x2a, 0x22, 0x65, 0x2f, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2d, 0x61, 0x70, 0x70, - 0x6c, 0x79, 0x12, 0xe4, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x22, 0x70, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x6a, 0x22, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, + 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2d, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x3a, + 0x01, 0x2a, 0x12, 0xe4, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x3e, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, diff --git a/protos/gotocompany/optimus/core/v1beta1/resource.swagger.json b/protos/gotocompany/optimus/core/v1beta1/resource.swagger.json index 42dd06cf88..bc03fb54af 100644 --- a/protos/gotocompany/optimus/core/v1beta1/resource.swagger.json +++ b/protos/gotocompany/optimus/core/v1beta1/resource.swagger.json @@ -568,7 +568,7 @@ "NULL_VALUE" ], "default": "NULL_VALUE", - "description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\nThe JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value." + "description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value." }, "rpcStatus": { "type": "object", diff --git a/protos/gotocompany/optimus/core/v1beta1/runtime.pb.go b/protos/gotocompany/optimus/core/v1beta1/runtime.pb.go index dc73639783..0131905a36 100644 --- a/protos/gotocompany/optimus/core/v1beta1/runtime.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/runtime.pb.go @@ -143,8 +143,8 @@ var file_gotocompany_optimus_core_v1beta1_runtime_proto_rawDesc = []byte{ 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x97, 0x01, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, + 0x15, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x3a, 0x01, 0x2a, 0x42, 0x97, 0x01, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x42, 0x15, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, diff --git a/protos/gotocompany/optimus/core/v1beta1/secret.pb.go b/protos/gotocompany/optimus/core/v1beta1/secret.pb.go index 78f21eb830..7b866db77d 100644 --- a/protos/gotocompany/optimus/core/v1beta1/secret.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/secret.pb.go @@ -583,11 +583,11 @@ var file_gotocompany_optimus_core_v1beta1_secret_proto_rawDesc = []byte{ 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x3a, 0x01, 0x2a, 0x22, 0x34, 0x2f, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, - 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x2f, 0x7b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x7d, 0x12, 0xbe, 0x01, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, + 0x73, 0x65, 0x22, 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x22, 0x34, 0x2f, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x65, 0x63, 0x72, + 0x65, 0x74, 0x2f, 0x7b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, + 0x3a, 0x01, 0x2a, 0x12, 0xbe, 0x01, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x35, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, @@ -595,11 +595,11 @@ var file_gotocompany_optimus_core_v1beta1_secret_proto_rawDesc = []byte{ 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x3a, 0x01, 0x2a, 0x1a, 0x34, - 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, - 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x2f, 0x7b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xaa, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, + 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x1a, 0x34, 0x2f, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x2f, 0x7b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x3a, 0x01, 0x2a, 0x12, 0xaa, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x72, From de2e950529074fd270cf890df9e04e9fb930d2d1 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Mon, 9 Feb 2026 15:41:55 +0700 Subject: [PATCH 06/26] feat: add handler to generate estimated finish time --- core/scheduler/handler/v1beta1/job_run.go | 45 +++++++++++++++++++ .../service/job_estimator_service.go | 14 +++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/core/scheduler/handler/v1beta1/job_run.go b/core/scheduler/handler/v1beta1/job_run.go index e8ec811a6a..74e9df9100 100644 --- a/core/scheduler/handler/v1beta1/job_run.go +++ b/core/scheduler/handler/v1beta1/job_run.go @@ -37,6 +37,10 @@ type JobSLAPredictorService interface { IdentifySLABreaches(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string, reqConfig service.JobSLAPredictorRequestConfig) (map[scheduler.JobName]map[scheduler.JobName]*service.JobState, error) } +type JobEstimatorService interface { + GenerateEstimatedFinishTimes(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string, referenceTime time.Time, scheduleRangeInHours time.Duration) (map[scheduler.JobSchedule]time.Time, error) +} + type JobRunService interface { JobRunInput(context.Context, tenant.ProjectName, scheduler.JobName, scheduler.RunConfig) (*scheduler.ExecutorInput, error) UpdateJobState(context.Context, *scheduler.Event) error @@ -73,6 +77,7 @@ type JobRunHandler struct { jobLineageService JobLineageService jobSLAPredictorService JobSLAPredictorService thirdPartySensorService ThirdPartySensorService + jobEstimatorService JobEstimatorService pb.UnimplementedJobRunServiceServer } @@ -574,6 +579,46 @@ func (h JobRunHandler) GetJobRunLineageSummary(ctx context.Context, req *pb.GetJ return toJobRunLineageSummaryResponse(jobRunLineages), nil } +// GenerateEstimatedFinishTime generates estimated finish time for jobs based on their schedule in the given range +func (h JobRunHandler) GenerateEstimatedFinishTime(ctx context.Context, req *pb.GenerateEstimatedFinishTimeRequest) (*pb.GenerateEstimatedFinishTimeResponse, error) { + projectName, err := tenant.ProjectNameFrom(req.GetProjectName()) + if err != nil { + h.l.Error("error adapting project name [%s]: %s", req.GetProjectName(), err) + return nil, errors.GRPCErr(err, "unable to adapt project name") + } + + jobNames := []scheduler.JobName{} + for _, jn := range req.GetJobNames() { + jobName, err := scheduler.JobNameFrom(jn) + if err != nil { + h.l.Error("error adapting job name [%s]: %s", jn, err) + return nil, errors.GRPCErr(err, "unable to adapt job name") + } + jobNames = append(jobNames, jobName) + } + + referenceTime := time.Now().UTC() + if req.GetReferenceTime() != nil && req.GetReferenceTime().IsValid() { + referenceTime = req.GetReferenceTime().AsTime().UTC() + } + scheduleRangeInHours := time.Duration(req.GetScheduledRangeInHours()) * time.Hour + + estimatedFinishTimes, err := h.jobEstimatorService.GenerateEstimatedFinishTimes(ctx, projectName, jobNames, req.GetJobLabels(), referenceTime, scheduleRangeInHours) + if err != nil { + h.l.Error("error generating estimated finish times: %s", err) + return nil, errors.GRPCErr(err, "unable to generate estimated finish times") + } + + response := &pb.GenerateEstimatedFinishTimeResponse{ + Jobs: make(map[string]*timestamppb.Timestamp), + } + for jobSchedule, estimatedFinishTime := range estimatedFinishTimes { + response.Jobs[jobSchedule.JobName.String()] = timestamppb.New(estimatedFinishTime) + } + + return response, nil +} + func NewJobRunHandler( l log.Logger, service JobRunService, diff --git a/core/scheduler/service/job_estimator_service.go b/core/scheduler/service/job_estimator_service.go index 67f7c0582d..b96249c2c2 100644 --- a/core/scheduler/service/job_estimator_service.go +++ b/core/scheduler/service/job_estimator_service.go @@ -109,7 +109,19 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, } } - return jobRunEstimatedFinishTimes, nil + // estimated finish time generated for target jobs + finalJobRunEstimatedFinishTimes := make(map[scheduler.JobSchedule]time.Time) + for _, jobSchedule := range jobSchedules { + key := *jobSchedule + estimatedFinishTime, ok := jobRunEstimatedFinishTimes[key] + if !ok { + s.l.Warn("estimated finish time not found for job schedule", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) + continue + } + finalJobRunEstimatedFinishTimes[key] = estimatedFinishTime + } + + return finalJobRunEstimatedFinishTimes, nil } func (s *JobEstimatorService) populateEstimatedFinishTime(ctx context.Context, jobTarget, jobSchedule *scheduler.JobSchedule, jobRunEstimatedFinishTimes map[scheduler.JobSchedule]time.Time, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { From 6a8fe59031f52787c691c7641fc5991a43046097 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Mon, 9 Feb 2026 16:00:56 +0700 Subject: [PATCH 07/26] feat: integrate job finish time estimator service --- core/scheduler/handler/v1beta1/job_run.go | 2 + .../scheduler/handler/v1beta1/job_run_test.go | 74 +++++++++---------- server/optimus.go | 6 +- 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/core/scheduler/handler/v1beta1/job_run.go b/core/scheduler/handler/v1beta1/job_run.go index 74e9df9100..7eab51e79f 100644 --- a/core/scheduler/handler/v1beta1/job_run.go +++ b/core/scheduler/handler/v1beta1/job_run.go @@ -627,6 +627,7 @@ func NewJobRunHandler( jobLineageService JobLineageService, jobSLAPredictorService JobSLAPredictorService, thirdPartySensorService ThirdPartySensorService, + jobEstimatorService JobEstimatorService, ) *JobRunHandler { return &JobRunHandler{ l: l, @@ -636,5 +637,6 @@ func NewJobRunHandler( jobLineageService: jobLineageService, jobSLAPredictorService: jobSLAPredictorService, thirdPartySensorService: thirdPartySensorService, + jobEstimatorService: jobEstimatorService, } } diff --git a/core/scheduler/handler/v1beta1/job_run_test.go b/core/scheduler/handler/v1beta1/job_run_test.go index 7117b8e5da..bae4cd864c 100644 --- a/core/scheduler/handler/v1beta1/job_run_test.go +++ b/core/scheduler/handler/v1beta1/job_run_test.go @@ -37,7 +37,7 @@ func TestJobRunHandler(t *testing.T) { t.Run("GetJobRun", func(t *testing.T) { t.Run("should return error if project name is invalid", func(t *testing.T) { - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) req := &pb.GetJobRunsRequest{ ProjectName: "", JobName: "job1", @@ -52,7 +52,7 @@ func TestJobRunHandler(t *testing.T) { }) t.Run("should return error if job name is invalid", func(t *testing.T) { - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) req := &pb.GetJobRunsRequest{ ProjectName: "proj", JobName: "", @@ -67,7 +67,7 @@ func TestJobRunHandler(t *testing.T) { }) t.Run("should return error if state is invalid", func(t *testing.T) { - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) req := &pb.GetJobRunsRequest{ ProjectName: "proj", JobName: "job1", @@ -93,7 +93,7 @@ func TestJobRunHandler(t *testing.T) { Return(jobRuns, nil) defer jobRunService.AssertExpectations(t) - jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, nil) req := &pb.GetJobRunsRequest{ ProjectName: "proj", JobName: "job1", @@ -126,7 +126,7 @@ func TestJobRunHandler(t *testing.T) { Return(jobRuns, fmt.Errorf("service error")) defer jobRunService.AssertExpectations(t) - jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, nil) req := &pb.GetJobRunsRequest{ ProjectName: "proj", JobName: "job1", @@ -144,7 +144,7 @@ func TestJobRunHandler(t *testing.T) { t.Run("JobRunInput", func(t *testing.T) { t.Run("returns error when project name is invalid", func(t *testing.T) { service := new(mockJobRunService) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) inputRequest := pb.JobRunInputRequest{ ProjectName: "", @@ -162,7 +162,7 @@ func TestJobRunHandler(t *testing.T) { }) t.Run("returns error when job name is invalid", func(t *testing.T) { service := new(mockJobRunService) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) inputRequest := pb.JobRunInputRequest{ ProjectName: "proj", @@ -180,7 +180,7 @@ func TestJobRunHandler(t *testing.T) { }) t.Run("returns error when executor is invalid", func(t *testing.T) { service := new(mockJobRunService) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) inputRequest := pb.JobRunInputRequest{ ProjectName: "proj", @@ -198,7 +198,7 @@ func TestJobRunHandler(t *testing.T) { }) t.Run("returns error when scheduled_at is invalid", func(t *testing.T) { service := new(mockJobRunService) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) inputRequest := pb.JobRunInputRequest{ ProjectName: "proj", @@ -215,7 +215,7 @@ func TestJobRunHandler(t *testing.T) { }) t.Run("returns error when run config is invalid", func(t *testing.T) { service := new(mockJobRunService) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) inputRequest := pb.JobRunInputRequest{ ProjectName: "proj", @@ -237,7 +237,7 @@ func TestJobRunHandler(t *testing.T) { Return(&scheduler.ExecutorInput{}, fmt.Errorf("error in service")) defer service.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) inputRequest := pb.JobRunInputRequest{ ProjectName: "proj", @@ -263,7 +263,7 @@ func TestJobRunHandler(t *testing.T) { }, nil) defer service.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) inputRequest := pb.JobRunInputRequest{ ProjectName: "proj", @@ -327,7 +327,7 @@ func TestJobRunHandler(t *testing.T) { jobRunService.On("GetInterval", ctx, tenant.ProjectName(projectName), scheduler.JobName(jobName), jobScheduleTime).Return(dataInterval, nil) defer jobRunService.AssertExpectations(t) - jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, thirdPartySensorService) + jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, thirdPartySensorService, nil) req := &pb.GetThirdPartySensorRequest{ ThirdPartyType: upstreamResolverType.String(), @@ -393,7 +393,7 @@ func TestJobRunHandler(t *testing.T) { jobRunService.On("GetInterval", ctx, tenant.ProjectName(projectName), scheduler.JobName(jobName), jobScheduleTime).Return(dataInterval, nil) defer jobRunService.AssertExpectations(t) - jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, thirdPartySensorService) + jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, thirdPartySensorService, nil) req := &pb.GetThirdPartySensorRequest{ ThirdPartyType: upstreamResolverType.String(), @@ -440,7 +440,7 @@ func TestJobRunHandler(t *testing.T) { jobRunService.On("GetJobRuns", ctx, tenant.ProjectName(projectName), job.Name, query).Return(jobRuns, "", nil) defer jobRunService.AssertExpectations(t) - jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, nil) req := &pb.JobRunRequest{ ProjectName: projectName, @@ -485,7 +485,7 @@ func TestJobRunHandler(t *testing.T) { jobRunService.On("GetJobRuns", ctx, tenant.ProjectName(projectName), job.Name, query).Return(jobRuns, "", nil) defer jobRunService.AssertExpectations(t) - jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, nil) req := &pb.JobRunRequest{ ProjectName: projectName, @@ -523,7 +523,7 @@ func TestJobRunHandler(t *testing.T) { jobRunService.On("GetJobRuns", ctx, tenant.ProjectName(projectName), job.Name, query).Return(nil, "", fmt.Errorf("some random error")) defer jobRunService.AssertExpectations(t) - jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, nil) req := &pb.JobRunRequest{ ProjectName: projectName, @@ -537,7 +537,7 @@ func TestJobRunHandler(t *testing.T) { }) t.Run("should not return job runs if project name is not valid", func(t *testing.T) { - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) req := &pb.JobRunRequest{ ProjectName: "", JobName: "transform-tables", @@ -552,7 +552,7 @@ func TestJobRunHandler(t *testing.T) { }) t.Run("should not return job runs if job name is not valid", func(t *testing.T) { - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) req := &pb.JobRunRequest{ ProjectName: "some-project", JobName: "", @@ -566,7 +566,7 @@ func TestJobRunHandler(t *testing.T) { assert.Nil(t, resp) }) t.Run("should not return job runs if only start date is invalid", func(t *testing.T) { - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) req := &pb.JobRunRequest{ ProjectName: "some-project", JobName: "jobname", @@ -579,7 +579,7 @@ func TestJobRunHandler(t *testing.T) { assert.Nil(t, resp) }) t.Run("should not return job runs if only end date is invalid", func(t *testing.T) { - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) req := &pb.JobRunRequest{ ProjectName: "some-project", JobName: "jobname", @@ -594,7 +594,7 @@ func TestJobRunHandler(t *testing.T) { }) t.Run("UploadToScheduler", func(t *testing.T) { t.Run("should fail deployment if project name empty", func(t *testing.T) { - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) namespaceName := "namespace-name" req := &pb.UploadToSchedulerRequest{ ProjectName: "", @@ -613,7 +613,7 @@ func TestJobRunHandler(t *testing.T) { } jobRunService := new(mockJobRunService) jobRunService.On("UploadToScheduler", ctx, tenant.ProjectName(projectName)).Return(nil) - jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, nil) _, err := jobRunHandler.UploadToScheduler(ctx, req) assert.Nil(t, err) @@ -634,7 +634,7 @@ func TestJobRunHandler(t *testing.T) { Value: eventValues, }, } - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) resp, err := jobRunHandler.RegisterJobEvent(ctx, req) assert.NotNil(t, err) @@ -658,7 +658,7 @@ func TestJobRunHandler(t *testing.T) { Value: eventValues, }, } - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) resp, err := jobRunHandler.RegisterJobEvent(ctx, req) assert.NotNil(t, err) @@ -681,7 +681,7 @@ func TestJobRunHandler(t *testing.T) { Value: eventValues, }, } - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) resp, err := jobRunHandler.RegisterJobEvent(ctx, req) assert.NotNil(t, err) @@ -705,7 +705,7 @@ func TestJobRunHandler(t *testing.T) { Value: eventValues, }, } - jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, nil, nil, nil, nil, nil, nil, nil) resp, err := jobRunHandler.RegisterJobEvent(ctx, req) assert.NotNil(t, err) @@ -756,7 +756,7 @@ func TestJobRunHandler(t *testing.T) { notifier.On("Relay", ctx, event).Return(nil) defer jobRunService.AssertExpectations(t) - jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, notifier, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, notifier, nil, nil, nil, nil, nil) resp, err := jobRunHandler.RegisterJobEvent(ctx, req) assert.NotNil(t, err) @@ -807,7 +807,7 @@ func TestJobRunHandler(t *testing.T) { notifier.On("Relay", ctx, event).Return(nil) defer jobRunService.AssertExpectations(t) - jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, notifier, nil, nil, nil, nil) + jobRunHandler := v1beta1.NewJobRunHandler(logger, jobRunService, notifier, nil, nil, nil, nil, nil) resp, err := jobRunHandler.RegisterJobEvent(ctx, req) assert.NotNil(t, err) @@ -822,7 +822,7 @@ func TestJobRunHandler(t *testing.T) { service := new(mockJobRunService) defer service.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) request := &pb.GetIntervalRequest{ ProjectName: "", JobName: "test_job", @@ -840,7 +840,7 @@ func TestJobRunHandler(t *testing.T) { service := new(mockJobRunService) defer service.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) request := &pb.GetIntervalRequest{ ProjectName: "test_project", JobName: "", @@ -858,7 +858,7 @@ func TestJobRunHandler(t *testing.T) { service := new(mockJobRunService) defer service.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) request := &pb.GetIntervalRequest{ ProjectName: "test_project", JobName: "test_job", @@ -876,7 +876,7 @@ func TestJobRunHandler(t *testing.T) { service := new(mockJobRunService) defer service.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) request := &pb.GetIntervalRequest{ ProjectName: "test_project", JobName: "test_job", @@ -932,7 +932,7 @@ func TestJobRunHandler(t *testing.T) { assert.NotNil(t, interval) assert.NoError(t, err) - handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, service, nil, nil, nil, nil, nil, nil) request := &pb.GetIntervalRequest{ ProjectName: "test_project", JobName: "test_job", @@ -955,7 +955,7 @@ func TestJobRunHandler(t *testing.T) { defer jobRunService.AssertExpectations(t) defer jobLineageService.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, jobLineageService, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, jobLineageService, nil, nil, nil) req := &pb.GetJobRunLineageSummaryRequest{ TargetJobs: []*pb.TargetJobRunIdentifier{ @@ -979,7 +979,7 @@ func TestJobRunHandler(t *testing.T) { defer jobRunService.AssertExpectations(t) defer jobLineageService.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, jobLineageService, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, jobLineageService, nil, nil, nil) req := &pb.GetJobRunLineageSummaryRequest{ TargetJobs: []*pb.TargetJobRunIdentifier{ @@ -1006,7 +1006,7 @@ func TestJobRunHandler(t *testing.T) { defer jobRunService.AssertExpectations(t) defer jobLineageService.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, jobLineageService, nil, nil) + handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, jobLineageService, nil, nil, nil) scheduledAt := timestamppb.Now() req := &pb.GetJobRunLineageSummaryRequest{ diff --git a/server/optimus.go b/server/optimus.go index b55178fce6..2e9e371ba0 100644 --- a/server/optimus.go +++ b/server/optimus.go @@ -199,7 +199,6 @@ func (s *OptimusServer) setupDB() error { if err != nil { return fmt.Errorf("postgres.Open: %w", err) } - return nil } @@ -446,6 +445,9 @@ func (s *OptimusServer) setupHandlers() error { newJobSLAPredictorService := schedulerService.NewJobSLAPredictorService(s.logger, s.conf.Alerting.PotentialSLABreachConfig, slaRepository, jobLineageService, newDurationEstimatorService, jobProviderRepo, alertsHandler, tenantService, newJobRunService) + // Job Estimator Service + jobEstimatorService := schedulerService.NewJobEstimatorService(s.logger, jobRunRepo, jobProviderRepo, jobLineageService, newDurationEstimatorService) + // Resource Bounded Context primaryResourceService := rService.NewResourceService(s.logger, resourceRepository, jJobService, resourceManager, s.eventHandler, jJobService, alertsHandler, tenantService, newEngine, syncer, syncStatusRepository) backupService := rService.NewBackupService(backupRepository, resourceRepository, resourceManager, s.logger) @@ -488,7 +490,7 @@ func (s *OptimusServer) setupHandlers() error { pb.RegisterResourceServiceServer(s.grpcServer, rHandler.NewResourceHandler(s.logger, primaryResourceService, resourceChangeLogService)) sensorService := schedulerService.NewSensorService(s.logger, s.conf.UpstreamResolvers...) - pb.RegisterJobRunServiceServer(s.grpcServer, schedulerHandler.NewJobRunHandler(s.logger, newJobRunService, eventsService, newSchedulerService, jobLineageService, newJobSLAPredictorService, sensorService)) + pb.RegisterJobRunServiceServer(s.grpcServer, schedulerHandler.NewJobRunHandler(s.logger, newJobRunService, eventsService, newSchedulerService, jobLineageService, newJobSLAPredictorService, sensorService, jobEstimatorService)) // backup service pb.RegisterBackupServiceServer(s.grpcServer, rHandler.NewBackupHandler(s.logger, backupService)) From e57aa596c047ed71161d33750841860d51854ea0 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Tue, 10 Feb 2026 08:00:36 +0700 Subject: [PATCH 08/26] feat: safety check for nil variables --- .../service/job_estimator_service.go | 65 +++++++++++++------ 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/core/scheduler/service/job_estimator_service.go b/core/scheduler/service/job_estimator_service.go index b96249c2c2..3409be9328 100644 --- a/core/scheduler/service/job_estimator_service.go +++ b/core/scheduler/service/job_estimator_service.go @@ -82,11 +82,20 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, // calculate estimated finish time for each job for _, jobSchedule := range jobSchedules { + if jobSchedule == nil { // safety check + s.l.Warn("nil job schedule provided, cannot calculate estimated finish time") + continue + } key := *jobSchedule if _, ok := jobRunEstimatedFinishTimes[key]; ok { // already calculated continue } - err := s.populateEstimatedFinishTime(ctx, jobSchedule, jobSchedule, jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) + if _, ok := jobsWithLineageMap[jobSchedule.JobName]; !ok { // safety check + s.l.Warn("no lineage found for job, cannot calculate estimated finish time", "job", jobSchedule.JobName) + continue + } + s.l.Debug("calculating estimated finish time for job", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) + err := s.populateEstimatedFinishTime(ctx, jobSchedule, jobsWithLineageMap[jobSchedule.JobName], jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) if err != nil { s.l.Error("failed to populate estimated finish time for job", "job", jobSchedule.JobName, "error", err) return nil, err @@ -124,49 +133,67 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, return finalJobRunEstimatedFinishTimes, nil } -func (s *JobEstimatorService) populateEstimatedFinishTime(ctx context.Context, jobTarget, jobSchedule *scheduler.JobSchedule, jobRunEstimatedFinishTimes map[scheduler.JobSchedule]time.Time, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { - key := *jobSchedule - estimatedDuration, ok := jobDurationsEstimation[jobSchedule.JobName] - if !ok { +func (s *JobEstimatorService) populateEstimatedFinishTime(ctx context.Context, jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunEstimatedFinishTimes map[scheduler.JobSchedule]time.Time, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { + if currentJobWithLineage == nil || currentJobWithLineage.JobRuns[jobTarget.JobName] == nil { + s.l.Warn("no job run found for job, skipping estimated finish time calculation", "job", currentJobWithLineage.JobName) + return nil + } + currentJobRun := currentJobWithLineage.JobRuns[jobTarget.JobName] + currentJobScheduleKey := scheduler.JobSchedule{ + JobName: currentJobWithLineage.JobName, + ScheduledAt: currentJobRun.ScheduledAt, + } + estimatedDuration, ok := jobDurationsEstimation[currentJobWithLineage.JobName] + if !ok || estimatedDuration == nil { // if no estimation found, we cannot proceed - s.l.Warn("no duration estimation found for job, cannot calculate estimated finish time", "job", jobSchedule.JobName) + s.l.Warn("no duration estimation found for job, cannot calculate estimated finish time", "job", currentJobWithLineage.JobName) return nil } // termination condition // 1. cache if already calculated - if _, ok := jobRunEstimatedFinishTimes[key]; ok { + if _, ok := jobRunEstimatedFinishTimes[currentJobScheduleKey]; ok { + s.l.Debug("estimated finish time already calculated for job, skipping", "job", currentJobWithLineage.JobName, "scheduled_at", currentJobRun.ScheduledAt) return nil } // 2. if end_time is nil and scheduled_time+duration Date: Tue, 10 Feb 2026 14:00:47 +0700 Subject: [PATCH 09/26] test: add test cases for job estimator finish time --- .../service/job_estimator_service.go | 6 +- .../service/job_estimator_service_test.go | 748 ++++++++++++++++++ .../service/job_sla_predictor_service_test.go | 2 +- 3 files changed, 752 insertions(+), 4 deletions(-) create mode 100644 core/scheduler/service/job_estimator_service_test.go diff --git a/core/scheduler/service/job_estimator_service.go b/core/scheduler/service/job_estimator_service.go index 3409be9328..92de678e19 100644 --- a/core/scheduler/service/job_estimator_service.go +++ b/core/scheduler/service/job_estimator_service.go @@ -95,7 +95,7 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, continue } s.l.Debug("calculating estimated finish time for job", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) - err := s.populateEstimatedFinishTime(ctx, jobSchedule, jobsWithLineageMap[jobSchedule.JobName], jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) + err := s.PopulateEstimatedFinishTime(ctx, jobSchedule, jobsWithLineageMap[jobSchedule.JobName], jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) if err != nil { s.l.Error("failed to populate estimated finish time for job", "job", jobSchedule.JobName, "error", err) return nil, err @@ -133,7 +133,7 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, return finalJobRunEstimatedFinishTimes, nil } -func (s *JobEstimatorService) populateEstimatedFinishTime(ctx context.Context, jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunEstimatedFinishTimes map[scheduler.JobSchedule]time.Time, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { +func (s *JobEstimatorService) PopulateEstimatedFinishTime(ctx context.Context, jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunEstimatedFinishTimes map[scheduler.JobSchedule]time.Time, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { if currentJobWithLineage == nil || currentJobWithLineage.JobRuns[jobTarget.JobName] == nil { s.l.Warn("no job run found for job, skipping estimated finish time calculation", "job", currentJobWithLineage.JobName) return nil @@ -180,7 +180,7 @@ func (s *JobEstimatorService) populateEstimatedFinishTime(ctx context.Context, j s.l.Debug("no upstream job run found for job, skipping upstream in estimated finish time calculation", "job", currentJobWithLineage.JobName, "upstream_job", upstream.JobName) continue } - err := s.populateEstimatedFinishTime(ctx, jobTarget, upstream, jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) + err := s.PopulateEstimatedFinishTime(ctx, jobTarget, upstream, jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) if err != nil { return err } diff --git a/core/scheduler/service/job_estimator_service_test.go b/core/scheduler/service/job_estimator_service_test.go new file mode 100644 index 0000000000..e9da96092c --- /dev/null +++ b/core/scheduler/service/job_estimator_service_test.go @@ -0,0 +1,748 @@ +package service_test + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + "github.com/goto/optimus/core/scheduler" + "github.com/goto/optimus/core/scheduler/service" + "github.com/goto/optimus/core/tenant" + "github.com/goto/salt/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGenerateEstimatedFinishTimes(t *testing.T) { + ctx := context.Background() + projectName := tenant.ProjectName("project-a") + referenceTime := time.Now() + scheduleRangeInHours := 10 * time.Hour + l := log.NewNoop() + + t.Run("given no jobs, should return empty map", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + + // when + estimatedFinishTimes, err := jobEstimatorService.GenerateEstimatedFinishTimes(ctx, projectName, []scheduler.JobName{}, map[string]string{}, referenceTime, scheduleRangeInHours) + + // then + assert.NoError(t, err) + assert.Empty(t, estimatedFinishTimes) + }) + + t.Run("given jobs, when get job detail error, return error", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + + jobAName := scheduler.JobName("job-A") + + jobDetailsGetter.On("GetJobs", ctx, projectName, []string{jobAName.String()}).Return([]*scheduler.JobWithDetails{}, errors.New("some error")) + + // when + estimatedFinishTimes, err := jobEstimatorService.GenerateEstimatedFinishTimes(ctx, projectName, []scheduler.JobName{jobAName}, map[string]string{}, referenceTime, scheduleRangeInHours) + + // then + assert.Nil(t, estimatedFinishTimes) + assert.EqualError(t, err, "some error") + }) + + t.Run("given job label, when get job detail error, return error", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + + labels := map[string]string{"category": "some-category"} + + jobDetailsGetter.On("GetJobsByLabels", ctx, projectName, labels).Return([]*scheduler.JobWithDetails{}, errors.New("some error")) + + // when + estimatedFinishTimes, err := jobEstimatorService.GenerateEstimatedFinishTimes(ctx, projectName, []scheduler.JobName{}, labels, referenceTime, scheduleRangeInHours) + + // then + assert.Nil(t, estimatedFinishTimes) + assert.EqualError(t, err, "some error") + }) + + t.Run("given jobs, with no job details, should return empty map", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + + jobAName := scheduler.JobName("job-A") + + jobDetailsGetter.On("GetJobs", ctx, projectName, []string{jobAName.String()}).Return([]*scheduler.JobWithDetails{}, nil) + + // when + estimatedFinishTimes, err := jobEstimatorService.GenerateEstimatedFinishTimes(ctx, projectName, []scheduler.JobName{jobAName}, map[string]string{}, referenceTime, scheduleRangeInHours) + + // then + assert.NoError(t, err) + assert.Empty(t, estimatedFinishTimes) + }) + + t.Run("given job, with no job schedules, should return empty map", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + + tenant, _ := tenant.NewTenant("project-a", "team-a") + jobAName := scheduler.JobName("job-A") + + jobWithDetails := &scheduler.JobWithDetails{ + Name: jobAName, + Job: &scheduler.Job{ + Tenant: tenant, + Name: jobAName, + }, + Schedule: nil, // no schedule + } + + jobDetailsGetter.On("GetJobs", ctx, projectName, []string{jobAName.String()}).Return([]*scheduler.JobWithDetails{jobWithDetails}, nil) + + // when + estimatedFinishTimes, err := jobEstimatorService.GenerateEstimatedFinishTimes(ctx, projectName, []scheduler.JobName{jobAName}, map[string]string{}, referenceTime, scheduleRangeInHours) + + // then + assert.NoError(t, err) + assert.Empty(t, estimatedFinishTimes) + }) + + t.Run("given job, with job schedules, when get lineage error, return error", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + + tenant, _ := tenant.NewTenant("project-a", "team-a") + jobAName := scheduler.JobName("job-A") + startDate := referenceTime.Add(-24 * time.Hour).Truncate(time.Hour) + // get hour from now + scheduleRangeInHours - 1 hours to make sure it's within next schedule range + scheduledAt := referenceTime.Add(scheduleRangeInHours - 1*time.Hour).Truncate(time.Hour) + interval := fmt.Sprintf("0 %d * * *", scheduledAt.Hour()) // daily + + jobWithDetails := &scheduler.JobWithDetails{ + Name: jobAName, + Job: &scheduler.Job{ + Tenant: tenant, + Name: jobAName, + }, + Schedule: &scheduler.Schedule{ + StartDate: startDate, + Interval: interval, + }, + } + + jobDetailsGetter.On("GetJobs", ctx, projectName, []string{jobAName.String()}).Return([]*scheduler.JobWithDetails{jobWithDetails}, nil) + jobLineageFetcher.On("GetJobLineage", ctx, map[scheduler.JobName]*scheduler.JobSchedule{jobAName: {JobName: jobAName, ScheduledAt: scheduledAt}}).Return(nil, errors.New("some error")) + + // when + estimatedFinishTimes, err := jobEstimatorService.GenerateEstimatedFinishTimes(ctx, projectName, []scheduler.JobName{jobAName}, map[string]string{}, referenceTime, scheduleRangeInHours) + + // then + assert.Nil(t, estimatedFinishTimes) + assert.EqualError(t, err, "some error") + }) + + t.Run("given job, with job schedules and lineage, when estimate duration error, return error", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + + tenant, _ := tenant.NewTenant("project-a", "team-a") + jobAName := scheduler.JobName("job-A") + startDate := referenceTime.Add(-24 * time.Hour).Truncate(time.Hour) + scheduledAt := referenceTime.Add(scheduleRangeInHours - 1*time.Hour).Truncate(time.Hour) + interval := fmt.Sprintf("0 %d * * *", scheduledAt.Hour()) // daily + + jobWithDetails := &scheduler.JobWithDetails{ + Name: jobAName, + Job: &scheduler.Job{ + Tenant: tenant, + Name: jobAName, + }, + Schedule: &scheduler.Schedule{ + StartDate: startDate, + Interval: interval, + }, + } + + jobLineageSummary := &scheduler.JobLineageSummary{ + JobName: jobAName, + Upstreams: []*scheduler.JobLineageSummary{}, + } + + jobDetailsGetter.On("GetJobs", ctx, projectName, []string{jobAName.String()}).Return([]*scheduler.JobWithDetails{jobWithDetails}, nil) + jobLineageFetcher.On("GetJobLineage", ctx, map[scheduler.JobName]*scheduler.JobSchedule{jobAName: {JobName: jobAName, ScheduledAt: scheduledAt}}).Return(map[scheduler.JobName]*scheduler.JobLineageSummary{jobAName: jobLineageSummary}, nil) + durationEstimator.On("GetPercentileDurationByJobNames", ctx, referenceTime, []scheduler.JobName{jobAName}).Return(nil, errors.New("some error")) + + // when + estimatedFinishTimes, err := jobEstimatorService.GenerateEstimatedFinishTimes(ctx, projectName, []scheduler.JobName{jobAName}, map[string]string{}, referenceTime, scheduleRangeInHours) + + // then + assert.Nil(t, estimatedFinishTimes) + assert.EqualError(t, err, "some error") + }) + + t.Run("given job, with job schedules, lineage and duration estimation, should return estimated finish time", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + + tenant, _ := tenant.NewTenant("project-a", "team-a") + jobAName := scheduler.JobName("job-A") + startDate := referenceTime.Add(-24 * time.Hour).Truncate(time.Hour) + scheduledAt := referenceTime.Add(scheduleRangeInHours - 1*time.Hour).Truncate(time.Hour) + interval := fmt.Sprintf("0 %d * * *", scheduledAt.Hour()) // daily + + jobWithDetails := &scheduler.JobWithDetails{ + Name: jobAName, + Job: &scheduler.Job{ + Tenant: tenant, + Name: jobAName, + }, + Schedule: &scheduler.Schedule{ + StartDate: startDate, + Interval: interval, + }, + } + + jobLineageSummary := &scheduler.JobLineageSummary{ + JobName: jobAName, + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ + jobAName: { + JobName: jobAName, + ScheduledAt: scheduledAt, + }, + }, + Upstreams: []*scheduler.JobLineageSummary{}, + } + + jobDetailsGetter.On("GetJobs", ctx, projectName, []string{jobAName.String()}).Return([]*scheduler.JobWithDetails{jobWithDetails}, nil) + jobLineageFetcher.On("GetJobLineage", ctx, map[scheduler.JobName]*scheduler.JobSchedule{jobAName: {JobName: jobAName, ScheduledAt: scheduledAt}}).Return(map[scheduler.JobName]*scheduler.JobLineageSummary{jobAName: jobLineageSummary}, nil) + durationEstimator.On("GetPercentileDurationByJobNames", ctx, referenceTime, []scheduler.JobName{jobAName}).Return(map[scheduler.JobName]*time.Duration{jobAName: func() *time.Duration { d := 30 * time.Minute; return &d }()}, nil) + jobRunDetailsRepo.On("UpsertEstimatedFinishTime", ctx, projectName, jobAName, scheduledAt, scheduledAt.Add(30*time.Minute)).Return(nil) + + // when + estimatedFinishTimes, err := jobEstimatorService.GenerateEstimatedFinishTimes(ctx, projectName, []scheduler.JobName{jobAName}, map[string]string{}, referenceTime, scheduleRangeInHours) + + // then + assert.NoError(t, err) + expectedEstimatedFinishTime := scheduledAt.Add(30 * time.Minute) + assert.Equal(t, map[scheduler.JobSchedule]time.Time{{JobName: jobAName, ScheduledAt: scheduledAt}: expectedEstimatedFinishTime}, estimatedFinishTimes) + }) +} + +func TestPopulateEstimatedFinishTime(t *testing.T) { + ctx := context.Background() + l := log.NewNoop() + referenceTime := time.Now() + scheduleRangeInHours := 10 * time.Hour + bufferTime := 10 * time.Minute + + t.Run("when no current job run exists, should skip", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + + jobRunEstimatedFinishTime := map[scheduler.JobSchedule]time.Time{} + jobWithLineageMap := map[scheduler.JobName]*scheduler.JobLineageSummary{} + jobDurationEstimation := map[scheduler.JobName]*time.Duration{} + + scheduledAt := referenceTime.Add(scheduleRangeInHours - 1*time.Hour).Truncate(time.Hour) + jobTarget := &scheduler.JobSchedule{ + JobName: scheduler.JobName("job-A"), + ScheduledAt: scheduledAt, + } + currentJobWithLineage := &scheduler.JobLineageSummary{ + JobName: jobTarget.JobName, + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{}, // no current job run + Upstreams: []*scheduler.JobLineageSummary{}, + } + jobWithLineageMap[jobTarget.JobName] = currentJobWithLineage + jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() + + // when + err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + + // then + assert.NoError(t, err) + assert.Empty(t, jobRunEstimatedFinishTime) + }) + + t.Run("when duration estimation not found, should skip", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + jobRunEstimatedFinishTime := map[scheduler.JobSchedule]time.Time{} + jobWithLineageMap := map[scheduler.JobName]*scheduler.JobLineageSummary{} + jobDurationEstimation := map[scheduler.JobName]*time.Duration{} + + scheduledAt := referenceTime.Add(scheduleRangeInHours - 1*time.Hour).Truncate(time.Hour) + jobTarget := &scheduler.JobSchedule{ + JobName: scheduler.JobName("job-A"), + ScheduledAt: scheduledAt, + } + currentJobWithLineage := &scheduler.JobLineageSummary{ + JobName: jobTarget.JobName, + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ + jobTarget.JobName: { + JobName: jobTarget.JobName, + ScheduledAt: scheduledAt, + }, + }, + Upstreams: []*scheduler.JobLineageSummary{}, + } + jobWithLineageMap[jobTarget.JobName] = currentJobWithLineage + // no duration estimation added + + // when + err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + + // then + assert.NoError(t, err) + assert.Empty(t, jobRunEstimatedFinishTime) + }) + + t.Run("when estimated finish time already calculated, should skip", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + jobRunEstimatedFinishTime := map[scheduler.JobSchedule]time.Time{} + jobWithLineageMap := map[scheduler.JobName]*scheduler.JobLineageSummary{} + jobDurationEstimation := map[scheduler.JobName]*time.Duration{} + + scheduledAt := referenceTime.Add(scheduleRangeInHours - 1*time.Hour).Truncate(time.Hour) + jobTarget := &scheduler.JobSchedule{ + JobName: scheduler.JobName("job-A"), + ScheduledAt: scheduledAt, + } + currentJobWithLineage := &scheduler.JobLineageSummary{ + JobName: jobTarget.JobName, + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ + jobTarget.JobName: { + JobName: jobTarget.JobName, + ScheduledAt: scheduledAt, + }, + }, + Upstreams: []*scheduler.JobLineageSummary{}, + } + jobWithLineageMap[jobTarget.JobName] = currentJobWithLineage + jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() + // already calculated + jobRunEstimatedFinishTime[*jobTarget] = scheduledAt.Add(25 * time.Minute) + + // when + err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + // then + assert.NoError(t, err) + // should not be updated + assert.Equal(t, scheduledAt.Add(25*time.Minute), jobRunEstimatedFinishTime[*jobTarget]) + }) + + t.Run("when end_time is nil and running late, should set estimated finish time to reference time + buffer", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + jobRunEstimatedFinishTime := map[scheduler.JobSchedule]time.Time{} + jobWithLineageMap := map[scheduler.JobName]*scheduler.JobLineageSummary{} + jobDurationEstimation := map[scheduler.JobName]*time.Duration{} + + scheduledAt := referenceTime.Add(-1 * time.Hour) // scheduled in the past + jobTarget := &scheduler.JobSchedule{ + JobName: scheduler.JobName("job-A"), + ScheduledAt: scheduledAt, + } + currentJobWithLineage := &scheduler.JobLineageSummary{ + JobName: jobTarget.JobName, + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ + jobTarget.JobName: { + JobName: jobTarget.JobName, + ScheduledAt: scheduledAt, + JobEndTime: nil, // still running + }, + }, + Upstreams: []*scheduler.JobLineageSummary{}, + } + jobWithLineageMap[jobTarget.JobName] = currentJobWithLineage + jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() + + // when + err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + + // then + assert.NoError(t, err) + expectedEstimatedFinishTime := referenceTime.Add(bufferTime) + assert.Equal(t, expectedEstimatedFinishTime, jobRunEstimatedFinishTime[*jobTarget]) + }) + + t.Run("when end_time is not nil, should set estimated finish time to job end time", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + jobRunEstimatedFinishTime := map[scheduler.JobSchedule]time.Time{} + jobWithLineageMap := map[scheduler.JobName]*scheduler.JobLineageSummary{} + jobDurationEstimation := map[scheduler.JobName]*time.Duration{} + + scheduledAt := referenceTime.Add(-1 * time.Hour) // scheduled in the past + jobEndTime := referenceTime.Add(-30 * time.Minute) + jobTarget := &scheduler.JobSchedule{ + JobName: scheduler.JobName("job-A"), + ScheduledAt: scheduledAt, + } + currentJobWithLineage := &scheduler.JobLineageSummary{ + JobName: jobTarget.JobName, + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ + jobTarget.JobName: { + JobName: jobTarget.JobName, + ScheduledAt: scheduledAt, + JobEndTime: &jobEndTime, + }, + }, + Upstreams: []*scheduler.JobLineageSummary{}, + } + jobWithLineageMap[jobTarget.JobName] = currentJobWithLineage + jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() + + // when + err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + + // then + assert.NoError(t, err) + assert.Equal(t, jobEndTime, jobRunEstimatedFinishTime[*jobTarget]) + }) + + t.Run("when targeted job will run in the future, should set estimated finish time to scheduled at + estimated duration", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + jobRunEstimatedFinishTime := map[scheduler.JobSchedule]time.Time{} + jobWithLineageMap := map[scheduler.JobName]*scheduler.JobLineageSummary{} + jobDurationEstimation := map[scheduler.JobName]*time.Duration{} + + scheduledAt := referenceTime.Add(1 * time.Hour) // scheduled in the future + jobTarget := &scheduler.JobSchedule{ + JobName: scheduler.JobName("job-A"), + ScheduledAt: scheduledAt, + } + currentJobWithLineage := &scheduler.JobLineageSummary{ + JobName: jobTarget.JobName, + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ + jobTarget.JobName: { + JobName: jobTarget.JobName, + ScheduledAt: scheduledAt, + }, + }, + Upstreams: []*scheduler.JobLineageSummary{}, + } + jobWithLineageMap[jobTarget.JobName] = currentJobWithLineage + jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() + + // when + err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + + // then + assert.NoError(t, err) + expectedEstimatedFinishTime := scheduledAt.Add(30 * time.Minute) + assert.Equal(t, expectedEstimatedFinishTime, jobRunEstimatedFinishTime[*jobTarget]) + }) + + t.Run("when targeted job will run in the future, and there's an upstream job running late, should set estimated finish time to max(upstream estimated finish time, scheduled_at) + estimated duration", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + jobRunEstimatedFinishTime := map[scheduler.JobSchedule]time.Time{} + jobWithLineageMap := map[scheduler.JobName]*scheduler.JobLineageSummary{} + jobDurationEstimation := map[scheduler.JobName]*time.Duration{} + + scheduledAt := referenceTime.Add(1 * time.Hour) // scheduled in the future + upstreamScheduledAt := referenceTime.Add(-1 * time.Hour) // upstream scheduled in the past + jobTarget := &scheduler.JobSchedule{ + JobName: scheduler.JobName("job-A"), + ScheduledAt: scheduledAt, + } + currentJobWithLineage := &scheduler.JobLineageSummary{ + JobName: jobTarget.JobName, + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ + jobTarget.JobName: { + JobName: jobTarget.JobName, + ScheduledAt: scheduledAt, + }, + }, + Upstreams: []*scheduler.JobLineageSummary{}, + } + jobUpstreamWithLineage := &scheduler.JobLineageSummary{ + JobName: scheduler.JobName("job-B"), + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ + jobTarget.JobName: { + JobName: scheduler.JobName("job-B"), + ScheduledAt: upstreamScheduledAt, + }, + }, + Upstreams: []*scheduler.JobLineageSummary{}, + } + currentJobWithLineage.Upstreams = append(currentJobWithLineage.Upstreams, jobUpstreamWithLineage) + jobWithLineageMap[jobTarget.JobName] = currentJobWithLineage + + jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() + jobDurationEstimation[jobUpstreamWithLineage.JobName] = func() *time.Duration { d := 45 * time.Minute; return &d }() + + // when + err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + + // then + assert.NoError(t, err) + expectedEstimatedFinishTime := scheduledAt.Add(30 * time.Minute) + assert.Equal(t, expectedEstimatedFinishTime, jobRunEstimatedFinishTime[*jobTarget]) + }) + + t.Run("when targeted job will run in the future, and there's an upstream job running late, and estimated finish time for upstream is greater than scheduled_at, should set estimated finish time to max(upstream estimated finish time, scheduled_at) + estimated duration", func(t *testing.T) { + // given + jobRunDetailsRepo := NewJobRunDetailsRepository(t) + jobDetailsGetter := NewJobDetailsGetter(t) + jobLineageFetcher := NewJobLineageFetcher(t) + durationEstimator := NewDurationEstimator(t) + + jobEstimatorService := service.NewJobEstimatorService( + l, + jobRunDetailsRepo, + jobDetailsGetter, + jobLineageFetcher, + durationEstimator, + ) + jobRunEstimatedFinishTime := map[scheduler.JobSchedule]time.Time{} + jobWithLineageMap := map[scheduler.JobName]*scheduler.JobLineageSummary{} + jobDurationEstimation := map[scheduler.JobName]*time.Duration{} + + scheduledAt := referenceTime.Add(5 * time.Minute) // scheduled in the future + upstreamScheduledAt := referenceTime.Add(-1 * time.Hour) // upstream scheduled in the past + jobTarget := &scheduler.JobSchedule{ + JobName: scheduler.JobName("job-A"), + ScheduledAt: scheduledAt, + } + currentJobWithLineage := &scheduler.JobLineageSummary{ + JobName: jobTarget.JobName, + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ + jobTarget.JobName: { + JobName: jobTarget.JobName, + ScheduledAt: scheduledAt, + }, + }, + Upstreams: []*scheduler.JobLineageSummary{}, + } + jobUpstreamWithLineage := &scheduler.JobLineageSummary{ + JobName: scheduler.JobName("job-B"), + JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ + jobTarget.JobName: { + JobName: scheduler.JobName("job-B"), + ScheduledAt: upstreamScheduledAt, + }, + }, + Upstreams: []*scheduler.JobLineageSummary{}, + } + currentJobWithLineage.Upstreams = append(currentJobWithLineage.Upstreams, jobUpstreamWithLineage) + jobWithLineageMap[jobTarget.JobName] = currentJobWithLineage + + jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() + jobDurationEstimation[jobUpstreamWithLineage.JobName] = func() *time.Duration { d := 45 * time.Minute; return &d }() + + // when + err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + + // then + assert.NoError(t, err) + expectedEstimatedFinishTime := referenceTime.Add(10 * time.Minute).Add(30 * time.Minute) + assert.Equal(t, expectedEstimatedFinishTime, jobRunEstimatedFinishTime[*jobTarget]) + }) +} + +// JobRunDetailsRepository is an autogenerated mock type for the JobRunDetailsRepository type +type JobRunDetailsRepository struct { + mock.Mock +} + +// UpsertEstimatedFinishTime provides a mock function with given fields: ctx, projectName, jobName, scheduledAt, estimatedFinishTime +func (_m *JobRunDetailsRepository) UpsertEstimatedFinishTime(ctx context.Context, projectName tenant.ProjectName, jobName scheduler.JobName, scheduledAt time.Time, estimatedFinishTime time.Time) error { + ret := _m.Called(ctx, projectName, jobName, scheduledAt, estimatedFinishTime) + + if len(ret) == 0 { + panic("no return value specified for UpsertEstimatedFinishTime") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, tenant.ProjectName, scheduler.JobName, time.Time, time.Time) error); ok { + r0 = rf(ctx, projectName, jobName, scheduledAt, estimatedFinishTime) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewJobRunDetailsRepository creates a new instance of JobRunDetailsRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewJobRunDetailsRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *JobRunDetailsRepository { + mock := &JobRunDetailsRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/scheduler/service/job_sla_predictor_service_test.go b/core/scheduler/service/job_sla_predictor_service_test.go index eb3f24981a..9ba70075a4 100644 --- a/core/scheduler/service/job_sla_predictor_service_test.go +++ b/core/scheduler/service/job_sla_predictor_service_test.go @@ -1479,7 +1479,7 @@ func (_m *JobDetailsGetter) GetJobs(ctx context.Context, projectName tenant.Proj // GetJobsByLabels provides a mock function with given fields: ctx, projectName, labels func (_m *JobDetailsGetter) GetJobsByLabels(ctx context.Context, projectName tenant.ProjectName, labels map[string]string) ([]*scheduler.JobWithDetails, error) { - ret := _m.Called(ctx, projectName, labels, false, "") + ret := _m.Called(ctx, projectName, labels) if len(ret) == 0 { panic("no return value specified for GetJobsByLabels") From 63756dfe3bc84b0a0fbd817619494c4e7391eba5 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Tue, 10 Feb 2026 14:08:08 +0700 Subject: [PATCH 10/26] test: add test cases for generate estimation on handler --- .../scheduler/handler/v1beta1/job_run_test.go | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/core/scheduler/handler/v1beta1/job_run_test.go b/core/scheduler/handler/v1beta1/job_run_test.go index bae4cd864c..f8e6a416ea 100644 --- a/core/scheduler/handler/v1beta1/job_run_test.go +++ b/core/scheduler/handler/v1beta1/job_run_test.go @@ -1045,6 +1045,58 @@ func TestJobRunHandler(t *testing.T) { assert.Equal(t, len(mockLineages), len(resp.Jobs)) }) }) + + t.Run("GenerateEstimatedFinishTime", func(t *testing.T) { + t.Run("should return error when estimator service error", func(t *testing.T) { + jobRunService := new(mockJobRunService) + defer jobRunService.AssertExpectations(t) + + jobEstimatorService := NewJobEstimatorService(t) + defer jobEstimatorService.AssertExpectations(t) + + handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, jobEstimatorService) + + req := &pb.GenerateEstimatedFinishTimeRequest{ + ProjectName: projectName, + JobNames: []string{"job-A"}, + ScheduledRangeInHours: 12, + } + + jobEstimatorService.On("GenerateEstimatedFinishTimes", ctx, tenant.ProjectName(projectName), []scheduler.JobName{"job-A"}, mock.Anything, mock.Anything, 12*time.Hour).Return(nil, errors.New("service error")) + resp, err := handler.GenerateEstimatedFinishTime(ctx, req) + assert.NotNil(t, err) + assert.Nil(t, resp) + assert.ErrorContains(t, err, "unable to generate estimated finish times") + }) + t.Run("should return estimated finish time successfully", func(t *testing.T) { + jobRunService := new(mockJobRunService) + defer jobRunService.AssertExpectations(t) + + jobEstimatorService := NewJobEstimatorService(t) + defer jobEstimatorService.AssertExpectations(t) + + handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, jobEstimatorService) + + req := &pb.GenerateEstimatedFinishTimeRequest{ + ProjectName: projectName, + JobNames: []string{"job-A"}, + ScheduledRangeInHours: 12, + } + + expectedFinishTime := timestamppb.New(time.Now().Add(30 * time.Minute)) + + jobEstimatorService.On("GenerateEstimatedFinishTimes", ctx, tenant.ProjectName(projectName), []scheduler.JobName{"job-A"}, mock.Anything, mock.Anything, 12*time.Hour).Return(map[scheduler.JobSchedule]time.Time{ + { + JobName: "job-A", + ScheduledAt: time.Now(), + }: expectedFinishTime.AsTime(), + }, nil) + resp, err := handler.GenerateEstimatedFinishTime(ctx, req) + assert.Nil(t, err) + assert.NotNil(t, resp) + assert.Equal(t, 1, len(resp.Jobs)) + }) + }) } type mockThirdPartyClient struct { @@ -1152,3 +1204,52 @@ func (m *mockNotifier) Relay(ctx context.Context, event *scheduler.Event) error args := m.Called(ctx, event) return args.Error(0) } + +// JobEstimatorService is an autogenerated mock type for the JobEstimatorService type +type JobEstimatorService struct { + mock.Mock +} + +// GenerateEstimatedFinishTimes provides a mock function with given fields: ctx, projectName, jobNames, labels, referenceTime, scheduleRangeInHours +func (_m *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string, referenceTime time.Time, scheduleRangeInHours time.Duration) (map[scheduler.JobSchedule]time.Time, error) { + ret := _m.Called(ctx, projectName, jobNames, labels, referenceTime, scheduleRangeInHours) + + if len(ret) == 0 { + panic("no return value specified for GenerateEstimatedFinishTimes") + } + + var r0 map[scheduler.JobSchedule]time.Time + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, tenant.ProjectName, []scheduler.JobName, map[string]string, time.Time, time.Duration) (map[scheduler.JobSchedule]time.Time, error)); ok { + return rf(ctx, projectName, jobNames, labels, referenceTime, scheduleRangeInHours) + } + if rf, ok := ret.Get(0).(func(context.Context, tenant.ProjectName, []scheduler.JobName, map[string]string, time.Time, time.Duration) map[scheduler.JobSchedule]time.Time); ok { + r0 = rf(ctx, projectName, jobNames, labels, referenceTime, scheduleRangeInHours) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[scheduler.JobSchedule]time.Time) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, tenant.ProjectName, []scheduler.JobName, map[string]string, time.Time, time.Duration) error); ok { + r1 = rf(ctx, projectName, jobNames, labels, referenceTime, scheduleRangeInHours) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewJobEstimatorService creates a new instance of JobEstimatorService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewJobEstimatorService(t interface { + mock.TestingT + Cleanup(func()) +}) *JobEstimatorService { + mock := &JobEstimatorService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From 4966e6575f4c82083e359d6ce4da7bcb10b7fc76 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Tue, 10 Feb 2026 14:11:23 +0700 Subject: [PATCH 11/26] fix: linter --- .../scheduler/handler/v1beta1/job_run_test.go | 5 +-- .../service/job_estimator_service.go | 6 ++-- .../service/job_estimator_service_test.go | 31 ++++++++++--------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/core/scheduler/handler/v1beta1/job_run_test.go b/core/scheduler/handler/v1beta1/job_run_test.go index f8e6a416ea..94df0aa3a9 100644 --- a/core/scheduler/handler/v1beta1/job_run_test.go +++ b/core/scheduler/handler/v1beta1/job_run_test.go @@ -1245,9 +1245,10 @@ func (_m *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, func NewJobEstimatorService(t interface { mock.TestingT Cleanup(func()) -}) *JobEstimatorService { +}, +) *JobEstimatorService { mock := &JobEstimatorService{} - mock.Mock.Test(t) + mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/core/scheduler/service/job_estimator_service.go b/core/scheduler/service/job_estimator_service.go index 92de678e19..8fc0e8748a 100644 --- a/core/scheduler/service/job_estimator_service.go +++ b/core/scheduler/service/job_estimator_service.go @@ -95,7 +95,7 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, continue } s.l.Debug("calculating estimated finish time for job", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) - err := s.PopulateEstimatedFinishTime(ctx, jobSchedule, jobsWithLineageMap[jobSchedule.JobName], jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) + err := s.PopulateEstimatedFinishTime(jobSchedule, jobsWithLineageMap[jobSchedule.JobName], jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) if err != nil { s.l.Error("failed to populate estimated finish time for job", "job", jobSchedule.JobName, "error", err) return nil, err @@ -133,7 +133,7 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, return finalJobRunEstimatedFinishTimes, nil } -func (s *JobEstimatorService) PopulateEstimatedFinishTime(ctx context.Context, jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunEstimatedFinishTimes map[scheduler.JobSchedule]time.Time, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { +func (s *JobEstimatorService) PopulateEstimatedFinishTime(jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunEstimatedFinishTimes map[scheduler.JobSchedule]time.Time, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { if currentJobWithLineage == nil || currentJobWithLineage.JobRuns[jobTarget.JobName] == nil { s.l.Warn("no job run found for job, skipping estimated finish time calculation", "job", currentJobWithLineage.JobName) return nil @@ -180,7 +180,7 @@ func (s *JobEstimatorService) PopulateEstimatedFinishTime(ctx context.Context, j s.l.Debug("no upstream job run found for job, skipping upstream in estimated finish time calculation", "job", currentJobWithLineage.JobName, "upstream_job", upstream.JobName) continue } - err := s.PopulateEstimatedFinishTime(ctx, jobTarget, upstream, jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) + err := s.PopulateEstimatedFinishTime(jobTarget, upstream, jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) if err != nil { return err } diff --git a/core/scheduler/service/job_estimator_service_test.go b/core/scheduler/service/job_estimator_service_test.go index e9da96092c..6be8d24d31 100644 --- a/core/scheduler/service/job_estimator_service_test.go +++ b/core/scheduler/service/job_estimator_service_test.go @@ -7,12 +7,13 @@ import ( "testing" "time" - "github.com/goto/optimus/core/scheduler" - "github.com/goto/optimus/core/scheduler/service" - "github.com/goto/optimus/core/tenant" "github.com/goto/salt/log" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + + "github.com/goto/optimus/core/scheduler" + "github.com/goto/optimus/core/scheduler/service" + "github.com/goto/optimus/core/tenant" ) func TestGenerateEstimatedFinishTimes(t *testing.T) { @@ -318,7 +319,6 @@ func TestGenerateEstimatedFinishTimes(t *testing.T) { } func TestPopulateEstimatedFinishTime(t *testing.T) { - ctx := context.Background() l := log.NewNoop() referenceTime := time.Now() scheduleRangeInHours := 10 * time.Hour @@ -357,7 +357,7 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() // when - err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobEstimatorService.PopulateEstimatedFinishTime(jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) @@ -401,7 +401,7 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { // no duration estimation added // when - err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobEstimatorService.PopulateEstimatedFinishTime(jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) @@ -447,7 +447,7 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { jobRunEstimatedFinishTime[*jobTarget] = scheduledAt.Add(25 * time.Minute) // when - err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobEstimatorService.PopulateEstimatedFinishTime(jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) // should not be updated @@ -492,7 +492,7 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() // when - err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobEstimatorService.PopulateEstimatedFinishTime(jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) @@ -539,7 +539,7 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() // when - err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobEstimatorService.PopulateEstimatedFinishTime(jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) @@ -583,7 +583,7 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() // when - err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobEstimatorService.PopulateEstimatedFinishTime(jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) @@ -642,7 +642,7 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { jobDurationEstimation[jobUpstreamWithLineage.JobName] = func() *time.Duration { d := 45 * time.Minute; return &d }() // when - err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobEstimatorService.PopulateEstimatedFinishTime(jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) @@ -701,7 +701,7 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { jobDurationEstimation[jobUpstreamWithLineage.JobName] = func() *time.Duration { d := 45 * time.Minute; return &d }() // when - err := jobEstimatorService.PopulateEstimatedFinishTime(ctx, jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobEstimatorService.PopulateEstimatedFinishTime(jobTarget, currentJobWithLineage, jobRunEstimatedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) @@ -716,7 +716,7 @@ type JobRunDetailsRepository struct { } // UpsertEstimatedFinishTime provides a mock function with given fields: ctx, projectName, jobName, scheduledAt, estimatedFinishTime -func (_m *JobRunDetailsRepository) UpsertEstimatedFinishTime(ctx context.Context, projectName tenant.ProjectName, jobName scheduler.JobName, scheduledAt time.Time, estimatedFinishTime time.Time) error { +func (_m *JobRunDetailsRepository) UpsertEstimatedFinishTime(ctx context.Context, projectName tenant.ProjectName, jobName scheduler.JobName, scheduledAt, estimatedFinishTime time.Time) error { ret := _m.Called(ctx, projectName, jobName, scheduledAt, estimatedFinishTime) if len(ret) == 0 { @@ -738,9 +738,10 @@ func (_m *JobRunDetailsRepository) UpsertEstimatedFinishTime(ctx context.Context func NewJobRunDetailsRepository(t interface { mock.TestingT Cleanup(func()) -}) *JobRunDetailsRepository { +}, +) *JobRunDetailsRepository { mock := &JobRunDetailsRepository{} - mock.Mock.Test(t) + mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) From 027a52efb7bd0590df68a22e67d0ed5963d46f4c Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Tue, 10 Feb 2026 14:16:36 +0700 Subject: [PATCH 12/26] fix: test case --- core/scheduler/service/job_sla_predictor_service_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/scheduler/service/job_sla_predictor_service_test.go b/core/scheduler/service/job_sla_predictor_service_test.go index 9ba70075a4..0e301c0414 100644 --- a/core/scheduler/service/job_sla_predictor_service_test.go +++ b/core/scheduler/service/job_sla_predictor_service_test.go @@ -106,7 +106,7 @@ func TestIdentifySLABreaches(t *testing.T) { Severity: "", } - jobDetailsGetter.On("GetJobsByLabels", ctx, projectName, labels, false, "").Return([]*scheduler.JobWithDetails{}, nil).Once() + jobDetailsGetter.On("GetJobsByLabels", ctx, projectName, labels).Return([]*scheduler.JobWithDetails{}, nil).Once() // when jobBreachRootCause, err := jobSLAPredictorService.IdentifySLABreaches(ctx, projectName, jobNames, labels, reqConfig) From 5253808f59f9c2aa1d2e4c138da5bc5d13a3b4b8 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Wed, 11 Feb 2026 12:02:15 +0700 Subject: [PATCH 13/26] feat: skip disabled job --- .../service/job_estimator_service.go | 12 ++++++- .../service/job_estimator_service_test.go | 32 +++++++++++++------ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/core/scheduler/service/job_estimator_service.go b/core/scheduler/service/job_estimator_service.go index 8fc0e8748a..56847f541e 100644 --- a/core/scheduler/service/job_estimator_service.go +++ b/core/scheduler/service/job_estimator_service.go @@ -134,10 +134,16 @@ func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, } func (s *JobEstimatorService) PopulateEstimatedFinishTime(jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunEstimatedFinishTimes map[scheduler.JobSchedule]time.Time, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { + // pre condition check if currentJobWithLineage == nil || currentJobWithLineage.JobRuns[jobTarget.JobName] == nil { s.l.Warn("no job run found for job, skipping estimated finish time calculation", "job", currentJobWithLineage.JobName) return nil } + if !currentJobWithLineage.IsEnabled { + s.l.Debug("job is disabled, skipping estimated finish time calculation", "job", currentJobWithLineage.JobName) + return nil + } + currentJobRun := currentJobWithLineage.JobRuns[jobTarget.JobName] currentJobScheduleKey := scheduler.JobSchedule{ JobName: currentJobWithLineage.JobName, @@ -189,7 +195,11 @@ func (s *JobEstimatorService) PopulateEstimatedFinishTime(jobTarget *scheduler.J JobName: upstream.JobName, ScheduledAt: upstream.JobRuns[jobTarget.JobName].ScheduledAt, } - upstreamEstimatedFinishTime := jobRunEstimatedFinishTimes[upstreamScheduleKey] + upstreamEstimatedFinishTime, ok := jobRunEstimatedFinishTimes[upstreamScheduleKey] + if !ok { + s.l.Warn("estimated finish time not found for upstream job, skipping in estimated finish time calculation", "job", currentJobWithLineage.JobName, "upstream_job", upstream.JobName) + continue + } maxUpstreamEstimatedFinishTime = maxTime(maxUpstreamEstimatedFinishTime, upstreamEstimatedFinishTime) } diff --git a/core/scheduler/service/job_estimator_service_test.go b/core/scheduler/service/job_estimator_service_test.go index 6be8d24d31..474358819e 100644 --- a/core/scheduler/service/job_estimator_service_test.go +++ b/core/scheduler/service/job_estimator_service_test.go @@ -244,6 +244,7 @@ func TestGenerateEstimatedFinishTimes(t *testing.T) { jobLineageSummary := &scheduler.JobLineageSummary{ JobName: jobAName, + IsEnabled: true, Upstreams: []*scheduler.JobLineageSummary{}, } @@ -293,7 +294,8 @@ func TestGenerateEstimatedFinishTimes(t *testing.T) { } jobLineageSummary := &scheduler.JobLineageSummary{ - JobName: jobAName, + JobName: jobAName, + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ jobAName: { JobName: jobAName, @@ -350,6 +352,7 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { } currentJobWithLineage := &scheduler.JobLineageSummary{ JobName: jobTarget.JobName, + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{}, // no current job run Upstreams: []*scheduler.JobLineageSummary{}, } @@ -388,7 +391,8 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { ScheduledAt: scheduledAt, } currentJobWithLineage := &scheduler.JobLineageSummary{ - JobName: jobTarget.JobName, + JobName: jobTarget.JobName, + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ jobTarget.JobName: { JobName: jobTarget.JobName, @@ -432,7 +436,8 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { ScheduledAt: scheduledAt, } currentJobWithLineage := &scheduler.JobLineageSummary{ - JobName: jobTarget.JobName, + JobName: jobTarget.JobName, + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ jobTarget.JobName: { JobName: jobTarget.JobName, @@ -478,7 +483,8 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { ScheduledAt: scheduledAt, } currentJobWithLineage := &scheduler.JobLineageSummary{ - JobName: jobTarget.JobName, + JobName: jobTarget.JobName, + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ jobTarget.JobName: { JobName: jobTarget.JobName, @@ -525,7 +531,8 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { ScheduledAt: scheduledAt, } currentJobWithLineage := &scheduler.JobLineageSummary{ - JobName: jobTarget.JobName, + JobName: jobTarget.JobName, + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ jobTarget.JobName: { JobName: jobTarget.JobName, @@ -570,7 +577,8 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { ScheduledAt: scheduledAt, } currentJobWithLineage := &scheduler.JobLineageSummary{ - JobName: jobTarget.JobName, + JobName: jobTarget.JobName, + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ jobTarget.JobName: { JobName: jobTarget.JobName, @@ -616,7 +624,8 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { ScheduledAt: scheduledAt, } currentJobWithLineage := &scheduler.JobLineageSummary{ - JobName: jobTarget.JobName, + JobName: jobTarget.JobName, + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ jobTarget.JobName: { JobName: jobTarget.JobName, @@ -626,7 +635,8 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { Upstreams: []*scheduler.JobLineageSummary{}, } jobUpstreamWithLineage := &scheduler.JobLineageSummary{ - JobName: scheduler.JobName("job-B"), + JobName: scheduler.JobName("job-B"), + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ jobTarget.JobName: { JobName: scheduler.JobName("job-B"), @@ -675,7 +685,8 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { ScheduledAt: scheduledAt, } currentJobWithLineage := &scheduler.JobLineageSummary{ - JobName: jobTarget.JobName, + JobName: jobTarget.JobName, + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ jobTarget.JobName: { JobName: jobTarget.JobName, @@ -685,7 +696,8 @@ func TestPopulateEstimatedFinishTime(t *testing.T) { Upstreams: []*scheduler.JobLineageSummary{}, } jobUpstreamWithLineage := &scheduler.JobLineageSummary{ - JobName: scheduler.JobName("job-B"), + JobName: scheduler.JobName("job-B"), + IsEnabled: true, JobRuns: map[scheduler.JobName]*scheduler.JobRunSummary{ jobTarget.JobName: { JobName: scheduler.JobName("job-B"), From e863789dd7241902616597a38da4b825db468ff4 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Thu, 12 Feb 2026 15:06:38 +0700 Subject: [PATCH 14/26] refactor: estimated -> estimator + enrich api response --- Makefile | 2 +- core/scheduler/handler/v1beta1/job_run.go | 39 +- .../scheduler/handler/v1beta1/job_run_test.go | 60 +- .../service/job_estimator_service.go | 216 ----- .../service/job_expectator_service.go | 243 ++++++ ...test.go => job_expectator_service_test.go} | 233 ++--- ...0080_create_job_run_details_table.down.sql | 1 - ...job_run_expectation_details_table.down.sql | 1 + ..._job_run_expectation_details_table.up.sql} | 4 +- .../postgres/scheduler/job_run_repository.go | 10 +- .../optimus/core/v1beta1/job_run.pb.go | 817 ++++++++++-------- .../optimus/core/v1beta1/job_run.pb.gw.go | 32 +- .../optimus/core/v1beta1/job_run.swagger.json | 34 +- .../optimus/core/v1beta1/job_run_grpc.pb.go | 32 +- server/optimus.go | 4 +- 15 files changed, 949 insertions(+), 779 deletions(-) delete mode 100644 core/scheduler/service/job_estimator_service.go create mode 100644 core/scheduler/service/job_expectator_service.go rename core/scheduler/service/{job_estimator_service_test.go => job_expectator_service_test.go} (65%) delete mode 100644 internal/store/postgres/migrations/000080_create_job_run_details_table.down.sql create mode 100644 internal/store/postgres/migrations/000080_create_job_run_expectation_details_table.down.sql rename internal/store/postgres/migrations/{000080_create_job_run_details_table.up.sql => 000080_create_job_run_expectation_details_table.up.sql} (76%) diff --git a/Makefile b/Makefile index 296221cda3..303ed9971e 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ NAME = "github.com/goto/optimus" LAST_COMMIT := $(shell git rev-parse --short HEAD) LAST_TAG := "$(shell git rev-list --tags --max-count=1)" OPMS_VERSION := "$(shell git describe --tags ${LAST_TAG})-next" -PROTON_COMMIT := "977983ef13d406a54a1859aa419907d634272686" +PROTON_COMMIT := "ccb9ecd951b224d1466494fb4241a6223821e4b5" .PHONY: build test test-ci generate-proto unit-test-ci integration-test vet coverage clean install lint diff --git a/core/scheduler/handler/v1beta1/job_run.go b/core/scheduler/handler/v1beta1/job_run.go index 7eab51e79f..b745fc540a 100644 --- a/core/scheduler/handler/v1beta1/job_run.go +++ b/core/scheduler/handler/v1beta1/job_run.go @@ -37,8 +37,8 @@ type JobSLAPredictorService interface { IdentifySLABreaches(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string, reqConfig service.JobSLAPredictorRequestConfig) (map[scheduler.JobName]map[scheduler.JobName]*service.JobState, error) } -type JobEstimatorService interface { - GenerateEstimatedFinishTimes(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string, referenceTime time.Time, scheduleRangeInHours time.Duration) (map[scheduler.JobSchedule]time.Time, error) +type JobExpectatorService interface { + GenerateExpectedFinishTimes(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string, referenceTime time.Time, scheduleRangeInHours time.Duration) (map[scheduler.JobSchedule]service.FinishTimeDetail, error) } type JobRunService interface { @@ -77,7 +77,7 @@ type JobRunHandler struct { jobLineageService JobLineageService jobSLAPredictorService JobSLAPredictorService thirdPartySensorService ThirdPartySensorService - jobEstimatorService JobEstimatorService + jobExpectatorService JobExpectatorService pb.UnimplementedJobRunServiceServer } @@ -579,8 +579,8 @@ func (h JobRunHandler) GetJobRunLineageSummary(ctx context.Context, req *pb.GetJ return toJobRunLineageSummaryResponse(jobRunLineages), nil } -// GenerateEstimatedFinishTime generates estimated finish time for jobs based on their schedule in the given range -func (h JobRunHandler) GenerateEstimatedFinishTime(ctx context.Context, req *pb.GenerateEstimatedFinishTimeRequest) (*pb.GenerateEstimatedFinishTimeResponse, error) { +// GenerateExpectedFinishTime generates expected finish time for jobs based on their schedule in the given range +func (h JobRunHandler) GenerateExpectedFinishTime(ctx context.Context, req *pb.GenerateExpectedFinishTimeRequest) (*pb.GenerateExpectedFinishTimeResponse, error) { projectName, err := tenant.ProjectNameFrom(req.GetProjectName()) if err != nil { h.l.Error("error adapting project name [%s]: %s", req.GetProjectName(), err) @@ -603,17 +603,28 @@ func (h JobRunHandler) GenerateEstimatedFinishTime(ctx context.Context, req *pb. } scheduleRangeInHours := time.Duration(req.GetScheduledRangeInHours()) * time.Hour - estimatedFinishTimes, err := h.jobEstimatorService.GenerateEstimatedFinishTimes(ctx, projectName, jobNames, req.GetJobLabels(), referenceTime, scheduleRangeInHours) + jobsWithFinishTime, err := h.jobExpectatorService.GenerateExpectedFinishTimes(ctx, projectName, jobNames, req.GetJobLabels(), referenceTime, scheduleRangeInHours) if err != nil { - h.l.Error("error generating estimated finish times: %s", err) - return nil, errors.GRPCErr(err, "unable to generate estimated finish times") + h.l.Error("error generating expected finish times: %s", err) + return nil, errors.GRPCErr(err, "unable to generate expected finish times") } - response := &pb.GenerateEstimatedFinishTimeResponse{ - Jobs: make(map[string]*timestamppb.Timestamp), + response := &pb.GenerateExpectedFinishTimeResponse{ + InprogressJobs: make(map[string]*pb.FinishTimeDetailResponse), + FinishedJobs: make(map[string]*pb.FinishTimeDetailResponse), } - for jobSchedule, estimatedFinishTime := range estimatedFinishTimes { - response.Jobs[jobSchedule.JobName.String()] = timestamppb.New(estimatedFinishTime) + for jobSchedule, jobWithFinishTime := range jobsWithFinishTime { + finishTimeDetail := &pb.FinishTimeDetailResponse{ + ScheduledAt: timestamppb.New(jobSchedule.ScheduledAt), + ExpectedFinishTime: timestamppb.New(jobWithFinishTime.FinishTime), + } + + switch jobWithFinishTime.Status { + case service.FinishTimeStatusFinished: + response.FinishedJobs[jobSchedule.JobName.String()] = finishTimeDetail + case service.FinishTimeStatusInprogress: + response.InprogressJobs[jobSchedule.JobName.String()] = finishTimeDetail + } } return response, nil @@ -627,7 +638,7 @@ func NewJobRunHandler( jobLineageService JobLineageService, jobSLAPredictorService JobSLAPredictorService, thirdPartySensorService ThirdPartySensorService, - jobEstimatorService JobEstimatorService, + jobExpectatorService JobExpectatorService, ) *JobRunHandler { return &JobRunHandler{ l: l, @@ -637,6 +648,6 @@ func NewJobRunHandler( jobLineageService: jobLineageService, jobSLAPredictorService: jobSLAPredictorService, thirdPartySensorService: thirdPartySensorService, - jobEstimatorService: jobEstimatorService, + jobExpectatorService: jobExpectatorService, } } diff --git a/core/scheduler/handler/v1beta1/job_run_test.go b/core/scheduler/handler/v1beta1/job_run_test.go index 94df0aa3a9..a5028f81f2 100644 --- a/core/scheduler/handler/v1beta1/job_run_test.go +++ b/core/scheduler/handler/v1beta1/job_run_test.go @@ -1046,38 +1046,38 @@ func TestJobRunHandler(t *testing.T) { }) }) - t.Run("GenerateEstimatedFinishTime", func(t *testing.T) { + t.Run("GenerateExpectedFinishTime", func(t *testing.T) { t.Run("should return error when estimator service error", func(t *testing.T) { jobRunService := new(mockJobRunService) defer jobRunService.AssertExpectations(t) - jobEstimatorService := NewJobEstimatorService(t) - defer jobEstimatorService.AssertExpectations(t) + jobExpectatorService := NewJobExpectatorService(t) + defer jobExpectatorService.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, jobEstimatorService) + handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, jobExpectatorService) - req := &pb.GenerateEstimatedFinishTimeRequest{ + req := &pb.GenerateExpectedFinishTimeRequest{ ProjectName: projectName, JobNames: []string{"job-A"}, ScheduledRangeInHours: 12, } - jobEstimatorService.On("GenerateEstimatedFinishTimes", ctx, tenant.ProjectName(projectName), []scheduler.JobName{"job-A"}, mock.Anything, mock.Anything, 12*time.Hour).Return(nil, errors.New("service error")) - resp, err := handler.GenerateEstimatedFinishTime(ctx, req) + jobExpectatorService.On("GenerateExpectedFinishTimes", ctx, tenant.ProjectName(projectName), []scheduler.JobName{"job-A"}, mock.Anything, mock.Anything, 12*time.Hour).Return(nil, errors.New("service error")) + resp, err := handler.GenerateExpectedFinishTime(ctx, req) assert.NotNil(t, err) assert.Nil(t, resp) - assert.ErrorContains(t, err, "unable to generate estimated finish times") + assert.ErrorContains(t, err, "unable to generate expected finish times") }) - t.Run("should return estimated finish time successfully", func(t *testing.T) { + t.Run("should return expected finish time successfully", func(t *testing.T) { jobRunService := new(mockJobRunService) defer jobRunService.AssertExpectations(t) - jobEstimatorService := NewJobEstimatorService(t) - defer jobEstimatorService.AssertExpectations(t) + jobExpectatorService := NewJobExpectatorService(t) + defer jobExpectatorService.AssertExpectations(t) - handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, jobEstimatorService) + handler := v1beta1.NewJobRunHandler(logger, jobRunService, nil, nil, nil, nil, nil, jobExpectatorService) - req := &pb.GenerateEstimatedFinishTimeRequest{ + req := &pb.GenerateExpectedFinishTimeRequest{ ProjectName: projectName, JobNames: []string{"job-A"}, ScheduledRangeInHours: 12, @@ -1085,16 +1085,16 @@ func TestJobRunHandler(t *testing.T) { expectedFinishTime := timestamppb.New(time.Now().Add(30 * time.Minute)) - jobEstimatorService.On("GenerateEstimatedFinishTimes", ctx, tenant.ProjectName(projectName), []scheduler.JobName{"job-A"}, mock.Anything, mock.Anything, 12*time.Hour).Return(map[scheduler.JobSchedule]time.Time{ + jobExpectatorService.On("GenerateExpectedFinishTimes", ctx, tenant.ProjectName(projectName), []scheduler.JobName{"job-A"}, mock.Anything, mock.Anything, 12*time.Hour).Return(map[scheduler.JobSchedule]service.FinishTimeDetail{ { JobName: "job-A", ScheduledAt: time.Now(), - }: expectedFinishTime.AsTime(), + }: {FinishTime: expectedFinishTime.AsTime(), Status: service.FinishTimeStatusInprogress}, }, nil) - resp, err := handler.GenerateEstimatedFinishTime(ctx, req) + resp, err := handler.GenerateExpectedFinishTime(ctx, req) assert.Nil(t, err) assert.NotNil(t, resp) - assert.Equal(t, 1, len(resp.Jobs)) + assert.Equal(t, 1, len(resp.InprogressJobs)) }) }) } @@ -1205,29 +1205,29 @@ func (m *mockNotifier) Relay(ctx context.Context, event *scheduler.Event) error return args.Error(0) } -// JobEstimatorService is an autogenerated mock type for the JobEstimatorService type -type JobEstimatorService struct { +// JobExpectatorService is an autogenerated mock type for the JobExpectatorService type +type JobExpectatorService struct { mock.Mock } -// GenerateEstimatedFinishTimes provides a mock function with given fields: ctx, projectName, jobNames, labels, referenceTime, scheduleRangeInHours -func (_m *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string, referenceTime time.Time, scheduleRangeInHours time.Duration) (map[scheduler.JobSchedule]time.Time, error) { +// GenerateExpectedFinishTimes provides a mock function with given fields: ctx, projectName, jobNames, labels, referenceTime, scheduleRangeInHours +func (_m *JobExpectatorService) GenerateExpectedFinishTimes(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string, referenceTime time.Time, scheduleRangeInHours time.Duration) (map[scheduler.JobSchedule]service.FinishTimeDetail, error) { ret := _m.Called(ctx, projectName, jobNames, labels, referenceTime, scheduleRangeInHours) if len(ret) == 0 { - panic("no return value specified for GenerateEstimatedFinishTimes") + panic("no return value specified for GenerateExpectedFinishTimes") } - var r0 map[scheduler.JobSchedule]time.Time + var r0 map[scheduler.JobSchedule]service.FinishTimeDetail var r1 error - if rf, ok := ret.Get(0).(func(context.Context, tenant.ProjectName, []scheduler.JobName, map[string]string, time.Time, time.Duration) (map[scheduler.JobSchedule]time.Time, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, tenant.ProjectName, []scheduler.JobName, map[string]string, time.Time, time.Duration) (map[scheduler.JobSchedule]service.FinishTimeDetail, error)); ok { return rf(ctx, projectName, jobNames, labels, referenceTime, scheduleRangeInHours) } - if rf, ok := ret.Get(0).(func(context.Context, tenant.ProjectName, []scheduler.JobName, map[string]string, time.Time, time.Duration) map[scheduler.JobSchedule]time.Time); ok { + if rf, ok := ret.Get(0).(func(context.Context, tenant.ProjectName, []scheduler.JobName, map[string]string, time.Time, time.Duration) map[scheduler.JobSchedule]service.FinishTimeDetail); ok { r0 = rf(ctx, projectName, jobNames, labels, referenceTime, scheduleRangeInHours) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(map[scheduler.JobSchedule]time.Time) + r0 = ret.Get(0).(map[scheduler.JobSchedule]service.FinishTimeDetail) } } @@ -1240,14 +1240,14 @@ func (_m *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, return r0, r1 } -// NewJobEstimatorService creates a new instance of JobEstimatorService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// NewJobExpectatorService creates a new instance of JobExpectatorService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. -func NewJobEstimatorService(t interface { +func NewJobExpectatorService(t interface { mock.TestingT Cleanup(func()) }, -) *JobEstimatorService { - mock := &JobEstimatorService{} +) *JobExpectatorService { + mock := &JobExpectatorService{} mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/core/scheduler/service/job_estimator_service.go b/core/scheduler/service/job_estimator_service.go deleted file mode 100644 index 56847f541e..0000000000 --- a/core/scheduler/service/job_estimator_service.go +++ /dev/null @@ -1,216 +0,0 @@ -package service - -import ( - "context" - "time" - - "github.com/goto/salt/log" - - "github.com/goto/optimus/core/scheduler" - "github.com/goto/optimus/core/tenant" -) - -type JobRunDetailsRepository interface { - UpsertEstimatedFinishTime(ctx context.Context, projectName tenant.ProjectName, jobName scheduler.JobName, scheduledAt, estimatedFinishTime time.Time) error -} - -type JobEstimatorService struct { - l log.Logger - bufferTime time.Duration - jobRunDetailsRepo JobRunDetailsRepository - jobDetailsGetter JobDetailsGetter - jobLineageFetcher JobLineageFetcher - durationEstimator DurationEstimator -} - -func NewJobEstimatorService( - logger log.Logger, - jobRunDetailsRepo JobRunDetailsRepository, - jobDetailsGetter JobDetailsGetter, - jobLineageFetcher JobLineageFetcher, - durationEstimator DurationEstimator, -) *JobEstimatorService { - return &JobEstimatorService{ - l: logger, - bufferTime: 10 * time.Minute, // TODO: make this configurable - jobRunDetailsRepo: jobRunDetailsRepo, - jobDetailsGetter: jobDetailsGetter, - jobLineageFetcher: jobLineageFetcher, - durationEstimator: durationEstimator, - } -} - -func (s *JobEstimatorService) GenerateEstimatedFinishTimes(ctx context.Context, projectName tenant.ProjectName, jobNames []scheduler.JobName, labels map[string]string, referenceTime time.Time, scheduleRangeInHours time.Duration) (map[scheduler.JobSchedule]time.Time, error) { - jobRunEstimatedFinishTimes := make(map[scheduler.JobSchedule]time.Time) - - if len(jobNames) == 0 && len(labels) == 0 { - s.l.Warn("no job names or labels provided, skipping estimated finish time generation") - return jobRunEstimatedFinishTimes, nil - } - - // fetch job details - jobsWithDetails, err := getJobWithDetails(ctx, s.l, s.jobDetailsGetter, projectName, jobNames, labels) - if err != nil { - return nil, err - } - if len(jobsWithDetails) == 0 { - return jobRunEstimatedFinishTimes, nil - } - - // get scheduled at - jobSchedules := getJobSchedules(s.l, jobsWithDetails, scheduleRangeInHours, referenceTime) - if len(jobSchedules) == 0 { - s.l.Warn("no job schedules found for the given jobs in the next schedule range, skipping estimated finish time generation") - return jobRunEstimatedFinishTimes, nil - } - - // get lineage - jobsWithLineageMap, err := s.jobLineageFetcher.GetJobLineage(ctx, jobSchedules) - if err != nil { - s.l.Error("failed to get job lineage, skipping estimated finish time generation", "error", err) - return nil, err - } - - uniqueJobNames := collectJobNames(jobsWithLineageMap) - - // get job durations estimation - jobDurationsEstimation, err := s.durationEstimator.GetPercentileDurationByJobNames(ctx, referenceTime, uniqueJobNames) - if err != nil { - s.l.Error("failed to estimate job durations, skipping estimated finish time generation", "error", err) - return nil, err - } - - // calculate estimated finish time for each job - for _, jobSchedule := range jobSchedules { - if jobSchedule == nil { // safety check - s.l.Warn("nil job schedule provided, cannot calculate estimated finish time") - continue - } - key := *jobSchedule - if _, ok := jobRunEstimatedFinishTimes[key]; ok { // already calculated - continue - } - if _, ok := jobsWithLineageMap[jobSchedule.JobName]; !ok { // safety check - s.l.Warn("no lineage found for job, cannot calculate estimated finish time", "job", jobSchedule.JobName) - continue - } - s.l.Debug("calculating estimated finish time for job", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) - err := s.PopulateEstimatedFinishTime(jobSchedule, jobsWithLineageMap[jobSchedule.JobName], jobRunEstimatedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) - if err != nil { - s.l.Error("failed to populate estimated finish time for job", "job", jobSchedule.JobName, "error", err) - return nil, err - } - } - - // save to db - for _, jobSchedule := range jobSchedules { - key := *jobSchedule - estimatedFinishTime, ok := jobRunEstimatedFinishTimes[key] - if !ok { - s.l.Warn("estimated finish time not found for job schedule", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) - continue - } - s.l.Info("estimated finish time calculated", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt, "estimated_finish_time", estimatedFinishTime) - err := s.jobRunDetailsRepo.UpsertEstimatedFinishTime(ctx, projectName, jobSchedule.JobName, jobSchedule.ScheduledAt, estimatedFinishTime) - if err != nil { - s.l.Error("failed to upsert estimated finish time for job schedule", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt, "error", err) - return nil, err - } - } - - // estimated finish time generated for target jobs - finalJobRunEstimatedFinishTimes := make(map[scheduler.JobSchedule]time.Time) - for _, jobSchedule := range jobSchedules { - key := *jobSchedule - estimatedFinishTime, ok := jobRunEstimatedFinishTimes[key] - if !ok { - s.l.Warn("estimated finish time not found for job schedule", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) - continue - } - finalJobRunEstimatedFinishTimes[key] = estimatedFinishTime - } - - return finalJobRunEstimatedFinishTimes, nil -} - -func (s *JobEstimatorService) PopulateEstimatedFinishTime(jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunEstimatedFinishTimes map[scheduler.JobSchedule]time.Time, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { - // pre condition check - if currentJobWithLineage == nil || currentJobWithLineage.JobRuns[jobTarget.JobName] == nil { - s.l.Warn("no job run found for job, skipping estimated finish time calculation", "job", currentJobWithLineage.JobName) - return nil - } - if !currentJobWithLineage.IsEnabled { - s.l.Debug("job is disabled, skipping estimated finish time calculation", "job", currentJobWithLineage.JobName) - return nil - } - - currentJobRun := currentJobWithLineage.JobRuns[jobTarget.JobName] - currentJobScheduleKey := scheduler.JobSchedule{ - JobName: currentJobWithLineage.JobName, - ScheduledAt: currentJobRun.ScheduledAt, - } - estimatedDuration, ok := jobDurationsEstimation[currentJobWithLineage.JobName] - if !ok || estimatedDuration == nil { - // if no estimation found, we cannot proceed - s.l.Warn("no duration estimation found for job, cannot calculate estimated finish time", "job", currentJobWithLineage.JobName) - return nil - } - - // termination condition - // 1. cache if already calculated - if _, ok := jobRunEstimatedFinishTimes[currentJobScheduleKey]; ok { - s.l.Debug("estimated finish time already calculated for job, skipping", "job", currentJobWithLineage.JobName, "scheduled_at", currentJobRun.ScheduledAt) - return nil - } - // 2. if end_time is nil and scheduled_time+duration google.protobuf.Timestamp + 53, // 0: gotocompany.optimus.core.v1beta1.DataCompleteness.date:type_name -> google.protobuf.Timestamp 3, // 1: gotocompany.optimus.core.v1beta1.DexSensorResponse.log:type_name -> gotocompany.optimus.core.v1beta1.DataCompleteness - 51, // 2: gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest.scheduled_at:type_name -> google.protobuf.Timestamp + 53, // 2: gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest.scheduled_at:type_name -> google.protobuf.Timestamp 2, // 3: gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest.dex_sensor_request:type_name -> gotocompany.optimus.core.v1beta1.DexSensorRequest 4, // 4: gotocompany.optimus.core.v1beta1.GetThirdPartySensorResponse.dex_sensor_response:type_name -> gotocompany.optimus.core.v1beta1.DexSensorResponse - 51, // 5: gotocompany.optimus.core.v1beta1.GetIntervalRequest.reference_time:type_name -> google.protobuf.Timestamp - 51, // 6: gotocompany.optimus.core.v1beta1.GetIntervalResponse.start_time:type_name -> google.protobuf.Timestamp - 51, // 7: gotocompany.optimus.core.v1beta1.GetIntervalResponse.end_time:type_name -> google.protobuf.Timestamp - 52, // 8: gotocompany.optimus.core.v1beta1.RegisterJobEventRequest.event:type_name -> gotocompany.optimus.core.v1beta1.JobEvent - 51, // 9: gotocompany.optimus.core.v1beta1.JobRunInputRequest.scheduled_at:type_name -> google.protobuf.Timestamp + 53, // 5: gotocompany.optimus.core.v1beta1.GetIntervalRequest.reference_time:type_name -> google.protobuf.Timestamp + 53, // 6: gotocompany.optimus.core.v1beta1.GetIntervalResponse.start_time:type_name -> google.protobuf.Timestamp + 53, // 7: gotocompany.optimus.core.v1beta1.GetIntervalResponse.end_time:type_name -> google.protobuf.Timestamp + 54, // 8: gotocompany.optimus.core.v1beta1.RegisterJobEventRequest.event:type_name -> gotocompany.optimus.core.v1beta1.JobEvent + 53, // 9: gotocompany.optimus.core.v1beta1.JobRunInputRequest.scheduled_at:type_name -> google.protobuf.Timestamp 0, // 10: gotocompany.optimus.core.v1beta1.JobRunInputRequest.instance_type:type_name -> gotocompany.optimus.core.v1beta1.InstanceSpec.Type - 51, // 11: gotocompany.optimus.core.v1beta1.GetJobRunsRequest.since:type_name -> google.protobuf.Timestamp - 51, // 12: gotocompany.optimus.core.v1beta1.GetJobRunsRequest.until:type_name -> google.protobuf.Timestamp - 51, // 13: gotocompany.optimus.core.v1beta1.JobRunWithDetail.scheduled_at:type_name -> google.protobuf.Timestamp - 51, // 14: gotocompany.optimus.core.v1beta1.JobRunWithDetail.start_time:type_name -> google.protobuf.Timestamp - 51, // 15: gotocompany.optimus.core.v1beta1.JobRunWithDetail.end_time:type_name -> google.protobuf.Timestamp + 53, // 11: gotocompany.optimus.core.v1beta1.GetJobRunsRequest.since:type_name -> google.protobuf.Timestamp + 53, // 12: gotocompany.optimus.core.v1beta1.GetJobRunsRequest.until:type_name -> google.protobuf.Timestamp + 53, // 13: gotocompany.optimus.core.v1beta1.JobRunWithDetail.scheduled_at:type_name -> google.protobuf.Timestamp + 53, // 14: gotocompany.optimus.core.v1beta1.JobRunWithDetail.start_time:type_name -> google.protobuf.Timestamp + 53, // 15: gotocompany.optimus.core.v1beta1.JobRunWithDetail.end_time:type_name -> google.protobuf.Timestamp 15, // 16: gotocompany.optimus.core.v1beta1.GetJobRunsResponse.job_runs:type_name -> gotocompany.optimus.core.v1beta1.JobRunWithDetail - 51, // 17: gotocompany.optimus.core.v1beta1.JobRunRequest.start_date:type_name -> google.protobuf.Timestamp - 51, // 18: gotocompany.optimus.core.v1beta1.JobRunRequest.end_date:type_name -> google.protobuf.Timestamp - 53, // 19: gotocompany.optimus.core.v1beta1.JobRunResponse.job_runs:type_name -> gotocompany.optimus.core.v1beta1.JobRun + 53, // 17: gotocompany.optimus.core.v1beta1.JobRunRequest.start_date:type_name -> google.protobuf.Timestamp + 53, // 18: gotocompany.optimus.core.v1beta1.JobRunRequest.end_date:type_name -> google.protobuf.Timestamp + 55, // 19: gotocompany.optimus.core.v1beta1.JobRunResponse.job_runs:type_name -> gotocompany.optimus.core.v1beta1.JobRun 24, // 20: gotocompany.optimus.core.v1beta1.InstanceSpec.data:type_name -> gotocompany.optimus.core.v1beta1.InstanceSpecData - 51, // 21: gotocompany.optimus.core.v1beta1.InstanceSpec.executed_at:type_name -> google.protobuf.Timestamp + 53, // 21: gotocompany.optimus.core.v1beta1.InstanceSpec.executed_at:type_name -> google.protobuf.Timestamp 0, // 22: gotocompany.optimus.core.v1beta1.InstanceSpec.type:type_name -> gotocompany.optimus.core.v1beta1.InstanceSpec.Type 1, // 23: gotocompany.optimus.core.v1beta1.InstanceSpecData.type:type_name -> gotocompany.optimus.core.v1beta1.InstanceSpecData.Type - 44, // 24: gotocompany.optimus.core.v1beta1.JobRunInputResponse.envs:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.EnvsEntry - 45, // 25: gotocompany.optimus.core.v1beta1.JobRunInputResponse.files:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.FilesEntry - 46, // 26: gotocompany.optimus.core.v1beta1.JobRunInputResponse.secrets:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.SecretsEntry - 54, // 27: gotocompany.optimus.core.v1beta1.TaskWindow.size:type_name -> google.protobuf.Duration - 54, // 28: gotocompany.optimus.core.v1beta1.TaskWindow.offset:type_name -> google.protobuf.Duration + 45, // 24: gotocompany.optimus.core.v1beta1.JobRunInputResponse.envs:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.EnvsEntry + 46, // 25: gotocompany.optimus.core.v1beta1.JobRunInputResponse.files:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.FilesEntry + 47, // 26: gotocompany.optimus.core.v1beta1.JobRunInputResponse.secrets:type_name -> gotocompany.optimus.core.v1beta1.JobRunInputResponse.SecretsEntry + 56, // 27: gotocompany.optimus.core.v1beta1.TaskWindow.size:type_name -> google.protobuf.Duration + 56, // 28: gotocompany.optimus.core.v1beta1.TaskWindow.offset:type_name -> google.protobuf.Duration 28, // 29: gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryRequest.target_jobs:type_name -> gotocompany.optimus.core.v1beta1.TargetJobRunIdentifier - 51, // 30: gotocompany.optimus.core.v1beta1.TargetJobRunIdentifier.scheduled_at:type_name -> google.protobuf.Timestamp + 53, // 30: gotocompany.optimus.core.v1beta1.TargetJobRunIdentifier.scheduled_at:type_name -> google.protobuf.Timestamp 30, // 31: gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryResponse.jobs:type_name -> gotocompany.optimus.core.v1beta1.JobRunLineageSummary - 51, // 32: gotocompany.optimus.core.v1beta1.JobRunLineageSummary.scheduled_at:type_name -> google.protobuf.Timestamp + 53, // 32: gotocompany.optimus.core.v1beta1.JobRunLineageSummary.scheduled_at:type_name -> google.protobuf.Timestamp 34, // 33: gotocompany.optimus.core.v1beta1.JobRunLineageSummary.job_runs:type_name -> gotocompany.optimus.core.v1beta1.JobExecutionSummary 31, // 34: gotocompany.optimus.core.v1beta1.JobRunLineageSummary.execution_summary:type_name -> gotocompany.optimus.core.v1beta1.LineageExecutionSummary 33, // 35: gotocompany.optimus.core.v1beta1.LineageExecutionSummary.largest_scheduled_way_too_late_job:type_name -> gotocompany.optimus.core.v1beta1.LineageDelaySummary 33, // 36: gotocompany.optimus.core.v1beta1.LineageExecutionSummary.largest_system_scheduling_delay_job:type_name -> gotocompany.optimus.core.v1beta1.LineageDelaySummary 32, // 37: gotocompany.optimus.core.v1beta1.LineageExecutionSummary.top_longest_task_duration_jobs:type_name -> gotocompany.optimus.core.v1beta1.JobWithTaskDuration 32, // 38: gotocompany.optimus.core.v1beta1.LineageExecutionSummary.top_longest_hook_duration_jobs:type_name -> gotocompany.optimus.core.v1beta1.JobWithTaskDuration - 51, // 39: gotocompany.optimus.core.v1beta1.LineageDelaySummary.scheduled_at:type_name -> google.protobuf.Timestamp - 51, // 40: gotocompany.optimus.core.v1beta1.LineageDelaySummary.upstream_scheduled_at:type_name -> google.protobuf.Timestamp + 53, // 39: gotocompany.optimus.core.v1beta1.LineageDelaySummary.scheduled_at:type_name -> google.protobuf.Timestamp + 53, // 40: gotocompany.optimus.core.v1beta1.LineageDelaySummary.upstream_scheduled_at:type_name -> google.protobuf.Timestamp 37, // 41: gotocompany.optimus.core.v1beta1.JobExecutionSummary.sla:type_name -> gotocompany.optimus.core.v1beta1.SLAConfig 35, // 42: gotocompany.optimus.core.v1beta1.JobExecutionSummary.job_run_summary:type_name -> gotocompany.optimus.core.v1beta1.JobRunSummary 36, // 43: gotocompany.optimus.core.v1beta1.JobExecutionSummary.delay_summary:type_name -> gotocompany.optimus.core.v1beta1.JobRunDelaySummary - 51, // 44: gotocompany.optimus.core.v1beta1.JobRunSummary.scheduled_at:type_name -> google.protobuf.Timestamp - 51, // 45: gotocompany.optimus.core.v1beta1.JobRunSummary.sla_time:type_name -> google.protobuf.Timestamp - 51, // 46: gotocompany.optimus.core.v1beta1.JobRunSummary.job_start_time:type_name -> google.protobuf.Timestamp - 51, // 47: gotocompany.optimus.core.v1beta1.JobRunSummary.job_end_time:type_name -> google.protobuf.Timestamp - 51, // 48: gotocompany.optimus.core.v1beta1.JobRunSummary.wait_start_time:type_name -> google.protobuf.Timestamp - 51, // 49: gotocompany.optimus.core.v1beta1.JobRunSummary.wait_end_time:type_name -> google.protobuf.Timestamp - 51, // 50: gotocompany.optimus.core.v1beta1.JobRunSummary.task_start_time:type_name -> google.protobuf.Timestamp - 51, // 51: gotocompany.optimus.core.v1beta1.JobRunSummary.task_end_time:type_name -> google.protobuf.Timestamp - 51, // 52: gotocompany.optimus.core.v1beta1.JobRunSummary.hook_start_time:type_name -> google.protobuf.Timestamp - 51, // 53: gotocompany.optimus.core.v1beta1.JobRunSummary.hook_end_time:type_name -> google.protobuf.Timestamp - 54, // 54: gotocompany.optimus.core.v1beta1.SLAConfig.duration:type_name -> google.protobuf.Duration - 47, // 55: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.job_labels:type_name -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.JobLabelsEntry - 51, // 56: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.reference_time:type_name -> google.protobuf.Timestamp - 48, // 57: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.jobs:type_name -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry - 51, // 58: gotocompany.optimus.core.v1beta1.UpstreamJobStatus.inferred_sla_time:type_name -> google.protobuf.Timestamp - 51, // 59: gotocompany.optimus.core.v1beta1.UpstreamJobStatus.scheduled_at:type_name -> google.protobuf.Timestamp + 53, // 44: gotocompany.optimus.core.v1beta1.JobRunSummary.scheduled_at:type_name -> google.protobuf.Timestamp + 53, // 45: gotocompany.optimus.core.v1beta1.JobRunSummary.sla_time:type_name -> google.protobuf.Timestamp + 53, // 46: gotocompany.optimus.core.v1beta1.JobRunSummary.job_start_time:type_name -> google.protobuf.Timestamp + 53, // 47: gotocompany.optimus.core.v1beta1.JobRunSummary.job_end_time:type_name -> google.protobuf.Timestamp + 53, // 48: gotocompany.optimus.core.v1beta1.JobRunSummary.wait_start_time:type_name -> google.protobuf.Timestamp + 53, // 49: gotocompany.optimus.core.v1beta1.JobRunSummary.wait_end_time:type_name -> google.protobuf.Timestamp + 53, // 50: gotocompany.optimus.core.v1beta1.JobRunSummary.task_start_time:type_name -> google.protobuf.Timestamp + 53, // 51: gotocompany.optimus.core.v1beta1.JobRunSummary.task_end_time:type_name -> google.protobuf.Timestamp + 53, // 52: gotocompany.optimus.core.v1beta1.JobRunSummary.hook_start_time:type_name -> google.protobuf.Timestamp + 53, // 53: gotocompany.optimus.core.v1beta1.JobRunSummary.hook_end_time:type_name -> google.protobuf.Timestamp + 56, // 54: gotocompany.optimus.core.v1beta1.SLAConfig.duration:type_name -> google.protobuf.Duration + 48, // 55: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.job_labels:type_name -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.JobLabelsEntry + 53, // 56: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest.reference_time:type_name -> google.protobuf.Timestamp + 49, // 57: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.jobs:type_name -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry + 53, // 58: gotocompany.optimus.core.v1beta1.UpstreamJobStatus.inferred_sla_time:type_name -> google.protobuf.Timestamp + 53, // 59: gotocompany.optimus.core.v1beta1.UpstreamJobStatus.scheduled_at:type_name -> google.protobuf.Timestamp 40, // 60: gotocompany.optimus.core.v1beta1.UpstreamJobsStatus.jobs_status:type_name -> gotocompany.optimus.core.v1beta1.UpstreamJobStatus - 49, // 61: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeRequest.job_labels:type_name -> gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeRequest.JobLabelsEntry - 51, // 62: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeRequest.reference_time:type_name -> google.protobuf.Timestamp - 50, // 63: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeResponse.jobs:type_name -> gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeResponse.JobsEntry - 41, // 64: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.UpstreamJobsStatus - 51, // 65: gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeResponse.JobsEntry.value:type_name -> google.protobuf.Timestamp - 13, // 66: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:input_type -> gotocompany.optimus.core.v1beta1.JobRunInputRequest - 17, // 67: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:input_type -> gotocompany.optimus.core.v1beta1.JobRunRequest - 19, // 68: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleRequest - 21, // 69: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleRequest - 14, // 70: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunsRequest - 5, // 71: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:input_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest - 11, // 72: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:input_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventRequest - 9, // 73: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:input_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerRequest - 7, // 74: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:input_type -> gotocompany.optimus.core.v1beta1.GetIntervalRequest - 27, // 75: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryRequest - 38, // 76: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:input_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest - 42, // 77: gotocompany.optimus.core.v1beta1.JobRunService.GenerateEstimatedFinishTime:input_type -> gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeRequest - 25, // 78: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:output_type -> gotocompany.optimus.core.v1beta1.JobRunInputResponse - 18, // 79: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:output_type -> gotocompany.optimus.core.v1beta1.JobRunResponse - 20, // 80: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleResponse - 22, // 81: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleResponse - 16, // 82: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunsResponse - 6, // 83: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:output_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorResponse - 12, // 84: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:output_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventResponse - 10, // 85: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:output_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerResponse - 8, // 86: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:output_type -> gotocompany.optimus.core.v1beta1.GetIntervalResponse - 29, // 87: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryResponse - 39, // 88: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:output_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse - 43, // 89: gotocompany.optimus.core.v1beta1.JobRunService.GenerateEstimatedFinishTime:output_type -> gotocompany.optimus.core.v1beta1.GenerateEstimatedFinishTimeResponse - 78, // [78:90] is the sub-list for method output_type - 66, // [66:78] is the sub-list for method input_type - 66, // [66:66] is the sub-list for extension type_name - 66, // [66:66] is the sub-list for extension extendee - 0, // [0:66] is the sub-list for field type_name + 50, // 61: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeRequest.job_labels:type_name -> gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeRequest.JobLabelsEntry + 53, // 62: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeRequest.reference_time:type_name -> google.protobuf.Timestamp + 51, // 63: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.inprogress_jobs:type_name -> gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.InprogressJobsEntry + 52, // 64: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.finished_jobs:type_name -> gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.FinishedJobsEntry + 53, // 65: gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse.scheduled_at:type_name -> google.protobuf.Timestamp + 53, // 66: gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse.expected_finish_time:type_name -> google.protobuf.Timestamp + 41, // 67: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.UpstreamJobsStatus + 44, // 68: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.InprogressJobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse + 44, // 69: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.FinishedJobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse + 13, // 70: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:input_type -> gotocompany.optimus.core.v1beta1.JobRunInputRequest + 17, // 71: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:input_type -> gotocompany.optimus.core.v1beta1.JobRunRequest + 19, // 72: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleRequest + 21, // 73: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleRequest + 14, // 74: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunsRequest + 5, // 75: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:input_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest + 11, // 76: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:input_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventRequest + 9, // 77: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:input_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerRequest + 7, // 78: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:input_type -> gotocompany.optimus.core.v1beta1.GetIntervalRequest + 27, // 79: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryRequest + 38, // 80: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:input_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest + 42, // 81: gotocompany.optimus.core.v1beta1.JobRunService.GenerateExpectedFinishTime:input_type -> gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeRequest + 25, // 82: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:output_type -> gotocompany.optimus.core.v1beta1.JobRunInputResponse + 18, // 83: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:output_type -> gotocompany.optimus.core.v1beta1.JobRunResponse + 20, // 84: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleResponse + 22, // 85: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleResponse + 16, // 86: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunsResponse + 6, // 87: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:output_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorResponse + 12, // 88: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:output_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventResponse + 10, // 89: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:output_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerResponse + 8, // 90: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:output_type -> gotocompany.optimus.core.v1beta1.GetIntervalResponse + 29, // 91: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryResponse + 39, // 92: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:output_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse + 43, // 93: gotocompany.optimus.core.v1beta1.JobRunService.GenerateExpectedFinishTime:output_type -> gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse + 82, // [82:94] is the sub-list for method output_type + 70, // [70:82] is the sub-list for method input_type + 70, // [70:70] is the sub-list for extension type_name + 70, // [70:70] is the sub-list for extension extendee + 0, // [0:70] is the sub-list for field type_name } func init() { file_gotocompany_optimus_core_v1beta1_job_run_proto_init() } @@ -4369,7 +4468,7 @@ func file_gotocompany_optimus_core_v1beta1_job_run_proto_init() { } } file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GenerateEstimatedFinishTimeRequest); i { + switch v := v.(*GenerateExpectedFinishTimeRequest); i { case 0: return &v.state case 1: @@ -4381,7 +4480,19 @@ func file_gotocompany_optimus_core_v1beta1_job_run_proto_init() { } } file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GenerateEstimatedFinishTimeResponse); i { + switch v := v.(*GenerateExpectedFinishTimeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FinishTimeDetailResponse); i { case 0: return &v.state case 1: @@ -4406,7 +4517,7 @@ func file_gotocompany_optimus_core_v1beta1_job_run_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_gotocompany_optimus_core_v1beta1_job_run_proto_rawDesc, NumEnums: 2, - NumMessages: 49, + NumMessages: 51, NumExtensions: 0, NumServices: 1, }, diff --git a/protos/gotocompany/optimus/core/v1beta1/job_run.pb.gw.go b/protos/gotocompany/optimus/core/v1beta1/job_run.pb.gw.go index 966f67386a..f7bc0edf82 100644 --- a/protos/gotocompany/optimus/core/v1beta1/job_run.pb.gw.go +++ b/protos/gotocompany/optimus/core/v1beta1/job_run.pb.gw.go @@ -935,8 +935,8 @@ func local_request_JobRunService_IdentifyPotentialSLABreach_0(ctx context.Contex } -func request_JobRunService_GenerateEstimatedFinishTime_0(ctx context.Context, marshaler runtime.Marshaler, client JobRunServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GenerateEstimatedFinishTimeRequest +func request_JobRunService_GenerateExpectedFinishTime_0(ctx context.Context, marshaler runtime.Marshaler, client JobRunServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GenerateExpectedFinishTimeRequest var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -964,13 +964,13 @@ func request_JobRunService_GenerateEstimatedFinishTime_0(ctx context.Context, ma return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project_name", err) } - msg, err := client.GenerateEstimatedFinishTime(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GenerateExpectedFinishTime(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_JobRunService_GenerateEstimatedFinishTime_0(ctx context.Context, marshaler runtime.Marshaler, server JobRunServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GenerateEstimatedFinishTimeRequest +func local_request_JobRunService_GenerateExpectedFinishTime_0(ctx context.Context, marshaler runtime.Marshaler, server JobRunServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GenerateExpectedFinishTimeRequest var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -998,7 +998,7 @@ func local_request_JobRunService_GenerateEstimatedFinishTime_0(ctx context.Conte return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project_name", err) } - msg, err := server.GenerateEstimatedFinishTime(ctx, &protoReq) + msg, err := server.GenerateExpectedFinishTime(ctx, &protoReq) return msg, metadata, err } @@ -1262,18 +1262,18 @@ func RegisterJobRunServiceHandlerServer(ctx context.Context, mux *runtime.ServeM }) - mux.Handle("POST", pattern_JobRunService_GenerateEstimatedFinishTime_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_JobRunService_GenerateExpectedFinishTime_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateEstimatedFinishTime", runtime.WithHTTPPathPattern("/v1beta1/project/{project_name}/estimate_job_finish_time")) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateExpectedFinishTime", runtime.WithHTTPPathPattern("/v1beta1/project/{project_name}/expected_job_finish_time")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_JobRunService_GenerateEstimatedFinishTime_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_JobRunService_GenerateExpectedFinishTime_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -1281,7 +1281,7 @@ func RegisterJobRunServiceHandlerServer(ctx context.Context, mux *runtime.ServeM return } - forward_JobRunService_GenerateEstimatedFinishTime_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_JobRunService_GenerateExpectedFinishTime_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -1546,23 +1546,23 @@ func RegisterJobRunServiceHandlerClient(ctx context.Context, mux *runtime.ServeM }) - mux.Handle("POST", pattern_JobRunService_GenerateEstimatedFinishTime_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_JobRunService_GenerateExpectedFinishTime_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateEstimatedFinishTime", runtime.WithHTTPPathPattern("/v1beta1/project/{project_name}/estimate_job_finish_time")) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateExpectedFinishTime", runtime.WithHTTPPathPattern("/v1beta1/project/{project_name}/expected_job_finish_time")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_JobRunService_GenerateEstimatedFinishTime_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_JobRunService_GenerateExpectedFinishTime_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_JobRunService_GenerateEstimatedFinishTime_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_JobRunService_GenerateExpectedFinishTime_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -1592,7 +1592,7 @@ var ( pattern_JobRunService_IdentifyPotentialSLABreach_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 2, 4}, []string{"v1beta1", "project", "project_name", "potential_sla_breach", "identify"}, "")) - pattern_JobRunService_GenerateEstimatedFinishTime_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"v1beta1", "project", "project_name", "estimate_job_finish_time"}, "")) + pattern_JobRunService_GenerateExpectedFinishTime_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"v1beta1", "project", "project_name", "expected_job_finish_time"}, "")) ) var ( @@ -1618,5 +1618,5 @@ var ( forward_JobRunService_IdentifyPotentialSLABreach_0 = runtime.ForwardResponseMessage - forward_JobRunService_GenerateEstimatedFinishTime_0 = runtime.ForwardResponseMessage + forward_JobRunService_GenerateExpectedFinishTime_0 = runtime.ForwardResponseMessage ) diff --git a/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json b/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json index 2c3888e2d7..06fa2e1659 100644 --- a/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json +++ b/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json @@ -54,15 +54,15 @@ ] } }, - "/v1beta1/project/{projectName}/estimate_job_finish_time": { + "/v1beta1/project/{projectName}/expected_job_finish_time": { "post": { - "summary": "GenerateEstimatedFinishTime generates and stores the estimated finish time for a given job(s)", - "operationId": "JobRunService_GenerateEstimatedFinishTime", + "summary": "GenerateExpectedFinishTime generates and stores the expected finish time for a given job(s)", + "operationId": "JobRunService_GenerateExpectedFinishTime", "responses": { "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/v1beta1GenerateEstimatedFinishTimeResponse" + "$ref": "#/definitions/v1beta1GenerateExpectedFinishTimeResponse" } }, "default": { @@ -745,14 +745,32 @@ } } }, - "v1beta1GenerateEstimatedFinishTimeResponse": { + "v1beta1FinishTimeDetailResponse": { "type": "object", "properties": { - "jobs": { + "scheduledAt": { + "type": "string", + "format": "date-time" + }, + "expectedFinishTime": { + "type": "string", + "format": "date-time" + } + } + }, + "v1beta1GenerateExpectedFinishTimeResponse": { + "type": "object", + "properties": { + "inprogressJobs": { "type": "object", "additionalProperties": { - "type": "string", - "format": "date-time" + "$ref": "#/definitions/v1beta1FinishTimeDetailResponse" + } + }, + "finishedJobs": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/v1beta1FinishTimeDetailResponse" } } } diff --git a/protos/gotocompany/optimus/core/v1beta1/job_run_grpc.pb.go b/protos/gotocompany/optimus/core/v1beta1/job_run_grpc.pb.go index d50c1b9c47..024a3f4dfe 100644 --- a/protos/gotocompany/optimus/core/v1beta1/job_run_grpc.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/job_run_grpc.pb.go @@ -43,8 +43,8 @@ type JobRunServiceClient interface { GetJobRunLineageSummary(ctx context.Context, in *GetJobRunLineageSummaryRequest, opts ...grpc.CallOption) (*GetJobRunLineageSummaryResponse, error) // IdentifyPotentialSLABreach notifies optimus service about potential SLA breach for given job(s) IdentifyPotentialSLABreach(ctx context.Context, in *IdentifyPotentialSLABreachRequest, opts ...grpc.CallOption) (*IdentifyPotentialSLABreachResponse, error) - // GenerateEstimatedFinishTime generates and stores the estimated finish time for a given job(s) - GenerateEstimatedFinishTime(ctx context.Context, in *GenerateEstimatedFinishTimeRequest, opts ...grpc.CallOption) (*GenerateEstimatedFinishTimeResponse, error) + // GenerateExpectedFinishTime generates and stores the expected finish time for a given job(s) + GenerateExpectedFinishTime(ctx context.Context, in *GenerateExpectedFinishTimeRequest, opts ...grpc.CallOption) (*GenerateExpectedFinishTimeResponse, error) } type jobRunServiceClient struct { @@ -154,9 +154,9 @@ func (c *jobRunServiceClient) IdentifyPotentialSLABreach(ctx context.Context, in return out, nil } -func (c *jobRunServiceClient) GenerateEstimatedFinishTime(ctx context.Context, in *GenerateEstimatedFinishTimeRequest, opts ...grpc.CallOption) (*GenerateEstimatedFinishTimeResponse, error) { - out := new(GenerateEstimatedFinishTimeResponse) - err := c.cc.Invoke(ctx, "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateEstimatedFinishTime", in, out, opts...) +func (c *jobRunServiceClient) GenerateExpectedFinishTime(ctx context.Context, in *GenerateExpectedFinishTimeRequest, opts ...grpc.CallOption) (*GenerateExpectedFinishTimeResponse, error) { + out := new(GenerateExpectedFinishTimeResponse) + err := c.cc.Invoke(ctx, "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateExpectedFinishTime", in, out, opts...) if err != nil { return nil, err } @@ -188,8 +188,8 @@ type JobRunServiceServer interface { GetJobRunLineageSummary(context.Context, *GetJobRunLineageSummaryRequest) (*GetJobRunLineageSummaryResponse, error) // IdentifyPotentialSLABreach notifies optimus service about potential SLA breach for given job(s) IdentifyPotentialSLABreach(context.Context, *IdentifyPotentialSLABreachRequest) (*IdentifyPotentialSLABreachResponse, error) - // GenerateEstimatedFinishTime generates and stores the estimated finish time for a given job(s) - GenerateEstimatedFinishTime(context.Context, *GenerateEstimatedFinishTimeRequest) (*GenerateEstimatedFinishTimeResponse, error) + // GenerateExpectedFinishTime generates and stores the expected finish time for a given job(s) + GenerateExpectedFinishTime(context.Context, *GenerateExpectedFinishTimeRequest) (*GenerateExpectedFinishTimeResponse, error) mustEmbedUnimplementedJobRunServiceServer() } @@ -230,8 +230,8 @@ func (UnimplementedJobRunServiceServer) GetJobRunLineageSummary(context.Context, func (UnimplementedJobRunServiceServer) IdentifyPotentialSLABreach(context.Context, *IdentifyPotentialSLABreachRequest) (*IdentifyPotentialSLABreachResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method IdentifyPotentialSLABreach not implemented") } -func (UnimplementedJobRunServiceServer) GenerateEstimatedFinishTime(context.Context, *GenerateEstimatedFinishTimeRequest) (*GenerateEstimatedFinishTimeResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GenerateEstimatedFinishTime not implemented") +func (UnimplementedJobRunServiceServer) GenerateExpectedFinishTime(context.Context, *GenerateExpectedFinishTimeRequest) (*GenerateExpectedFinishTimeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenerateExpectedFinishTime not implemented") } func (UnimplementedJobRunServiceServer) mustEmbedUnimplementedJobRunServiceServer() {} @@ -444,20 +444,20 @@ func _JobRunService_IdentifyPotentialSLABreach_Handler(srv interface{}, ctx cont return interceptor(ctx, in, info, handler) } -func _JobRunService_GenerateEstimatedFinishTime_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GenerateEstimatedFinishTimeRequest) +func _JobRunService_GenerateExpectedFinishTime_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GenerateExpectedFinishTimeRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(JobRunServiceServer).GenerateEstimatedFinishTime(ctx, in) + return srv.(JobRunServiceServer).GenerateExpectedFinishTime(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateEstimatedFinishTime", + FullMethod: "/gotocompany.optimus.core.v1beta1.JobRunService/GenerateExpectedFinishTime", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(JobRunServiceServer).GenerateEstimatedFinishTime(ctx, req.(*GenerateEstimatedFinishTimeRequest)) + return srv.(JobRunServiceServer).GenerateExpectedFinishTime(ctx, req.(*GenerateExpectedFinishTimeRequest)) } return interceptor(ctx, in, info, handler) } @@ -514,8 +514,8 @@ var JobRunService_ServiceDesc = grpc.ServiceDesc{ Handler: _JobRunService_IdentifyPotentialSLABreach_Handler, }, { - MethodName: "GenerateEstimatedFinishTime", - Handler: _JobRunService_GenerateEstimatedFinishTime_Handler, + MethodName: "GenerateExpectedFinishTime", + Handler: _JobRunService_GenerateExpectedFinishTime_Handler, }, }, Streams: []grpc.StreamDesc{}, diff --git a/server/optimus.go b/server/optimus.go index 2e9e371ba0..d98daad11b 100644 --- a/server/optimus.go +++ b/server/optimus.go @@ -446,7 +446,7 @@ func (s *OptimusServer) setupHandlers() error { newJobSLAPredictorService := schedulerService.NewJobSLAPredictorService(s.logger, s.conf.Alerting.PotentialSLABreachConfig, slaRepository, jobLineageService, newDurationEstimatorService, jobProviderRepo, alertsHandler, tenantService, newJobRunService) // Job Estimator Service - jobEstimatorService := schedulerService.NewJobEstimatorService(s.logger, jobRunRepo, jobProviderRepo, jobLineageService, newDurationEstimatorService) + jobExpectatorService := schedulerService.NewJobExpectatorService(s.logger, jobRunRepo, jobProviderRepo, jobLineageService, newDurationEstimatorService) // Resource Bounded Context primaryResourceService := rService.NewResourceService(s.logger, resourceRepository, jJobService, resourceManager, s.eventHandler, jJobService, alertsHandler, tenantService, newEngine, syncer, syncStatusRepository) @@ -490,7 +490,7 @@ func (s *OptimusServer) setupHandlers() error { pb.RegisterResourceServiceServer(s.grpcServer, rHandler.NewResourceHandler(s.logger, primaryResourceService, resourceChangeLogService)) sensorService := schedulerService.NewSensorService(s.logger, s.conf.UpstreamResolvers...) - pb.RegisterJobRunServiceServer(s.grpcServer, schedulerHandler.NewJobRunHandler(s.logger, newJobRunService, eventsService, newSchedulerService, jobLineageService, newJobSLAPredictorService, sensorService, jobEstimatorService)) + pb.RegisterJobRunServiceServer(s.grpcServer, schedulerHandler.NewJobRunHandler(s.logger, newJobRunService, eventsService, newSchedulerService, jobLineageService, newJobSLAPredictorService, sensorService, jobExpectatorService)) // backup service pb.RegisterBackupServiceServer(s.grpcServer, rHandler.NewBackupHandler(s.logger, backupService)) From ffd85d25ed887652027d988605f1813f87ca6f2a Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Thu, 12 Feb 2026 15:12:06 +0700 Subject: [PATCH 15/26] refactor: remove unecessary vars --- .../service/job_expectator_service.go | 6 ++-- .../service/job_expectator_service_test.go | 28 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/core/scheduler/service/job_expectator_service.go b/core/scheduler/service/job_expectator_service.go index 618c59cbe0..0263ff6bab 100644 --- a/core/scheduler/service/job_expectator_service.go +++ b/core/scheduler/service/job_expectator_service.go @@ -107,7 +107,7 @@ func (s *JobExpectatorService) GenerateExpectedFinishTimes(ctx context.Context, continue } s.l.Debug("calculating expected finish time for job", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) - err := s.PopulateExpectedFinishTime(jobSchedule, jobsWithLineageMap[jobSchedule.JobName], jobRunExpectedFinishTimeDetail, jobsWithLineageMap, jobDurationsEstimation, referenceTime) + err := s.PopulateExpectedFinishTime(jobSchedule, jobsWithLineageMap[jobSchedule.JobName], jobRunExpectedFinishTimeDetail, jobDurationsEstimation, referenceTime) if err != nil { s.l.Error("failed to populate expected finish time for job", "job", jobSchedule.JobName, "error", err) return nil, err @@ -148,7 +148,7 @@ func (s *JobExpectatorService) GenerateExpectedFinishTimes(ctx context.Context, return finalJobRunExpectedFinishTimes, nil } -func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunExpectedFinishTimes map[scheduler.JobSchedule]FinishTimeDetail, jobsWithLineageMap map[scheduler.JobName]*scheduler.JobLineageSummary, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { +func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunExpectedFinishTimes map[scheduler.JobSchedule]FinishTimeDetail, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { // pre condition check if currentJobWithLineage == nil || currentJobWithLineage.JobRuns[jobTarget.JobName] == nil { s.l.Warn("no job run found for job, skipping expected finish time calculation", "job", currentJobWithLineage.JobName) @@ -210,7 +210,7 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J s.l.Debug("no upstream job run found for job, skipping upstream in expected finish time calculation", "job", currentJobWithLineage.JobName, "upstream_job", upstream.JobName) continue } - err := s.PopulateExpectedFinishTime(jobTarget, upstream, jobRunExpectedFinishTimes, jobsWithLineageMap, jobDurationsEstimation, referenceTime) + err := s.PopulateExpectedFinishTime(jobTarget, upstream, jobRunExpectedFinishTimes, jobDurationsEstimation, referenceTime) if err != nil { return err } diff --git a/core/scheduler/service/job_expectator_service_test.go b/core/scheduler/service/job_expectator_service_test.go index b245937d08..d7bfba928c 100644 --- a/core/scheduler/service/job_expectator_service_test.go +++ b/core/scheduler/service/job_expectator_service_test.go @@ -360,7 +360,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() // when - err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) @@ -405,7 +405,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { // no duration estimation added // when - err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) @@ -455,11 +455,11 @@ func TestPopulateExpectedFinishTime(t *testing.T) { } // when - err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) // should not be updated - assert.Equal(t, scheduledAt.Add(25*time.Minute), jobRunExpectedFinishTime[*jobTarget]) + assert.Equal(t, scheduledAt.Add(25*time.Minute), jobRunExpectedFinishTime[*jobTarget].FinishTime) }) t.Run("when end_time is nil and running late, should set expected finish time to reference time + buffer", func(t *testing.T) { @@ -501,12 +501,12 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() // when - err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) expectedExpectedFinishTime := referenceTime.Add(bufferTime) - assert.Equal(t, expectedExpectedFinishTime, jobRunExpectedFinishTime[*jobTarget]) + assert.Equal(t, expectedExpectedFinishTime, jobRunExpectedFinishTime[*jobTarget].FinishTime) }) t.Run("when end_time is not nil, should set expected finish time to job end time", func(t *testing.T) { @@ -549,11 +549,11 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() // when - err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) - assert.Equal(t, jobEndTime, jobRunExpectedFinishTime[*jobTarget]) + assert.Equal(t, jobEndTime, jobRunExpectedFinishTime[*jobTarget].FinishTime) }) t.Run("when targeted job will run in the future, should set expected finish time to scheduled at + expected duration", func(t *testing.T) { @@ -594,12 +594,12 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobDurationEstimation[jobTarget.JobName] = func() *time.Duration { d := 30 * time.Minute; return &d }() // when - err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) expectedExpectedFinishTime := scheduledAt.Add(30 * time.Minute) - assert.Equal(t, expectedExpectedFinishTime, jobRunExpectedFinishTime[*jobTarget]) + assert.Equal(t, expectedExpectedFinishTime, jobRunExpectedFinishTime[*jobTarget].FinishTime) }) t.Run("when targeted job will run in the future, and there's an upstream job running late, should set expected finish time to max(upstream expected finish time, scheduled_at) + expected duration", func(t *testing.T) { @@ -655,12 +655,12 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobDurationEstimation[jobUpstreamWithLineage.JobName] = func() *time.Duration { d := 45 * time.Minute; return &d }() // when - err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) expectedExpectedFinishTime := scheduledAt.Add(30 * time.Minute) - assert.Equal(t, expectedExpectedFinishTime, jobRunExpectedFinishTime[*jobTarget]) + assert.Equal(t, expectedExpectedFinishTime, jobRunExpectedFinishTime[*jobTarget].FinishTime) }) t.Run("when targeted job will run in the future, and there's an upstream job running late, and expected finish time for upstream is greater than scheduled_at, should set expected finish time to max(upstream expected finish time, scheduled_at) + expected duration", func(t *testing.T) { @@ -716,12 +716,12 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobDurationEstimation[jobUpstreamWithLineage.JobName] = func() *time.Duration { d := 45 * time.Minute; return &d }() // when - err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobWithLineageMap, jobDurationEstimation, referenceTime) + err := jobExpectatorService.PopulateExpectedFinishTime(jobTarget, currentJobWithLineage, jobRunExpectedFinishTime, jobDurationEstimation, referenceTime) // then assert.NoError(t, err) expectedExpectedFinishTime := referenceTime.Add(10 * time.Minute).Add(30 * time.Minute) - assert.Equal(t, expectedExpectedFinishTime, jobRunExpectedFinishTime[*jobTarget]) + assert.Equal(t, expectedExpectedFinishTime, jobRunExpectedFinishTime[*jobTarget].FinishTime) }) } From c9723ec6ca38ba4c6718c315b087a4fd26270bfb Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Fri, 13 Feb 2026 15:30:11 +0700 Subject: [PATCH 16/26] feat: create table if not exist --- .../000080_create_job_run_expectation_details_table.up.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/store/postgres/migrations/000080_create_job_run_expectation_details_table.up.sql b/internal/store/postgres/migrations/000080_create_job_run_expectation_details_table.up.sql index 940df9ee44..59de0321a3 100644 --- a/internal/store/postgres/migrations/000080_create_job_run_expectation_details_table.up.sql +++ b/internal/store/postgres/migrations/000080_create_job_run_expectation_details_table.up.sql @@ -1,4 +1,4 @@ -CREATE TABLE job_run_expectation_details ( +CREATE TABLE IF NOT EXISTS job_run_expectation_details ( project_name TEXT NOT NULL, job_name TEXT NOT NULL, scheduled_at TIMESTAMPTZ NOT NULL, From 51802842ecaa7034bf1f1eff8cbd3ce0b03af853 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Fri, 13 Feb 2026 15:34:50 +0700 Subject: [PATCH 17/26] refactor: update the log using fmt.Sprintf --- core/scheduler/handler/v1beta1/job_run.go | 6 ++-- .../service/job_expectator_service.go | 33 ++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/core/scheduler/handler/v1beta1/job_run.go b/core/scheduler/handler/v1beta1/job_run.go index b745fc540a..edcd61b399 100644 --- a/core/scheduler/handler/v1beta1/job_run.go +++ b/core/scheduler/handler/v1beta1/job_run.go @@ -583,7 +583,7 @@ func (h JobRunHandler) GetJobRunLineageSummary(ctx context.Context, req *pb.GetJ func (h JobRunHandler) GenerateExpectedFinishTime(ctx context.Context, req *pb.GenerateExpectedFinishTimeRequest) (*pb.GenerateExpectedFinishTimeResponse, error) { projectName, err := tenant.ProjectNameFrom(req.GetProjectName()) if err != nil { - h.l.Error("error adapting project name [%s]: %s", req.GetProjectName(), err) + h.l.Error(fmt.Sprintf("error adapting project name [%s]: %s", req.GetProjectName(), err.Error())) return nil, errors.GRPCErr(err, "unable to adapt project name") } @@ -591,7 +591,7 @@ func (h JobRunHandler) GenerateExpectedFinishTime(ctx context.Context, req *pb.G for _, jn := range req.GetJobNames() { jobName, err := scheduler.JobNameFrom(jn) if err != nil { - h.l.Error("error adapting job name [%s]: %s", jn, err) + h.l.Error(fmt.Sprintf("error adapting job name [%s]: %s", jn, err.Error())) return nil, errors.GRPCErr(err, "unable to adapt job name") } jobNames = append(jobNames, jobName) @@ -605,7 +605,7 @@ func (h JobRunHandler) GenerateExpectedFinishTime(ctx context.Context, req *pb.G jobsWithFinishTime, err := h.jobExpectatorService.GenerateExpectedFinishTimes(ctx, projectName, jobNames, req.GetJobLabels(), referenceTime, scheduleRangeInHours) if err != nil { - h.l.Error("error generating expected finish times: %s", err) + h.l.Error(fmt.Sprintf("error generating expected finish times: %s", err.Error())) return nil, errors.GRPCErr(err, "unable to generate expected finish times") } diff --git a/core/scheduler/service/job_expectator_service.go b/core/scheduler/service/job_expectator_service.go index 0263ff6bab..3f0c853cbd 100644 --- a/core/scheduler/service/job_expectator_service.go +++ b/core/scheduler/service/job_expectator_service.go @@ -2,6 +2,7 @@ package service import ( "context" + "fmt" "time" "github.com/goto/salt/log" @@ -79,7 +80,7 @@ func (s *JobExpectatorService) GenerateExpectedFinishTimes(ctx context.Context, // get lineage jobsWithLineageMap, err := s.jobLineageFetcher.GetJobLineage(ctx, jobSchedules) if err != nil { - s.l.Error("failed to get job lineage, skipping expected finish time generation", "error", err) + s.l.Error(fmt.Sprintf("failed to get job lineage, skipping expected finish time generation: %s", err.Error())) return nil, err } @@ -88,7 +89,7 @@ func (s *JobExpectatorService) GenerateExpectedFinishTimes(ctx context.Context, // get job durations estimation jobDurationsEstimation, err := s.durationEstimator.GetPercentileDurationByJobNames(ctx, referenceTime, uniqueJobNames) if err != nil { - s.l.Error("failed to estimate job durations, skipping expected finish time generation", "error", err) + s.l.Error(fmt.Sprintf("failed to estimate job durations, skipping expected finish time generation: %s", err.Error())) return nil, err } @@ -103,13 +104,13 @@ func (s *JobExpectatorService) GenerateExpectedFinishTimes(ctx context.Context, continue } if _, ok := jobsWithLineageMap[jobSchedule.JobName]; !ok { // safety check - s.l.Warn("no lineage found for job, cannot calculate expected finish time", "job", jobSchedule.JobName) + s.l.Warn(fmt.Sprintf("no lineage found for job [%s], cannot calculate expected finish time", jobSchedule.JobName)) continue } s.l.Debug("calculating expected finish time for job", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) err := s.PopulateExpectedFinishTime(jobSchedule, jobsWithLineageMap[jobSchedule.JobName], jobRunExpectedFinishTimeDetail, jobDurationsEstimation, referenceTime) if err != nil { - s.l.Error("failed to populate expected finish time for job", "job", jobSchedule.JobName, "error", err) + s.l.Error(fmt.Sprintf("failed to populate expected finish time for job [%s]: %s", jobSchedule.JobName, err.Error())) return nil, err } } @@ -119,15 +120,15 @@ func (s *JobExpectatorService) GenerateExpectedFinishTimes(ctx context.Context, key := *jobSchedule expectedFinishTimeDetail, ok := jobRunExpectedFinishTimeDetail[key] if !ok { - s.l.Warn("expected finish time not found for job schedule", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) + s.l.Warn(fmt.Sprintf("expected finish time not found for job schedule [job: %s, scheduled_at: %s]", jobSchedule.JobName, jobSchedule.ScheduledAt)) continue } // only upsert if still in progress if expectedFinishTimeDetail.Status == FinishTimeStatusInprogress { - s.l.Info("expected finish time calculated", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt, "expected_finish_time", expectedFinishTimeDetail.FinishTime, "status", expectedFinishTimeDetail.Status) + s.l.Info(fmt.Sprintf("expected finish time calculated [job: %s, scheduled_at: %s, expected_finish_time: %s, status: %s]", jobSchedule.JobName, jobSchedule.ScheduledAt, expectedFinishTimeDetail.FinishTime, expectedFinishTimeDetail.Status)) err := s.jobRunExpectationDetailsRepo.UpsertExpectedFinishTime(ctx, projectName, jobSchedule.JobName, jobSchedule.ScheduledAt, expectedFinishTimeDetail.FinishTime) if err != nil { - s.l.Error("failed to upsert expected finish time for job schedule", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt, "error", err) + s.l.Error(fmt.Sprintf("failed to upsert expected finish time for job schedule [job: %s, scheduled_at: %s, error: %s]", jobSchedule.JobName, jobSchedule.ScheduledAt, err.Error())) return nil, err } } @@ -139,7 +140,7 @@ func (s *JobExpectatorService) GenerateExpectedFinishTimes(ctx context.Context, key := *jobSchedule expectedFinishTime, ok := jobRunExpectedFinishTimeDetail[key] if !ok { - s.l.Warn("expected finish time not found for job schedule", "job", jobSchedule.JobName, "scheduled_at", jobSchedule.ScheduledAt) + s.l.Warn(fmt.Sprintf("expected finish time not found for job schedule [job: %s, scheduled_at: %s]", jobSchedule.JobName, jobSchedule.ScheduledAt)) continue } finalJobRunExpectedFinishTimes[key] = expectedFinishTime @@ -151,11 +152,11 @@ func (s *JobExpectatorService) GenerateExpectedFinishTimes(ctx context.Context, func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunExpectedFinishTimes map[scheduler.JobSchedule]FinishTimeDetail, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { // pre condition check if currentJobWithLineage == nil || currentJobWithLineage.JobRuns[jobTarget.JobName] == nil { - s.l.Warn("no job run found for job, skipping expected finish time calculation", "job", currentJobWithLineage.JobName) + s.l.Warn(fmt.Sprintf("no job run found for job [%s], skipping expected finish time calculation", currentJobWithLineage.JobName)) return nil } if !currentJobWithLineage.IsEnabled { - s.l.Debug("job is disabled, skipping expected finish time calculation", "job", currentJobWithLineage.JobName) + s.l.Debug(fmt.Sprintf("job is disabled, skipping expected finish time calculation [%s]", currentJobWithLineage.JobName)) return nil } @@ -167,21 +168,21 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J estimatedDuration, ok := jobDurationsEstimation[currentJobWithLineage.JobName] if !ok || estimatedDuration == nil { // if no estimation found, we cannot proceed - s.l.Warn("no duration estimation found for job, cannot calculate expected finish time", "job", currentJobWithLineage.JobName) + s.l.Warn(fmt.Sprintf("no duration estimation found for job [%s], cannot calculate expected finish time", currentJobWithLineage.JobName)) return nil } // termination condition // 1. cache if already calculated if _, ok := jobRunExpectedFinishTimes[currentJobScheduleKey]; ok { - s.l.Debug("expected finish time already calculated for job, skipping", "job", currentJobWithLineage.JobName, "scheduled_at", currentJobRun.ScheduledAt) + s.l.Debug(fmt.Sprintf("expected finish time already calculated for job [%s], skipping", currentJobWithLineage.JobName)) return nil } // 2. if end_time is nil and scheduled_time+duration Date: Wed, 18 Feb 2026 11:32:05 +0700 Subject: [PATCH 18/26] feat: when job is not started yet use buffer time as well --- .../service/job_expectator_service.go | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/core/scheduler/service/job_expectator_service.go b/core/scheduler/service/job_expectator_service.go index 3f0c853cbd..0ef282c1cb 100644 --- a/core/scheduler/service/job_expectator_service.go +++ b/core/scheduler/service/job_expectator_service.go @@ -178,9 +178,10 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J s.l.Debug(fmt.Sprintf("expected finish time already calculated for job [%s], skipping", currentJobWithLineage.JobName)) return nil } - // 2. if end_time is nil and scheduled_time+duration Date: Wed, 18 Feb 2026 11:40:56 +0700 Subject: [PATCH 19/26] feat: when job doesn't have sufficient run to estimate duration --- core/scheduler/service/job_expectator_service.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/scheduler/service/job_expectator_service.go b/core/scheduler/service/job_expectator_service.go index 0ef282c1cb..d679109645 100644 --- a/core/scheduler/service/job_expectator_service.go +++ b/core/scheduler/service/job_expectator_service.go @@ -169,7 +169,11 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J if !ok || estimatedDuration == nil { // if no estimation found, we cannot proceed s.l.Warn(fmt.Sprintf("no duration estimation found for job [%s], cannot calculate expected finish time", currentJobWithLineage.JobName)) - return nil + // rest of the logic can still work with 0 duration, which means expected finish time will be the same as max upstream expected finish time. + // this is a better approach than skipping expected finish time calculation entirely, as we can still provide some expected finish time estimation based on upstream jobs, + // rather than having no estimation at all. + zeroDuration := time.Duration(0) + estimatedDuration = &zeroDuration } // termination condition From 989ac8f8f15cb1eb31484793d36608f8b0b82fc8 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Wed, 18 Feb 2026 11:59:51 +0700 Subject: [PATCH 20/26] feat: when job already finished, it should be checked first --- .../service/job_expectator_service.go | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/core/scheduler/service/job_expectator_service.go b/core/scheduler/service/job_expectator_service.go index d679109645..6e6970c854 100644 --- a/core/scheduler/service/job_expectator_service.go +++ b/core/scheduler/service/job_expectator_service.go @@ -165,6 +165,23 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J JobName: currentJobWithLineage.JobName, ScheduledAt: currentJobRun.ScheduledAt, } + + jobStartTime := currentJobRun.JobStartTime + jobEndTime := currentJobRun.JobEndTime + + // termination condition: 1. if start_time is not nil and end_time is not nil + if jobStartTime != nil && jobEndTime != nil { + // if job has already ended, we can set the expected finish time to job end time + s.l.Debug(fmt.Sprintf("job has already ended, setting expected finish time to job end time [job: %s, scheduled_at: %s]", currentJobWithLineage.JobName, currentJobRun.ScheduledAt)) + jobRunExpectedFinishTimes[currentJobScheduleKey] = FinishTimeDetail{ + Status: FinishTimeStatusFinished, + FinishTime: *jobEndTime, + } + return nil + } + + // get estimated duration, once we know the job is not finished yet + // this information is needed to calculate expected finish time estimatedDuration, ok := jobDurationsEstimation[currentJobWithLineage.JobName] if !ok || estimatedDuration == nil { // if no estimation found, we cannot proceed @@ -176,15 +193,12 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J estimatedDuration = &zeroDuration } - // termination condition - // 1. cache if already calculated + // termination condition: 2. cache if already calculated if _, ok := jobRunExpectedFinishTimes[currentJobScheduleKey]; ok { s.l.Debug(fmt.Sprintf("expected finish time already calculated for job [%s], skipping", currentJobWithLineage.JobName)) return nil } - // 2. if start_time is not nil, end_time is nil, and scheduled_time+duration Date: Wed, 18 Feb 2026 14:21:03 +0700 Subject: [PATCH 21/26] refactor: adjust the calculation + fix test cases --- .../service/job_expectator_service.go | 53 +++++++------ .../service/job_expectator_service_test.go | 79 ++++++++++++++++--- 2 files changed, 96 insertions(+), 36 deletions(-) diff --git a/core/scheduler/service/job_expectator_service.go b/core/scheduler/service/job_expectator_service.go index 6e6970c854..2e9eb04717 100644 --- a/core/scheduler/service/job_expectator_service.go +++ b/core/scheduler/service/job_expectator_service.go @@ -152,7 +152,8 @@ func (s *JobExpectatorService) GenerateExpectedFinishTimes(ctx context.Context, func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.JobSchedule, currentJobWithLineage *scheduler.JobLineageSummary, jobRunExpectedFinishTimes map[scheduler.JobSchedule]FinishTimeDetail, jobDurationsEstimation map[scheduler.JobName]*time.Duration, referenceTime time.Time) error { // pre condition check if currentJobWithLineage == nil || currentJobWithLineage.JobRuns[jobTarget.JobName] == nil { - s.l.Warn(fmt.Sprintf("no job run found for job [%s], skipping expected finish time calculation", currentJobWithLineage.JobName)) + // TODO: add metric to track how many times this happens + s.l.Error(fmt.Sprintf("[critical] no job run found for job [%s], skipping expected finish time calculation", currentJobWithLineage.JobName)) return nil } if !currentJobWithLineage.IsEnabled { @@ -162,15 +163,16 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J currentJobRun := currentJobWithLineage.JobRuns[jobTarget.JobName] currentJobScheduleKey := scheduler.JobSchedule{ + // TODO: add project name as well, PR: https://github.com/goto/optimus/pull/501 JobName: currentJobWithLineage.JobName, ScheduledAt: currentJobRun.ScheduledAt, } - jobStartTime := currentJobRun.JobStartTime + taskStartTime := currentJobRun.TaskStartTime jobEndTime := currentJobRun.JobEndTime - // termination condition: 1. if start_time is not nil and end_time is not nil - if jobStartTime != nil && jobEndTime != nil { + // termination condition: 1. if end_time is not nil + if jobEndTime != nil { // if job has already ended, we can set the expected finish time to job end time s.l.Debug(fmt.Sprintf("job has already ended, setting expected finish time to job end time [job: %s, scheduled_at: %s]", currentJobWithLineage.JobName, currentJobRun.ScheduledAt)) jobRunExpectedFinishTimes[currentJobScheduleKey] = FinishTimeDetail{ @@ -182,15 +184,15 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J // get estimated duration, once we know the job is not finished yet // this information is needed to calculate expected finish time + // estimationDuration already has buffer time included, so we don't need to add extra buffer time in the expected finish time calculation estimatedDuration, ok := jobDurationsEstimation[currentJobWithLineage.JobName] if !ok || estimatedDuration == nil { // if no estimation found, we cannot proceed s.l.Warn(fmt.Sprintf("no duration estimation found for job [%s], cannot calculate expected finish time", currentJobWithLineage.JobName)) - // rest of the logic can still work with 0 duration, which means expected finish time will be the same as max upstream expected finish time. + // rest of the logic can still work with buffer duration, which means expected finish time will be the same as max upstream expected finish time. // this is a better approach than skipping expected finish time calculation entirely, as we can still provide some expected finish time estimation based on upstream jobs, // rather than having no estimation at all. - zeroDuration := time.Duration(0) - estimatedDuration = &zeroDuration + estimatedDuration = &s.bufferTime // use buffer time as default duration } // termination condition: 2. cache if already calculated @@ -198,13 +200,24 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J s.l.Debug(fmt.Sprintf("expected finish time already calculated for job [%s], skipping", currentJobWithLineage.JobName)) return nil } - // termination condition: 3. if start_time is not nil, end_time is nil, and scheduled_time+duration Date: Wed, 18 Feb 2026 14:25:12 +0700 Subject: [PATCH 22/26] feat: use different config for job expectator detail --- config/config_server.go | 6 ++++++ server/optimus.go | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/config/config_server.go b/config/config_server.go index b0ebc025d5..798c747a45 100644 --- a/config/config_server.go +++ b/config/config_server.go @@ -24,6 +24,7 @@ type ServerConfig struct { Features FeaturesConfig `mapstructure:"features"` Plugins Plugins `mapstructure:"plugins"` JobValidationConfig JobValidationConfig `mapstructure:"job_validation"` + JobExpectatorConfig JobExpectatorConfig `mapstructure:"job_expectator"` } type UpstreamResolver struct { @@ -165,3 +166,8 @@ type JobValidationConfig struct { type ValidateScheduleConfig struct { ReferenceTimezone string `mapstructure:"reference_timezone"` } + +type JobExpectatorConfig struct { + BufferDuration int `mapstructure:"buffer_duration_minutes" default:"10"` + DurationEstimatorConfig DurationEstimatorConfig `mapstructure:"duration_estimator_config"` +} diff --git a/server/optimus.go b/server/optimus.go index d98daad11b..630bb0f37d 100644 --- a/server/optimus.go +++ b/server/optimus.go @@ -446,7 +446,12 @@ func (s *OptimusServer) setupHandlers() error { newJobSLAPredictorService := schedulerService.NewJobSLAPredictorService(s.logger, s.conf.Alerting.PotentialSLABreachConfig, slaRepository, jobLineageService, newDurationEstimatorService, jobProviderRepo, alertsHandler, tenantService, newJobRunService) // Job Estimator Service - jobExpectatorService := schedulerService.NewJobExpectatorService(s.logger, jobRunRepo, jobProviderRepo, jobLineageService, newDurationEstimatorService) + newJobExpectatorDurationEstimatorService := schedulerService.NewDurationEstimatorService(s.logger, jobRunRepo, + s.conf.JobExpectatorConfig.DurationEstimatorConfig.LastNRuns, s.conf.JobExpectatorConfig.DurationEstimatorConfig.Percentile, + s.conf.JobExpectatorConfig.DurationEstimatorConfig.PaddingPercentage, s.conf.JobExpectatorConfig.DurationEstimatorConfig.MinPaddingMinutes, + s.conf.JobExpectatorConfig.DurationEstimatorConfig.MaxPaddingMinutes, + ) + jobExpectatorService := schedulerService.NewJobExpectatorService(s.logger, jobRunRepo, jobProviderRepo, jobLineageService, newJobExpectatorDurationEstimatorService) // Resource Bounded Context primaryResourceService := rService.NewResourceService(s.logger, resourceRepository, jJobService, resourceManager, s.eventHandler, jJobService, alertsHandler, tenantService, newEngine, syncer, syncStatusRepository) From 1d221dadbcb59fa70823d81d18858913f8c8ac6e Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Wed, 18 Feb 2026 14:28:27 +0700 Subject: [PATCH 23/26] feat: integrate buffer duration config --- config/config_server.go | 2 +- .../scheduler/service/job_expectator_service.go | 9 +++++---- .../service/job_expectator_service_test.go | 17 +++++++++++++++++ server/optimus.go | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/config/config_server.go b/config/config_server.go index 798c747a45..b349bbb9c4 100644 --- a/config/config_server.go +++ b/config/config_server.go @@ -168,6 +168,6 @@ type ValidateScheduleConfig struct { } type JobExpectatorConfig struct { - BufferDuration int `mapstructure:"buffer_duration_minutes" default:"10"` + BufferDurationInMinutes int `mapstructure:"buffer_duration_in_minutes" default:"10"` DurationEstimatorConfig DurationEstimatorConfig `mapstructure:"duration_estimator_config"` } diff --git a/core/scheduler/service/job_expectator_service.go b/core/scheduler/service/job_expectator_service.go index 2e9eb04717..12b15496b2 100644 --- a/core/scheduler/service/job_expectator_service.go +++ b/core/scheduler/service/job_expectator_service.go @@ -29,7 +29,7 @@ type JobRunExpectationDetailsRepository interface { type JobExpectatorService struct { l log.Logger - bufferTime time.Duration + bufferDuration time.Duration jobRunExpectationDetailsRepo JobRunExpectationDetailsRepository jobDetailsGetter JobDetailsGetter jobLineageFetcher JobLineageFetcher @@ -38,6 +38,7 @@ type JobExpectatorService struct { func NewJobExpectatorService( logger log.Logger, + bufferDurationInMinutes int, jobRunExpectationDetailsRepo JobRunExpectationDetailsRepository, jobDetailsGetter JobDetailsGetter, jobLineageFetcher JobLineageFetcher, @@ -45,7 +46,7 @@ func NewJobExpectatorService( ) *JobExpectatorService { return &JobExpectatorService{ l: logger, - bufferTime: 10 * time.Minute, // TODO: make this configurable + bufferDuration: time.Duration(bufferDurationInMinutes) * time.Minute, jobRunExpectationDetailsRepo: jobRunExpectationDetailsRepo, jobDetailsGetter: jobDetailsGetter, jobLineageFetcher: jobLineageFetcher, @@ -192,7 +193,7 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J // rest of the logic can still work with buffer duration, which means expected finish time will be the same as max upstream expected finish time. // this is a better approach than skipping expected finish time calculation entirely, as we can still provide some expected finish time estimation based on upstream jobs, // rather than having no estimation at all. - estimatedDuration = &s.bufferTime // use buffer time as default duration + estimatedDuration = &s.bufferDuration // use buffer time as default duration } // termination condition: 2. cache if already calculated @@ -208,7 +209,7 @@ func (s *JobExpectatorService) PopulateExpectedFinishTime(jobTarget *scheduler.J s.l.Debug(fmt.Sprintf("job is running late, setting expected finish time to reference time + buffer time [job: %s, scheduled_at: %s]", currentJobWithLineage.JobName, currentJobRun.ScheduledAt)) jobRunExpectedFinishTimes[currentJobScheduleKey] = FinishTimeDetail{ Status: FinishTimeStatusInprogress, - FinishTime: referenceTime.Add(s.bufferTime), + FinishTime: referenceTime.Add(s.bufferDuration), } return nil } diff --git a/core/scheduler/service/job_expectator_service_test.go b/core/scheduler/service/job_expectator_service_test.go index 380e3eae24..a74b121238 100644 --- a/core/scheduler/service/job_expectator_service_test.go +++ b/core/scheduler/service/job_expectator_service_test.go @@ -32,6 +32,7 @@ func TestGenerateExpectedFinishTimes(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -55,6 +56,7 @@ func TestGenerateExpectedFinishTimes(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -82,6 +84,7 @@ func TestGenerateExpectedFinishTimes(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -109,6 +112,7 @@ func TestGenerateExpectedFinishTimes(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -136,6 +140,7 @@ func TestGenerateExpectedFinishTimes(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -173,6 +178,7 @@ func TestGenerateExpectedFinishTimes(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -218,6 +224,7 @@ func TestGenerateExpectedFinishTimes(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -269,6 +276,7 @@ func TestGenerateExpectedFinishTimes(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -335,6 +343,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -376,6 +385,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -423,6 +433,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -469,6 +480,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -519,6 +531,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -567,6 +580,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -615,6 +629,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -661,6 +676,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, @@ -722,6 +738,7 @@ func TestPopulateExpectedFinishTime(t *testing.T) { jobExpectatorService := service.NewJobExpectatorService( l, + 10, jobRunExpectationDetailsRepo, jobDetailsGetter, jobLineageFetcher, diff --git a/server/optimus.go b/server/optimus.go index 630bb0f37d..e742154e44 100644 --- a/server/optimus.go +++ b/server/optimus.go @@ -451,7 +451,7 @@ func (s *OptimusServer) setupHandlers() error { s.conf.JobExpectatorConfig.DurationEstimatorConfig.PaddingPercentage, s.conf.JobExpectatorConfig.DurationEstimatorConfig.MinPaddingMinutes, s.conf.JobExpectatorConfig.DurationEstimatorConfig.MaxPaddingMinutes, ) - jobExpectatorService := schedulerService.NewJobExpectatorService(s.logger, jobRunRepo, jobProviderRepo, jobLineageService, newJobExpectatorDurationEstimatorService) + jobExpectatorService := schedulerService.NewJobExpectatorService(s.logger, s.conf.JobExpectatorConfig.BufferDurationInMinutes, jobRunRepo, jobProviderRepo, jobLineageService, newJobExpectatorDurationEstimatorService) // Resource Bounded Context primaryResourceService := rService.NewResourceService(s.logger, resourceRepository, jJobService, resourceManager, s.eventHandler, jJobService, alertsHandler, tenantService, newEngine, syncer, syncStatusRepository) From c802eded7dd1812c3341a3a23274d9f1e165ae9c Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Wed, 18 Feb 2026 14:39:10 +0700 Subject: [PATCH 24/26] feat: use different key to distinguished actual finish time --- Makefile | 2 +- core/scheduler/handler/v1beta1/job_run.go | 5 +- .../optimus/core/v1beta1/job_run.pb.go | 437 ++++++++++-------- .../optimus/core/v1beta1/job_run.swagger.json | 4 + 4 files changed, 249 insertions(+), 199 deletions(-) diff --git a/Makefile b/Makefile index 303ed9971e..3fde145f74 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ NAME = "github.com/goto/optimus" LAST_COMMIT := $(shell git rev-parse --short HEAD) LAST_TAG := "$(shell git rev-list --tags --max-count=1)" OPMS_VERSION := "$(shell git describe --tags ${LAST_TAG})-next" -PROTON_COMMIT := "ccb9ecd951b224d1466494fb4241a6223821e4b5" +PROTON_COMMIT := "c81f958da24628b40256dc464281c7d47e81fc7f" .PHONY: build test test-ci generate-proto unit-test-ci integration-test vet coverage clean install lint diff --git a/core/scheduler/handler/v1beta1/job_run.go b/core/scheduler/handler/v1beta1/job_run.go index edcd61b399..064739a281 100644 --- a/core/scheduler/handler/v1beta1/job_run.go +++ b/core/scheduler/handler/v1beta1/job_run.go @@ -615,14 +615,15 @@ func (h JobRunHandler) GenerateExpectedFinishTime(ctx context.Context, req *pb.G } for jobSchedule, jobWithFinishTime := range jobsWithFinishTime { finishTimeDetail := &pb.FinishTimeDetailResponse{ - ScheduledAt: timestamppb.New(jobSchedule.ScheduledAt), - ExpectedFinishTime: timestamppb.New(jobWithFinishTime.FinishTime), + ScheduledAt: timestamppb.New(jobSchedule.ScheduledAt), } switch jobWithFinishTime.Status { case service.FinishTimeStatusFinished: + finishTimeDetail.FinishTime = &pb.FinishTimeDetailResponse_ActualFinishTime{ActualFinishTime: timestamppb.New(jobWithFinishTime.FinishTime)} response.FinishedJobs[jobSchedule.JobName.String()] = finishTimeDetail case service.FinishTimeStatusInprogress: + finishTimeDetail.FinishTime = &pb.FinishTimeDetailResponse_ExpectedFinishTime{ExpectedFinishTime: timestamppb.New(jobWithFinishTime.FinishTime)} response.InprogressJobs[jobSchedule.JobName.String()] = finishTimeDetail } } diff --git a/protos/gotocompany/optimus/core/v1beta1/job_run.pb.go b/protos/gotocompany/optimus/core/v1beta1/job_run.pb.go index 31987299a8..7f6e4bb23f 100644 --- a/protos/gotocompany/optimus/core/v1beta1/job_run.pb.go +++ b/protos/gotocompany/optimus/core/v1beta1/job_run.pb.go @@ -2941,8 +2941,12 @@ type FinishTimeDetailResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ScheduledAt *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=scheduled_at,json=scheduledAt,proto3" json:"scheduled_at,omitempty"` - ExpectedFinishTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=expected_finish_time,json=expectedFinishTime,proto3" json:"expected_finish_time,omitempty"` + ScheduledAt *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=scheduled_at,json=scheduledAt,proto3" json:"scheduled_at,omitempty"` + // Types that are assignable to FinishTime: + // + // *FinishTimeDetailResponse_ExpectedFinishTime + // *FinishTimeDetailResponse_ActualFinishTime + FinishTime isFinishTimeDetailResponse_FinishTime `protobuf_oneof:"finish_time"` } func (x *FinishTimeDetailResponse) Reset() { @@ -2984,13 +2988,43 @@ func (x *FinishTimeDetailResponse) GetScheduledAt() *timestamppb.Timestamp { return nil } +func (m *FinishTimeDetailResponse) GetFinishTime() isFinishTimeDetailResponse_FinishTime { + if m != nil { + return m.FinishTime + } + return nil +} + func (x *FinishTimeDetailResponse) GetExpectedFinishTime() *timestamppb.Timestamp { - if x != nil { + if x, ok := x.GetFinishTime().(*FinishTimeDetailResponse_ExpectedFinishTime); ok { return x.ExpectedFinishTime } return nil } +func (x *FinishTimeDetailResponse) GetActualFinishTime() *timestamppb.Timestamp { + if x, ok := x.GetFinishTime().(*FinishTimeDetailResponse_ActualFinishTime); ok { + return x.ActualFinishTime + } + return nil +} + +type isFinishTimeDetailResponse_FinishTime interface { + isFinishTimeDetailResponse_FinishTime() +} + +type FinishTimeDetailResponse_ExpectedFinishTime struct { + ExpectedFinishTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=expected_finish_time,json=expectedFinishTime,proto3,oneof"` +} + +type FinishTimeDetailResponse_ActualFinishTime struct { + ActualFinishTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=actual_finish_time,json=actualFinishTime,proto3,oneof"` +} + +func (*FinishTimeDetailResponse_ExpectedFinishTime) isFinishTimeDetailResponse_FinishTime() {} + +func (*FinishTimeDetailResponse_ActualFinishTime) isFinishTimeDetailResponse_FinishTime() {} + var File_gotocompany_optimus_core_v1beta1_job_run_proto protoreflect.FileDescriptor var file_gotocompany_optimus_core_v1beta1_job_run_proto_rawDesc = []byte{ @@ -3623,186 +3657,192 @@ var file_gotocompany_optimus_core_v1beta1_job_run_proto_rawDesc = []byte{ 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa7, 0x01, 0x0a, 0x18, 0x46, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x84, 0x02, 0x0a, 0x18, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x4c, 0x0a, 0x14, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, + 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x4e, 0x0a, 0x14, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x12, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, - 0x54, 0x69, 0x6d, 0x65, 0x32, 0xeb, 0x13, 0x0a, 0x0d, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xbf, 0x01, 0x0a, 0x0b, 0x4a, 0x6f, 0x62, 0x52, 0x75, - 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, - 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, - 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, - 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, - 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3d, 0x22, 0x38, 0x2f, 0x76, 0x31, + 0x48, 0x00, 0x52, 0x12, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, + 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4a, 0x0a, 0x12, 0x61, 0x63, 0x74, 0x75, 0x61, 0x6c, + 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, + 0x52, 0x10, 0x61, 0x63, 0x74, 0x75, 0x61, 0x6c, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, + 0x6d, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x32, 0xeb, 0x13, 0x0a, 0x0d, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0xbf, 0x01, 0x0a, 0x0b, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, + 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x70, + 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, + 0x52, 0x75, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3d, 0x22, 0x38, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, + 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x75, 0x6e, 0x5f, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xa7, 0x01, 0x0a, 0x06, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, + 0x12, 0x2f, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, - 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x75, 0x6e, 0x5f, - 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xa7, 0x01, 0x0a, 0x06, 0x4a, 0x6f, 0x62, - 0x52, 0x75, 0x6e, 0x12, 0x2f, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, - 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x75, 0x6e, 0x12, + 0xd2, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, + 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x39, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, - 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, - 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, - 0x75, 0x6e, 0x12, 0xd2, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, - 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x39, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, - 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, - 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x12, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x2f, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0xdb, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x12, - 0x3c, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, - 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, - 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, - 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x41, 0x22, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, + 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, + 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x41, 0x12, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, + 0x72, 0x6f, 0x6c, 0x65, 0x12, 0xdb, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x3c, 0x2e, 0x67, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, + 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x67, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x6f, 0x6c, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x41, 0x22, 0x3f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x6f, + 0x6c, 0x65, 0x12, 0xb8, 0x01, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, + 0x73, 0x12, 0x33, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, + 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, + 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, + 0x52, 0x75, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x39, 0x12, 0x37, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, - 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x2f, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0xb8, 0x01, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, - 0x52, 0x75, 0x6e, 0x73, 0x12, 0x33, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, - 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x12, 0xe6, 0x01, + 0x0a, 0x19, 0x47, 0x65, 0x74, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x53, + 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3c, 0x2e, 0x67, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, + 0x65, 0x74, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x53, 0x65, 0x6e, 0x73, + 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x12, 0x37, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, - 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x75, 0x6e, 0x73, - 0x12, 0xe6, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, - 0x74, 0x79, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3c, - 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x53, - 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x67, + 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x46, + 0x1a, 0x41, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, + 0x2f, 0x74, 0x68, 0x69, 0x72, 0x64, 0x2d, 0x70, 0x61, 0x72, 0x74, 0x79, 0x2d, 0x73, 0x65, 0x6e, + 0x73, 0x6f, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0xe5, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x2e, 0x67, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, + 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, + 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x5a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x54, 0x22, 0x4f, 0x2f, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xbf, + 0x01, 0x0a, 0x11, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x72, 0x12, 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x6f, + 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x3b, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x1a, 0x26, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x01, 0x2a, + 0x12, 0xbb, 0x01, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, + 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, + 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, + 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x12, 0x37, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0xcb, + 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4c, 0x69, 0x6e, 0x65, + 0x61, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x40, 0x2e, 0x67, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x67, 0x65, 0x53, 0x75, + 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x53, 0x65, 0x6e, - 0x73, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4c, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x46, 0x1a, 0x41, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x68, 0x69, 0x72, 0x64, 0x2d, 0x70, 0x61, 0x72, 0x74, 0x79, 0x2d, - 0x73, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0xe5, 0x01, 0x0a, 0x10, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x39, - 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x54, 0x22, 0x4f, 0x2f, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, - 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, - 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x3a, 0x01, - 0x2a, 0x12, 0xbf, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x6f, 0x53, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x3a, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, - 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, - 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x6f, 0x53, - 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x1a, 0x26, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, - 0x3a, 0x01, 0x2a, 0x12, 0xbb, 0x01, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, - 0x76, 0x61, 0x6c, 0x12, 0x34, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, - 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, - 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x3f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x39, 0x12, 0x37, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, - 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x12, 0xcb, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4c, - 0x69, 0x6e, 0x65, 0x61, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x40, 0x2e, - 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x67, - 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x41, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, + 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x67, 0x65, + 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2f, 0x6a, 0x6f, 0x62, 0x2d, 0x72, 0x75, 0x6e, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x61, 0x67, + 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0xf1, 0x01, 0x0a, + 0x1a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x50, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x53, 0x4c, 0x41, 0x42, 0x72, 0x65, 0x61, 0x63, 0x68, 0x12, 0x43, 0x2e, 0x67, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x50, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x53, 0x4c, 0x41, 0x42, 0x72, 0x65, 0x61, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x44, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x50, 0x6f, 0x74, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x4c, 0x41, 0x42, 0x72, 0x65, 0x61, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42, 0x22, 0x3d, + 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, + 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6c, 0x61, 0x5f, 0x62, 0x72, + 0x65, 0x61, 0x63, 0x68, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x3a, 0x01, 0x2a, + 0x12, 0xec, 0x01, 0x0a, 0x1a, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x78, 0x70, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x43, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4c, 0x69, 0x6e, 0x65, - 0x61, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2f, 0x6a, 0x6f, 0x62, 0x2d, 0x72, 0x75, 0x6e, 0x2d, 0x6c, 0x69, 0x6e, - 0x65, 0x61, 0x67, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x3a, 0x01, 0x2a, 0x12, - 0xf1, 0x01, 0x0a, 0x1a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x50, 0x6f, 0x74, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x4c, 0x41, 0x42, 0x72, 0x65, 0x61, 0x63, 0x68, 0x12, 0x43, - 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x50, 0x6f, 0x74, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x53, 0x4c, 0x41, 0x42, 0x72, 0x65, 0x61, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x44, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, - 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x50, - 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x4c, 0x41, 0x42, 0x72, 0x65, 0x61, 0x63, - 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x42, 0x22, 0x3d, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x2f, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x6c, 0x61, - 0x5f, 0x62, 0x72, 0x65, 0x61, 0x63, 0x68, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, - 0x3a, 0x01, 0x2a, 0x12, 0xec, 0x01, 0x0a, 0x1a, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x61, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x78, 0x70, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x44, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, - 0x6d, 0x65, 0x12, 0x43, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x78, - 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x44, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x63, 0x6f, - 0x72, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, - 0x68, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x3d, 0x22, 0x38, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, - 0x6a, 0x6f, 0x62, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x3a, - 0x01, 0x2a, 0x42, 0x8f, 0x01, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x42, 0x0d, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x1e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2f, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x92, 0x41, 0x3b, 0x12, 0x05, 0x32, 0x03, 0x30, 0x2e, 0x31, - 0x1a, 0x0e, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x39, 0x31, 0x30, 0x30, - 0x22, 0x04, 0x2f, 0x61, 0x70, 0x69, 0x2a, 0x01, 0x01, 0x72, 0x19, 0x0a, 0x17, 0x4f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x20, 0x4a, 0x6f, 0x62, 0x20, 0x52, 0x75, 0x6e, 0x20, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x3d, 0x22, 0x38, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x7d, 0x2f, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x6a, 0x6f, 0x62, + 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x3a, 0x01, 0x2a, 0x42, + 0x8f, 0x01, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x42, 0x0d, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x50, 0x01, 0x5a, 0x1e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x67, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x74, 0x69, + 0x6d, 0x75, 0x73, 0x92, 0x41, 0x3b, 0x12, 0x05, 0x32, 0x03, 0x30, 0x2e, 0x31, 0x1a, 0x0e, 0x31, + 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, 0x39, 0x31, 0x30, 0x30, 0x22, 0x04, 0x2f, + 0x61, 0x70, 0x69, 0x2a, 0x01, 0x01, 0x72, 0x19, 0x0a, 0x17, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x20, 0x4a, 0x6f, 0x62, 0x20, 0x52, 0x75, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3946,38 +3986,39 @@ var file_gotocompany_optimus_core_v1beta1_job_run_proto_depIdxs = []int32{ 52, // 64: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.finished_jobs:type_name -> gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.FinishedJobsEntry 53, // 65: gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse.scheduled_at:type_name -> google.protobuf.Timestamp 53, // 66: gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse.expected_finish_time:type_name -> google.protobuf.Timestamp - 41, // 67: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.UpstreamJobsStatus - 44, // 68: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.InprogressJobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse - 44, // 69: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.FinishedJobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse - 13, // 70: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:input_type -> gotocompany.optimus.core.v1beta1.JobRunInputRequest - 17, // 71: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:input_type -> gotocompany.optimus.core.v1beta1.JobRunRequest - 19, // 72: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleRequest - 21, // 73: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleRequest - 14, // 74: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunsRequest - 5, // 75: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:input_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest - 11, // 76: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:input_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventRequest - 9, // 77: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:input_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerRequest - 7, // 78: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:input_type -> gotocompany.optimus.core.v1beta1.GetIntervalRequest - 27, // 79: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryRequest - 38, // 80: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:input_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest - 42, // 81: gotocompany.optimus.core.v1beta1.JobRunService.GenerateExpectedFinishTime:input_type -> gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeRequest - 25, // 82: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:output_type -> gotocompany.optimus.core.v1beta1.JobRunInputResponse - 18, // 83: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:output_type -> gotocompany.optimus.core.v1beta1.JobRunResponse - 20, // 84: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleResponse - 22, // 85: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleResponse - 16, // 86: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunsResponse - 6, // 87: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:output_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorResponse - 12, // 88: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:output_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventResponse - 10, // 89: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:output_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerResponse - 8, // 90: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:output_type -> gotocompany.optimus.core.v1beta1.GetIntervalResponse - 29, // 91: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryResponse - 39, // 92: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:output_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse - 43, // 93: gotocompany.optimus.core.v1beta1.JobRunService.GenerateExpectedFinishTime:output_type -> gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse - 82, // [82:94] is the sub-list for method output_type - 70, // [70:82] is the sub-list for method input_type - 70, // [70:70] is the sub-list for extension type_name - 70, // [70:70] is the sub-list for extension extendee - 0, // [0:70] is the sub-list for field type_name + 53, // 67: gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse.actual_finish_time:type_name -> google.protobuf.Timestamp + 41, // 68: gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse.JobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.UpstreamJobsStatus + 44, // 69: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.InprogressJobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse + 44, // 70: gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse.FinishedJobsEntry.value:type_name -> gotocompany.optimus.core.v1beta1.FinishTimeDetailResponse + 13, // 71: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:input_type -> gotocompany.optimus.core.v1beta1.JobRunInputRequest + 17, // 72: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:input_type -> gotocompany.optimus.core.v1beta1.JobRunRequest + 19, // 73: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleRequest + 21, // 74: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:input_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleRequest + 14, // 75: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunsRequest + 5, // 76: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:input_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorRequest + 11, // 77: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:input_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventRequest + 9, // 78: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:input_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerRequest + 7, // 79: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:input_type -> gotocompany.optimus.core.v1beta1.GetIntervalRequest + 27, // 80: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:input_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryRequest + 38, // 81: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:input_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachRequest + 42, // 82: gotocompany.optimus.core.v1beta1.JobRunService.GenerateExpectedFinishTime:input_type -> gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeRequest + 25, // 83: gotocompany.optimus.core.v1beta1.JobRunService.JobRunInput:output_type -> gotocompany.optimus.core.v1beta1.JobRunInputResponse + 18, // 84: gotocompany.optimus.core.v1beta1.JobRunService.JobRun:output_type -> gotocompany.optimus.core.v1beta1.JobRunResponse + 20, // 85: gotocompany.optimus.core.v1beta1.JobRunService.GetSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.GetSchedulerRoleResponse + 22, // 86: gotocompany.optimus.core.v1beta1.JobRunService.CreateSchedulerRole:output_type -> gotocompany.optimus.core.v1beta1.CreateSchedulerRoleResponse + 16, // 87: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRuns:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunsResponse + 6, // 88: gotocompany.optimus.core.v1beta1.JobRunService.GetThirdPartySensorStatus:output_type -> gotocompany.optimus.core.v1beta1.GetThirdPartySensorResponse + 12, // 89: gotocompany.optimus.core.v1beta1.JobRunService.RegisterJobEvent:output_type -> gotocompany.optimus.core.v1beta1.RegisterJobEventResponse + 10, // 90: gotocompany.optimus.core.v1beta1.JobRunService.UploadToScheduler:output_type -> gotocompany.optimus.core.v1beta1.UploadToSchedulerResponse + 8, // 91: gotocompany.optimus.core.v1beta1.JobRunService.GetInterval:output_type -> gotocompany.optimus.core.v1beta1.GetIntervalResponse + 29, // 92: gotocompany.optimus.core.v1beta1.JobRunService.GetJobRunLineageSummary:output_type -> gotocompany.optimus.core.v1beta1.GetJobRunLineageSummaryResponse + 39, // 93: gotocompany.optimus.core.v1beta1.JobRunService.IdentifyPotentialSLABreach:output_type -> gotocompany.optimus.core.v1beta1.IdentifyPotentialSLABreachResponse + 43, // 94: gotocompany.optimus.core.v1beta1.JobRunService.GenerateExpectedFinishTime:output_type -> gotocompany.optimus.core.v1beta1.GenerateExpectedFinishTimeResponse + 83, // [83:95] is the sub-list for method output_type + 71, // [71:83] is the sub-list for method input_type + 71, // [71:71] is the sub-list for extension type_name + 71, // [71:71] is the sub-list for extension extendee + 0, // [0:71] is the sub-list for field type_name } func init() { file_gotocompany_optimus_core_v1beta1_job_run_proto_init() } @@ -4511,6 +4552,10 @@ func file_gotocompany_optimus_core_v1beta1_job_run_proto_init() { (*GetThirdPartySensorResponse_DexSensorResponse)(nil), } file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[7].OneofWrappers = []interface{}{} + file_gotocompany_optimus_core_v1beta1_job_run_proto_msgTypes[42].OneofWrappers = []interface{}{ + (*FinishTimeDetailResponse_ExpectedFinishTime)(nil), + (*FinishTimeDetailResponse_ActualFinishTime)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json b/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json index 06fa2e1659..81b00fee27 100644 --- a/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json +++ b/protos/gotocompany/optimus/core/v1beta1/job_run.swagger.json @@ -755,6 +755,10 @@ "expectedFinishTime": { "type": "string", "format": "date-time" + }, + "actualFinishTime": { + "type": "string", + "format": "date-time" } } }, From 53b4469eaaa398518abc36eda2aafe4c05d22f06 Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Wed, 18 Feb 2026 14:42:58 +0700 Subject: [PATCH 25/26] fix: new server config --- config/loader_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/config/loader_test.go b/config/loader_test.go index 6587c41cb7..5c43252442 100644 --- a/config/loader_test.go +++ b/config/loader_test.go @@ -311,6 +311,16 @@ func (s *ConfigTestSuite) initExpectedServerConfig() { MaxPaddingMinutes: 1000, }, } + s.expectedServerConfig.JobExpectatorConfig = config.JobExpectatorConfig{ + BufferDurationInMinutes: 10, + DurationEstimatorConfig: config.DurationEstimatorConfig{ + LastNRuns: 7, + Percentile: 95, + PaddingPercentage: 0, + MinPaddingMinutes: 0, + MaxPaddingMinutes: 1000, + }, + } } func (*ConfigTestSuite) initServerConfigEnv() { From 17f3f3633d2c850e8df606d433924ce12242b6af Mon Sep 17 00:00:00 2001 From: Dery Rahman Ahaddienata Date: Wed, 18 Feb 2026 15:28:13 +0700 Subject: [PATCH 26/26] feat: update proto commit --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3fde145f74..b90eaf71ea 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ NAME = "github.com/goto/optimus" LAST_COMMIT := $(shell git rev-parse --short HEAD) LAST_TAG := "$(shell git rev-list --tags --max-count=1)" OPMS_VERSION := "$(shell git describe --tags ${LAST_TAG})-next" -PROTON_COMMIT := "c81f958da24628b40256dc464281c7d47e81fc7f" +PROTON_COMMIT := "b95054a6983b21201141a46c8cb8ecc95e6cdf7d" .PHONY: build test test-ci generate-proto unit-test-ci integration-test vet coverage clean install lint