diff --git a/chasm/lib/scheduler/scheduler.go b/chasm/lib/scheduler/scheduler.go index 621e273b97c..ab166f8e192 100644 --- a/chasm/lib/scheduler/scheduler.go +++ b/chasm/lib/scheduler/scheduler.go @@ -632,6 +632,9 @@ func (s *Scheduler) Describe( // waiting portion (those not yet surfaced via RecentActions) counts as buffered. info.BufferSize = int64(len(invoker.GetBufferedStarts()) - len(info.RecentActions)) + executionInfo := ctx.ExecutionInfo() + info.StateSizeBytes = int64(executionInfo.ApproximateStateSize) + return &schedulerpb.DescribeScheduleResponse{ FrontendResponse: &workflowservice.DescribeScheduleResponse{ Schedule: schedule, @@ -911,6 +914,7 @@ func (s *Scheduler) ListInfo( ctx chasm.Context, ) *schedulepb.ScheduleListInfo { spec := common.CloneProto(s.Schedule.Spec) + executionInfo := ctx.ExecutionInfo() // Clear fields that are too large/not useful for the list view. spec.TimezoneData = nil @@ -930,6 +934,7 @@ func (s *Scheduler) ListInfo( Paused: s.Schedule.State.Paused, RecentActions: invoker.recentActions(), FutureActionTimes: generator.FutureActionTimes, + StateSizeBytes: int64(executionInfo.ApproximateStateSize), } } diff --git a/tests/schedule_test.go b/tests/schedule_test.go index 3ec9769ed23..0da1aa18d43 100644 --- a/tests/schedule_test.go +++ b/tests/schedule_test.go @@ -84,6 +84,7 @@ func TestScheduleCHASM(t *testing.T) { t.Run("TestSkipsWorkflowSentinelWhenDisabled", func(t *testing.T) { testSkipsWorkflowSentinelWhenDisabled(t, newContext) }) t.Run("TestUpdateScheduleMemo", func(t *testing.T) { testUpdateScheduleMemo(t, newContext) }) t.Run("TestUpdateScheduleMemoOnly", func(t *testing.T) { testUpdateScheduleMemoOnly(t, newContext) }) + t.Run("TestStateSizeBytesReported", func(t *testing.T) { testStateSizeBytesReported(t, newContext) }) } func TestScheduleV1(t *testing.T) { @@ -1821,6 +1822,54 @@ func testCreatesWorkflowSentinel(t *testing.T, newContext contextFactory) { s.Equal(int64(1), countResp.Count) } +func testStateSizeBytesReported(t *testing.T, newContext contextFactory) { + s := testcore.NewEnv(t, scheduleCommonOpts()...) + + sid := testcore.RandomizeStr("sched-state-size") + wid := testcore.RandomizeStr("sched-state-size-wf") + wt := testcore.RandomizeStr("sched-state-size-wt") + + schedule := &schedulepb.Schedule{ + Spec: &schedulepb.ScheduleSpec{ + Interval: []*schedulepb.IntervalSpec{ + {Interval: durationpb.New(1 * time.Hour)}, + }, + }, + Action: &schedulepb.ScheduleAction{ + Action: &schedulepb.ScheduleAction_StartWorkflow{ + StartWorkflow: &workflowpb.NewWorkflowExecutionInfo{ + WorkflowId: wid, + WorkflowType: &commonpb.WorkflowType{Name: wt}, + TaskQueue: &taskqueuepb.TaskQueue{Name: s.WorkerTaskQueue(), Kind: enumspb.TASK_QUEUE_KIND_NORMAL}, + }, + }, + }, + State: &schedulepb.ScheduleState{Paused: true}, + } + + ctx := newContext(s.Context()) + _, err := s.FrontendClient().CreateSchedule(ctx, &workflowservice.CreateScheduleRequest{ + Namespace: s.Namespace().String(), + ScheduleId: sid, + Schedule: schedule, + Identity: "test", + RequestId: uuid.NewString(), + }) + s.NoError(err) + + desc, err := s.FrontendClient().DescribeSchedule(ctx, &workflowservice.DescribeScheduleRequest{ + Namespace: s.Namespace().String(), + ScheduleId: sid, + }) + s.NoError(err) + s.Positive(desc.GetInfo().GetStateSizeBytes(), "Describe should report a non-zero StateSizeBytes") + + entry := getScheduleEntryFromVisibility(s, sid, newContext, func(e *schedulepb.ScheduleListEntry) bool { + return e.GetInfo().GetStateSizeBytes() > 0 + }) + s.Positive(entry.GetInfo().GetStateSizeBytes(), "ListSchedules entry should report a non-zero StateSizeBytes") +} + // testCreatesCHASMSentinel tests that creating a V1 schedule also creates a // CHASM sentinel to reserve the schedule ID in the CHASM execution space. func testCreatesCHASMSentinel(t *testing.T, newContext contextFactory) {