func (s *WorkflowShadower) Stop() {
	if !atomic.CompareAndSwapInt32(&s.status, statusStarted, statusStopped) {
		return
	}
	close(s.shutdownCh)
	if success := util.AwaitWaitGroup(&s.shutdownWG, time.Minute); !success {
		s.logger.Warn("Workflow Shadower timedout on shutdown")
	}
}
Stop stops WorkflowShadower and wait up to one miniute for all goroutines to finish before returning
package internal
import (
	"context"
	"errors"
	"fmt"
	"math"
	"math/rand"
	"sync"
	"sync/atomic"
	"time"
	"github.com/facebookgo/clock"
	"go.uber.org/cadence/.gen/go/cadence/workflowserviceclient"
	"go.uber.org/cadence/.gen/go/shadower"
	"go.uber.org/cadence/internal/common"
	"go.uber.org/cadence/internal/common/util"
	"go.uber.org/zap"
)
const (
	statusInitialized int32 = 0
	statusStarted     int32 = 1
	statusStopped     int32 = 2
)
const (
	defaultWaitDurationPerIteration = 5 * time.Minute
)
type (
	ShadowOptions struct {
		WorkflowQuery string
		WorkflowTypes []string
		WorkflowStatus []string
		WorkflowStartTimeFilter TimeFilter
		SamplingRate float64
		Mode ShadowMode
		ExitCondition ShadowExitCondition
		Concurrency int
	}
	TimeFilter struct {
		MinTimestamp time.Time
		MaxTimestamp time.Time
	}
	ShadowMode int
	ShadowExitCondition struct {
		ExpirationInterval time.Duration
		ShadowCount int
	}
	WorkflowShadower struct {
		service       workflowserviceclient.Interface
		domain        string
		shadowOptions ShadowOptions
		logger        *zap.Logger
		replayer      *WorkflowReplayer
		status     int32
		shutdownCh chan struct{}
		shutdownWG sync.WaitGroup
		clock clock.Clock
	}
)
const (
	ShadowModeNormal ShadowMode = iota
	ShadowModeContinuous
)
func NewWorkflowShadower(
	service workflowserviceclient.Interface,
	domain string,
	shadowOptions ShadowOptions,
	replayOptions ReplayOptions,
	logger *zap.Logger,
) (*WorkflowShadower, error) {
	if len(domain) == 0 {
		return nil, errors.New("domain is not set")
	}
	if err := shadowOptions.validateAndPopulateFields(); err != nil {
		return nil, err
	}
	if shadowOptions.Concurrency > 1 {
		return nil, errors.New("local workflow shadower doesn't support concurrency > 1")
	}
	if logger == nil {
		logger = zap.NewNop()
	}
	return &WorkflowShadower{
		service:       service,
		domain:        domain,
		shadowOptions: shadowOptions,
		logger:        logger,
		replayer:      NewWorkflowReplayerWithOptions(replayOptions),
		status:     statusInitialized,
		shutdownCh: make(chan struct{}),
		clock: clock.New(),
	}, nil
}
func (s *WorkflowShadower) RegisterWorkflow(w interface{}) {
	s.replayer.RegisterWorkflow(w)
}
func (s *WorkflowShadower) RegisterWorkflowWithOptions(w interface{}, options RegisterWorkflowOptions) {
	s.replayer.RegisterWorkflowWithOptions(w, options)
}
func (s *WorkflowShadower) Run() error {
	if !atomic.CompareAndSwapInt32(&s.status, statusInitialized, statusStarted) {
		return errors.New("Workflow shadower already started")
	}
	return s.shadowWorker()
}