func()

in service/frontend/api/handler.go [1823:1962]


func (wh *WorkflowHandler) validateStartWorkflowExecutionRequest(ctx context.Context, startRequest *types.StartWorkflowExecutionRequest, scope metrics.Scope) error {
	if startRequest == nil {
		return validate.ErrRequestNotSet
	}
	domainName := startRequest.GetDomain()
	if domainName == "" {
		return validate.ErrDomainNotSet
	}
	if startRequest.GetWorkflowID() == "" {
		return validate.ErrWorkflowIDNotSet
	}
	if _, err := uuid.Parse(startRequest.RequestID); err != nil {
		return &types.BadRequestError{Message: fmt.Sprintf("requestId %q is not a valid UUID", startRequest.RequestID)}
	}
	if startRequest.WorkflowType == nil || startRequest.WorkflowType.GetName() == "" {
		return validate.ErrWorkflowTypeNotSet
	}
	if err := wh.versionChecker.ClientSupported(ctx, wh.config.EnableClientVersionCheck()); err != nil {
		return err
	}
	idLengthWarnLimit := wh.config.MaxIDLengthWarnLimit()
	if !common.IsValidIDLength(
		domainName,
		scope,
		idLengthWarnLimit,
		wh.config.DomainNameMaxLength(domainName),
		metrics.CadenceErrDomainNameExceededWarnLimit,
		domainName,
		wh.GetLogger(),
		tag.IDTypeDomainName) {
		return validate.ErrDomainTooLong
	}
	if !common.IsValidIDLength(
		startRequest.GetWorkflowID(),
		scope,
		idLengthWarnLimit,
		wh.config.WorkflowIDMaxLength(domainName),
		metrics.CadenceErrWorkflowIDExceededWarnLimit,
		domainName,
		wh.GetLogger(),
		tag.IDTypeWorkflowID) {
		return validate.ErrWorkflowIDTooLong
	}
	if err := common.ValidateRetryPolicy(startRequest.RetryPolicy); err != nil {
		return err
	}
	wh.GetLogger().Debug(
		"Received StartWorkflowExecution. WorkflowID",
		tag.WorkflowID(startRequest.GetWorkflowID()))
	if !common.IsValidIDLength(
		startRequest.WorkflowType.GetName(),
		scope,
		idLengthWarnLimit,
		wh.config.WorkflowTypeMaxLength(domainName),
		metrics.CadenceErrWorkflowTypeExceededWarnLimit,
		domainName,
		wh.GetLogger(),
		tag.IDTypeWorkflowType) {
		return validate.ErrWorkflowTypeTooLong
	}
	if err := wh.validateTaskList(startRequest.TaskList, scope, domainName); err != nil {
		return err
	}
	if startRequest.GetExecutionStartToCloseTimeoutSeconds() <= 0 {
		return validate.ErrInvalidExecutionStartToCloseTimeoutSeconds
	}
	if startRequest.GetTaskStartToCloseTimeoutSeconds() <= 0 {
		return validate.ErrInvalidTaskStartToCloseTimeoutSeconds
	}
	if startRequest.GetDelayStartSeconds() < 0 {
		return validate.ErrInvalidDelayStartSeconds
	}
	if startRequest.GetJitterStartSeconds() < 0 {
		return validate.ErrInvalidJitterStartSeconds
	}
	jitter := startRequest.GetJitterStartSeconds()
	cron := startRequest.GetCronSchedule()
	if cron != "" {
		if _, err := backoff.ValidateSchedule(startRequest.GetCronSchedule()); err != nil {
			return err
		}
	}
	if jitter > 0 && cron != "" {
		// Calculate the cron duration and ensure that jitter is not greater than the cron duration,
		// because that would be confusing to users.

		// Request using start/end time zero value, which will get us an exact answer (i.e. its not in the
		// middle of a minute)
		backoffSeconds, err := backoff.GetBackoffForNextScheduleInSeconds(cron, time.Time{}, time.Time{}, jitter)
		if err != nil {
			return err
		}
		if jitter > backoffSeconds {
			return validate.ErrInvalidJitterStartSeconds2
		}
	}
	if !common.IsValidIDLength(
		startRequest.GetRequestID(),
		scope,
		idLengthWarnLimit,
		wh.config.RequestIDMaxLength(domainName),
		metrics.CadenceErrRequestIDExceededWarnLimit,
		domainName,
		wh.GetLogger(),
		tag.IDTypeRequestID) {
		return validate.ErrRequestIDTooLong
	}
	if err := wh.searchAttributesValidator.ValidateSearchAttributes(startRequest.SearchAttributes, domainName); err != nil {
		return err
	}
	wh.GetLogger().Debug("Start workflow execution request domain", tag.WorkflowDomainName(domainName))
	domainID, err := wh.GetDomainCache().GetDomainID(domainName)
	if err != nil {
		return err
	}
	sizeLimitError := wh.config.BlobSizeLimitError(domainName)
	sizeLimitWarn := wh.config.BlobSizeLimitWarn(domainName)
	actualSize := len(startRequest.Input)
	if startRequest.Memo != nil {
		actualSize += common.GetSizeOfMapStringToByteArray(startRequest.Memo.GetFields())
	}
	if err := common.CheckEventBlobSizeLimit(
		actualSize,
		sizeLimitWarn,
		sizeLimitError,
		domainID,
		startRequest.GetWorkflowID(),
		"",
		scope,
		wh.GetThrottledLogger(),
		tag.BlobSizeViolationOperation("StartWorkflowExecution"),
	); err != nil {
		return err
	}
	isolationGroup := wh.getIsolationGroup(ctx, domainName)
	if !wh.isIsolationGroupHealthy(ctx, domainName, isolationGroup) {
		return &types.BadRequestError{fmt.Sprintf("Domain %s is drained from isolation group %s.", domainName, isolationGroup)}
	}
	return nil
}