feat(compiler): Handle error function exit in tracing mode [LNG-250] (#921)

* Wrap function calls with xor

* Do not detach tracing call in case of error exit

* Fix comment
This commit is contained in:
InversionSpaces 2023-10-17 15:42:38 +02:00 committed by GitHub
parent 030a0d464b
commit 03d23eb577
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 32 deletions

View File

@ -25,11 +25,16 @@ object ValueModel {
def errorCode(error: VarModel): Option[VarModel] = def errorCode(error: VarModel): Option[VarModel] =
error.intoField("error_code") error.intoField("error_code")
def errorMessage(error: VarModel): Option[VarModel] =
error.intoField("message")
val error = VarModel.fromVarRaw(ValueRaw.error) val error = VarModel.fromVarRaw(ValueRaw.error)
val errorType = ValueRaw.errorType val errorType = ValueRaw.errorType
// NOTE: It should be safe as `:error:` should have `error_code` field // NOTE: It should be safe as `:error:` should have `error_code` field
val lastErrorCode = errorCode(error).get val lastErrorCode = errorCode(error).get
// NOTE: It should be safe as `:error:` should have `message` field
val lastErrorMessage = errorMessage(error).get
implicit object ValueModelEq extends Eq[ValueModel] { implicit object ValueModelEq extends Eq[ValueModel] {
override def eqv(x: ValueModel, y: ValueModel): Boolean = x == y override def eqv(x: ValueModel, y: ValueModel): Boolean = x == y

View File

@ -1,23 +1,15 @@
package aqua.model.transform.funcop package aqua.model.transform.funcop
import cats.data.Chain import aqua.model.*
import cats.Eval
import aqua.model.{
CallModel,
CallServiceModel,
LiteralModel,
MetaModel,
OpModel,
SeqModel,
ValueModel
}
import aqua.model.transform.pre.InitPeerCallable import aqua.model.transform.pre.InitPeerCallable
import aqua.model.ParModel import aqua.model.ParModel
import aqua.model.DetachModel import aqua.model.DetachModel
import aqua.model.transform.TransformConfig.TracingConfig import aqua.model.transform.TransformConfig.TracingConfig
import cats.data.Chain
import cats.Eval
import aqua.types.ScalarType
final case class Tracing( final case class Tracing(
enabledConfig: Option[TracingConfig], enabledConfig: Option[TracingConfig],
initCallable: InitPeerCallable initCallable: InitPeerCallable
@ -41,18 +33,39 @@ final case class Tracing(
.fold(child)(traceCall => .fold(child)(traceCall =>
/* seq: /* seq:
detach: call tracing enter detach: call tracing enter
<call-arrow-code> xor:
detach: call tracing exit */ seq:
<call-arrow-code>
detach: call tracing exit
seq:
call tracing error exit
rethrow error
*/
SeqModel.wrap( SeqModel.wrap(
DetachModel.wrap( DetachModel.wrap(
initCallable.onInitPeer.wrap( initCallable.onInitPeer.wrap(
traceCall(Event.Enter) traceCall(Event.Enter)
) )
), ),
child, XorModel.wrap(
DetachModel.wrap( SeqModel.wrap(
initCallable.onInitPeer.wrap( child,
traceCall(Event.Exit) DetachModel.wrap(
initCallable.onInitPeer.wrap(
traceCall(Event.Exit)
)
)
),
SeqModel.wrap(
/**
* NOTE: Here we don't wrap trace call
* with detach because Aqua VM ignores
* it if it is detached.
*/
initCallable.onInitPeer.wrap(
traceCall(Event.ErrorExit)
),
FailModel(ValueModel.error).leaf
) )
) )
) )
@ -64,23 +77,47 @@ final case class Tracing(
object Tracing { object Tracing {
enum Event { enum Event {
case Enter, Exit case Enter, Exit, ErrorExit
def toArg: ValueModel = LiteralModel.quote(this match { def toArg(suffix: String = ""): ValueModel = LiteralModel.quote((this match {
case Enter => "enter" case Enter => "enter"
case Exit => "exit" case Exit => "exit"
}) case ErrorExit => "exit with error"
}) + suffix)
} }
def traceCallModel(config: TracingConfig, arrowName: String)( private def traceCallModel(config: TracingConfig, arrowName: String)(
event: Event event: Event
): OpModel.Tree = ): OpModel.Tree = {
CallServiceModel( val serviceCall = (msg: ValueModel) =>
LiteralModel.quote(config.serviceId), CallServiceModel(
config.serviceFuncName, LiteralModel.quote(config.serviceId),
CallModel( config.serviceFuncName,
args = List(LiteralModel.quote(arrowName), event.toArg), CallModel(
exportTo = Nil args = List(LiteralModel.quote(arrowName), msg),
) exportTo = Nil
).leaf )
).leaf
event match {
case Event.ErrorExit =>
val errorName = "-return-error-msg-"
RestrictionModel(
errorName,
ScalarType.string
).wrap(
CallServiceModel(
LiteralModel.quote("op"),
"concat_strings",
CallModel(
args = List(event.toArg(": "), ValueModel.lastErrorMessage),
exportTo = List(CallModel.Export(errorName, ScalarType.string))
)
).leaf,
serviceCall(VarModel(errorName, ScalarType.string))
)
case _ => serviceCall(event.toArg())
}
}
} }