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 }