github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/processors/command/provide.go (about)

     1  /*
     2   * Copyright (c) 2020-present unTill Pro, Ltd.
     3   */
     4  
     5  package commandprocessor
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"time"
    11  
    12  	"github.com/voedger/voedger/pkg/goutils/logger"
    13  
    14  	"github.com/voedger/voedger/pkg/appparts"
    15  	"github.com/voedger/voedger/pkg/iauthnz"
    16  	"github.com/voedger/voedger/pkg/in10n"
    17  	"github.com/voedger/voedger/pkg/isecrets"
    18  	"github.com/voedger/voedger/pkg/istructs"
    19  	imetrics "github.com/voedger/voedger/pkg/metrics"
    20  	"github.com/voedger/voedger/pkg/pipeline"
    21  	coreutils "github.com/voedger/voedger/pkg/utils"
    22  )
    23  
    24  type workspace struct {
    25  	NextWLogOffset istructs.Offset
    26  	idGenerator    istructs.IIDGenerator
    27  }
    28  
    29  type cmdProc struct {
    30  	pNumber       istructs.PartitionID
    31  	appPartition  *appPartition
    32  	appPartitions map[istructs.AppQName]*appPartition
    33  	n10nBroker    in10n.IN10nBroker
    34  	now           coreutils.TimeFunc
    35  	authenticator iauthnz.IAuthenticator
    36  	authorizer    iauthnz.IAuthorizer
    37  	storeOp       pipeline.ISyncOperator
    38  }
    39  
    40  type appPartition struct {
    41  	workspaces     map[istructs.WSID]*workspace
    42  	nextPLogOffset istructs.Offset
    43  }
    44  
    45  // syncActualizerFactory - это фабрика(разделИД), которая возвращает свитч, в бранчах которого по синхронному актуализатору на каждое приложение, внутри каждого - проекторы на каждое приложение
    46  func ProvideServiceFactory(appParts appparts.IAppPartitions, now coreutils.TimeFunc,
    47  	n10nBroker in10n.IN10nBroker, metrics imetrics.IMetrics, vvm VVMName, authenticator iauthnz.IAuthenticator, authorizer iauthnz.IAuthorizer,
    48  	secretReader isecrets.ISecretReader) ServiceFactory {
    49  	return func(commandsChannel CommandChannel, partitionID istructs.PartitionID) pipeline.IService {
    50  		cmdProc := &cmdProc{
    51  			pNumber:       partitionID,
    52  			appPartitions: map[istructs.AppQName]*appPartition{},
    53  			n10nBroker:    n10nBroker,
    54  			now:           now,
    55  			authenticator: authenticator,
    56  			authorizer:    authorizer,
    57  		}
    58  
    59  		return pipeline.NewService(func(vvmCtx context.Context) {
    60  			hsp := newHostStateProvider(vvmCtx, partitionID, secretReader)
    61  			//syncActualizerOperator := syncActualizerFactory(vvmCtx, partitionID)
    62  			cmdProc.storeOp = pipeline.NewSyncPipeline(vvmCtx, "store",
    63  				pipeline.WireFunc("applyRecords", func(ctx context.Context, work interface{}) (err error) {
    64  					// sync apply records
    65  					cmd := work.(*cmdWorkpiece)
    66  					if err = cmd.appStructs.Records().Apply(cmd.pLogEvent); err != nil {
    67  						cmd.appPartitionRestartScheduled = true
    68  					}
    69  					return err
    70  				}), pipeline.WireSyncOperator("syncProjectorsAndPutWLog", pipeline.ForkOperator(pipeline.ForkSame,
    71  					// forK: sync projector and PutWLog
    72  
    73  					pipeline.ForkBranch(
    74  						pipeline.NewSyncOp(func(ctx context.Context, work interface{}) (err error) {
    75  							cmd := work.(*cmdWorkpiece)
    76  
    77  							cmd.syncProjectorsStart = time.Now()
    78  							err = cmd.appPart.DoSyncActualizer(ctx, work)
    79  							cmd.metrics.increase(ProjectorsSeconds, time.Since(cmd.syncProjectorsStart).Seconds())
    80  							cmd.syncProjectorsStart = time.Time{}
    81  
    82  							if err != nil {
    83  								cmd.appPartitionRestartScheduled = true
    84  							}
    85  
    86  							return err
    87  						}),
    88  					),
    89  
    90  					pipeline.ForkBranch(pipeline.NewSyncOp(func(ctx context.Context, work interface{}) (err error) {
    91  						// put WLog
    92  						cmd := work.(*cmdWorkpiece)
    93  						if err = cmd.appStructs.Events().PutWlog(cmd.pLogEvent); err != nil {
    94  							cmd.appPartitionRestartScheduled = true
    95  						} else {
    96  							cmd.workspace.NextWLogOffset++
    97  						}
    98  						return
    99  					})),
   100  				)))
   101  			cmdPipeline := pipeline.NewSyncPipeline(vvmCtx, "Command Processor",
   102  				pipeline.WireFunc("borrowAppPart", borrowAppPart),
   103  				pipeline.WireFunc("limitCallRate", limitCallRate),
   104  				pipeline.WireFunc("getWSDesc", getWSDesc),
   105  				pipeline.WireFunc("authenticate", cmdProc.authenticate),
   106  				pipeline.WireFunc("checkWSInitialized", checkWSInitialized),
   107  				pipeline.WireFunc("checkWSActive", checkWSActive),
   108  				pipeline.WireFunc("getIWorkspace", getIWorkspace),
   109  				pipeline.WireFunc("getAppPartition", cmdProc.getAppPartition),
   110  				pipeline.WireFunc("getICommand", getICommand),
   111  				pipeline.WireFunc("getResources", getResources),
   112  				pipeline.WireFunc("getExec", getExec),
   113  				pipeline.WireFunc("authorizeRequest", cmdProc.authorizeRequest),
   114  				pipeline.WireFunc("unmarshalRequestBody", unmarshalRequestBody),
   115  				pipeline.WireFunc("getWorkspace", cmdProc.getWorkspace),
   116  				pipeline.WireFunc("getRawEventBuilderBuilders", cmdProc.getRawEventBuilder),
   117  				pipeline.WireFunc("getArgsObject", getArgsObject),
   118  				pipeline.WireFunc("getUnloggedArgsObject", getUnloggedArgsObject),
   119  				pipeline.WireFunc("checkArgsRefIntegrity", checkArgsRefIntegrity),
   120  				pipeline.WireFunc("parseCUDs", parseCUDs),
   121  				pipeline.WireSyncOperator("wrongArgsCatcher", &wrongArgsCatcher{}), // any error before -> wrap error into bad request http error
   122  				pipeline.WireFunc("authorizeCUDs", cmdProc.authorizeCUDs),
   123  				pipeline.WireFunc("checkIsActiveinCUDs", checkIsActiveInCUDs),
   124  				pipeline.WireFunc("writeCUDs", cmdProc.writeCUDs),
   125  				pipeline.WireFunc("getCmdResultBuilder", cmdProc.getCmdResultBuilder),
   126  				pipeline.WireFunc("buildCommandArgs", cmdProc.buildCommandArgs),
   127  				pipeline.WireFunc("execCommand", execCommand),
   128  				pipeline.WireFunc("build raw event", buildRawEvent),
   129  				pipeline.WireFunc("eventValidators", cmdProc.eventValidators),
   130  				pipeline.WireFunc("validateCUDsQNames", cmdProc.validateCUDsQNames),
   131  				pipeline.WireFunc("cudsValidators", cmdProc.cudsValidators),
   132  				pipeline.WireFunc("validateCmdResult", validateCmdResult),
   133  				pipeline.WireFunc("getIDGenerator", getIDGenerator),
   134  				pipeline.WireFunc("putPLog", cmdProc.putPLog),
   135  				pipeline.WireFunc("store", cmdProc.storeOp.DoSync),
   136  				pipeline.WireFunc("n10n", cmdProc.n10n),
   137  			)
   138  			// TODO: сделать потом plogOffset свой по каждому разделу, wlogoffset - свой для каждого wsid
   139  			defer cmdPipeline.Close()
   140  			for vvmCtx.Err() == nil {
   141  				select {
   142  				case intf := <-commandsChannel:
   143  					start := time.Now()
   144  					cmdMes := intf.(ICommandMessage)
   145  					cmd := &cmdWorkpiece{
   146  						cmdMes:            cmdMes,
   147  						requestData:       coreutils.MapObject{},
   148  						appParts:          appParts,
   149  						hostStateProvider: hsp,
   150  						metrics: commandProcessorMetrics{
   151  							vvmName: string(vvm),
   152  							app:     cmdMes.AppQName(),
   153  							metrics: metrics,
   154  						},
   155  					}
   156  					cmd.metrics.increase(CommandsTotal, 1.0)
   157  					cmdHandlingErr := cmdPipeline.SendSync(cmd)
   158  					if cmdHandlingErr != nil {
   159  						logger.Error(cmdHandlingErr)
   160  					}
   161  					sendResponse(cmd, cmdHandlingErr)
   162  					if cmd.appPartitionRestartScheduled {
   163  						logger.Info(fmt.Sprintf("partition %d will be restarted due of an error on writing to Log: %s", cmd.cmdMes.PartitionID(), cmdHandlingErr))
   164  						delete(cmdProc.appPartitions, cmd.cmdMes.AppQName())
   165  					}
   166  					cmd.release()
   167  					metrics.IncreaseApp(CommandsSeconds, string(vvm), cmdMes.AppQName(), time.Since(start).Seconds())
   168  				case <-vvmCtx.Done():
   169  					cmdProc.appPartitions = map[istructs.AppQName]*appPartition{} // clear appPartitions to test recovery
   170  					return
   171  				}
   172  			}
   173  		})
   174  	}
   175  }