From 82f073b4e44ef02badc63097393f235eec3f745f Mon Sep 17 00:00:00 2001 From: Lina Jodoin Date: Mon, 11 May 2026 16:32:19 -0700 Subject: [PATCH 1/2] [Scheduler] Emit StateSizeBytes in Describe/List (including visi memo) --- chasm/lib/scheduler/scheduler.go | 5 +++ tests/schedule_test.go | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) 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..65f697839f2 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,59 @@ func testCreatesWorkflowSentinel(t *testing.T, newContext contextFactory) { s.Equal(int64(1), countResp.Count) } +// testStateSizeBytesReported verifies that the CHASM scheduler wires +// chasm.Context.ExecutionInfo().ApproximateStateSize through to both +// ScheduleInfo.StateSizeBytes (Describe) and ScheduleListInfo.StateSizeBytes +// (List). The size calculation itself is covered by ApproximateStateSize unit +// tests; this test only exercises the wiring. +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) { From 14e90b2a84667aef9dade4e6dacf9569b7ba6988 Mon Sep 17 00:00:00 2001 From: Lina Jodoin Date: Mon, 11 May 2026 16:34:41 -0700 Subject: [PATCH 2/2] get rid of useless robocomment --- tests/schedule_test.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/schedule_test.go b/tests/schedule_test.go index 65f697839f2..0da1aa18d43 100644 --- a/tests/schedule_test.go +++ b/tests/schedule_test.go @@ -1822,11 +1822,6 @@ func testCreatesWorkflowSentinel(t *testing.T, newContext contextFactory) { s.Equal(int64(1), countResp.Count) } -// testStateSizeBytesReported verifies that the CHASM scheduler wires -// chasm.Context.ExecutionInfo().ApproximateStateSize through to both -// ScheduleInfo.StateSizeBytes (Describe) and ScheduleListInfo.StateSizeBytes -// (List). The size calculation itself is covered by ApproximateStateSize unit -// tests; this test only exercises the wiring. func testStateSizeBytesReported(t *testing.T, newContext contextFactory) { s := testcore.NewEnv(t, scheduleCommonOpts()...)