github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/framework/registry/factory.go (about)

     1  // Copyright 2022 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package registry
    15  
    16  import (
    17  	"encoding/json"
    18  	"reflect"
    19  	"strings"
    20  
    21  	"github.com/pingcap/log"
    22  	"github.com/pingcap/tiflow/engine/framework"
    23  	frameModel "github.com/pingcap/tiflow/engine/framework/model"
    24  	dcontext "github.com/pingcap/tiflow/engine/pkg/context"
    25  	"github.com/pingcap/tiflow/pkg/errors"
    26  )
    27  
    28  // WorkerFactory is an interface that should be implemented by the author of
    29  // WorkerImpl or JobMasterImpl (JobMaster is the worker of JobManager).
    30  // It represents a constructor for a given type of worker.
    31  type WorkerFactory interface {
    32  	// NewWorkerImpl return an implementation of the worker. its BaseWorker
    33  	// or BaseJobMaster field can be left nil, framework will fill it in.
    34  	NewWorkerImpl(
    35  		ctx *dcontext.Context, // We require a `dcontext` here to provide dependencies.
    36  		workerID frameModel.WorkerID, // the globally unique workerID for this worker to be created.
    37  		masterID frameModel.MasterID, // the masterID that this worker will report to.
    38  		config WorkerConfig, // the config used to initialize the worker.
    39  	) (framework.WorkerImpl, error)
    40  	DeserializeConfig(configBytes []byte) (WorkerConfig, error)
    41  	// IsRetryableError passes in an error to business logic, and returns whether
    42  	// job should be re-created or terminated permanently when meeting this error.
    43  	IsRetryableError(err error) bool
    44  }
    45  
    46  // WorkerConstructor alias to the function that can construct a WorkerImpl
    47  type WorkerConstructor[T framework.WorkerImpl, C any] func(
    48  	ctx *dcontext.Context, id frameModel.WorkerID, masterID frameModel.MasterID, config C,
    49  ) T
    50  
    51  // SimpleWorkerFactory is a WorkerFactory with built-in JSON codec for WorkerConfig.
    52  type SimpleWorkerFactory[T framework.WorkerImpl, C any] struct {
    53  	constructor WorkerConstructor[T, C]
    54  }
    55  
    56  // NewSimpleWorkerFactory creates a new WorkerFactory.
    57  func NewSimpleWorkerFactory[T framework.WorkerImpl, Config any](
    58  	constructor WorkerConstructor[T, Config],
    59  ) *SimpleWorkerFactory[T, Config] {
    60  	// Config must be a pointer
    61  	if !isPtr[Config]() {
    62  		// It's okay to panic here.
    63  		// The developer who used this function mistakenly should
    64  		// be able to figure out what happened.
    65  		log.Panic("expect worker's config type to be a pointer")
    66  	}
    67  	return &SimpleWorkerFactory[T, Config]{
    68  		constructor: constructor,
    69  	}
    70  }
    71  
    72  // NewWorkerImpl implements WorkerFactory.NewWorkerImpl
    73  func (f *SimpleWorkerFactory[T, C]) NewWorkerImpl(
    74  	ctx *dcontext.Context,
    75  	workerID frameModel.WorkerID,
    76  	masterID frameModel.MasterID,
    77  	config WorkerConfig,
    78  ) (framework.WorkerImpl, error) {
    79  	return f.constructor(ctx, workerID, masterID, config.(C)), nil
    80  }
    81  
    82  // DeserializeConfig implements WorkerFactory.DeserializeConfig
    83  func (f *SimpleWorkerFactory[T, C]) DeserializeConfig(configBytes []byte) (WorkerConfig, error) {
    84  	var config C
    85  	config = reflect.New(reflect.TypeOf(config).Elem()).Interface().(C)
    86  	if err := json.Unmarshal(configBytes, config); err != nil {
    87  		return nil, errors.ErrDeserializeConfig.Wrap(err).GenWithStackByArgs()
    88  	}
    89  	return config, nil
    90  }
    91  
    92  // IsRetryableError implements WorkerFactory.IsRetryableError
    93  func (f *SimpleWorkerFactory[T, C]) IsRetryableError(err error) bool {
    94  	if errors.Is(err, errors.ErrDeserializeConfig) {
    95  		return false
    96  	}
    97  	if strings.Contains(err.Error(), string(errors.ErrDeserializeConfig.RFCCode())) {
    98  		return false
    99  	}
   100  	return true
   101  }