80
// CreateFromMigrationState creates a CHASM schedule from migrated V1 state.
81
// Used during migration from workflow-backed schedules to CHASM schedules.
82
>
func (h *handler) CreateFromMigrationState(ctx context.Context, req *schedulerpb.CreateFromMigrationStateRequest) (resp *schedulerpb.CreateFromMigrationStateResponse, err error) {
handler.go
83
>
defer log.CapturePanic(h.logger, &err)
84
>
85
>
scheduleID := req.GetState().GetSchedulerState().GetScheduleId()
86
>
_, err = chasm.StartExecution(
87
>
ctx,
88
>
chasm.ExecutionKey{
89
>
NamespaceID: req.NamespaceId,
90
>
BusinessID: scheduleID,
91
>
},
92
>
CreateSchedulerFromMigration,
93
>
req,
94
>
)
95
>
96
>
var alreadyStartedErr *chasm.ExecutionAlreadyStartedError
97
>
if errors.As(err, &alreadyStartedErr) {
98
>
// Check if the existing schedule is a sentinel. Sentinels are
99
>
// auto-deleted SentinelIdleTime after schedule creation; the
100
>
// V1 schedule will keep retrying migration until it expires.
101
>
_, readErr := chasm.ReadComponent(
102
>
ctx,
103
>
chasm.NewComponentRef[*Scheduler](
104
>
chasm.ExecutionKey{
105
>
NamespaceID: req.NamespaceId,
106
>
BusinessID: scheduleID,
107
>
},
108
>
),
109
>
func(s *Scheduler, ctx chasm.Context, _ *struct{}) (*struct{}, error) {
110
>
if s.IsSentinel() {
111
>
return nil, ErrSentinel
112
>
}
113
return nil, nil
114
},
115
(*struct{})(nil),
116
)
118
>
if errors.Is(readErr, ErrSentinel) {
119
>
h.logger.Warn(
120
>
fmt.Sprintf("Migration blocked by sentinel schedule; sentinel will auto-delete %v after schedule creation", SentinelIdleTime),
121
>
tag.NewStringTag("schedule-id", scheduleID),
122
>
)
123
>
return nil, ErrSentinelBlocked
124
>
}
125
return nil, readErr
126
}