Skip to content

Commit

Permalink
Handle PanicSentinel in Interpreter (#1436)
Browse files Browse the repository at this point in the history
PR adds the ability to handle runtime exceptions 
in the interpreter and continue the execution 
passing the PanicSentinel value.
  • Loading branch information
4e6 authored and iamrecursion committed Feb 10, 2021
1 parent e4a3b5a commit e7d0932
Show file tree
Hide file tree
Showing 15 changed files with 692 additions and 969 deletions.
15 changes: 2 additions & 13 deletions docs/language-server/protocol-language-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ interface ExpressionUpdate {
An information about the computed value.

```typescript
type ExpressionUpdatePayload = Value | DatafalowError | RuntimeError | Poisoned;
type ExpressionUpdatePayload = Value | DatafalowError | Panic;

/**
* An empty payload. Indicates that the expression was computed to a value.
Expand All @@ -339,7 +339,7 @@ interface DataflowError {
/**
* Indicates that the expression failed with the runtime exception.
*/
interface RuntimeError {
interface Panic {
/**
* The error message.
*/
Expand All @@ -350,17 +350,6 @@ interface RuntimeError {
*/
trace: ExpressionId[];
}

/**
* Indicates that the expression was not computed due to a dependency,
* that failed with the runtime exception.
*/
interface Poisoned {
/**
* The list of expressions leading to the root expression that failed.
*/
trace: ExpressionId[];
}
```

### `VisualisationConfiguration`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,9 @@ final class ContextEventsListener(
case Api.ExpressionUpdate.Payload.DataflowError(trace) =>
ContextRegistryProtocol.ExpressionUpdate.Payload.DataflowError(trace)

case Api.ExpressionUpdate.Payload.RuntimeError(message, trace) =>
case Api.ExpressionUpdate.Payload.Panic(message, trace) =>
ContextRegistryProtocol.ExpressionUpdate.Payload
.RuntimeError(message, trace)

case Api.ExpressionUpdate.Payload.Poisoned(trace) =>
ContextRegistryProtocol.ExpressionUpdate.Payload.Poisoned(trace)
.Panic(message, trace)
}

/** Convert the runtime profiling info to the context registry protocol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,11 @@ object ContextRegistryProtocol {
* @param message the error message
* @param trace the stack trace
*/
case class RuntimeError(
case class Panic(
message: String,
trace: Seq[UUID]
) extends Payload

/** Indicates that the expression was not computed due to a dependency,
* that failed with the runtime exception.
*
* @param trace the list of expressions leading to the root error.
*/
case class Poisoned(trace: Seq[UUID]) extends Payload

private object CodecField {

val Type = "type"
Expand All @@ -166,9 +159,8 @@ object ContextRegistryProtocol {

val DataflowError = "DataflowError"

val RuntimeError = "RuntimeError"
val Panic = "Panic"

val Poisoned = "Poisoned"
}

implicit val encoder: Encoder[Payload] =
Expand All @@ -183,18 +175,11 @@ object ContextRegistryProtocol {
Json.obj(CodecField.Type -> PayloadType.DataflowError.asJson)
)

case m: Payload.RuntimeError =>
Encoder[Payload.RuntimeError]
case m: Payload.Panic =>
Encoder[Payload.Panic]
.apply(m)
.deepMerge(
Json.obj(CodecField.Type -> PayloadType.RuntimeError.asJson)
)

case m: Payload.Poisoned =>
Encoder[Payload.Poisoned]
.apply(m)
.deepMerge(
Json.obj(CodecField.Type -> PayloadType.Poisoned.asJson)
Json.obj(CodecField.Type -> PayloadType.Panic.asJson)
)
}

Expand All @@ -207,11 +192,8 @@ object ContextRegistryProtocol {
case PayloadType.DataflowError =>
Decoder[Payload.DataflowError].tryDecode(cursor)

case PayloadType.RuntimeError =>
Decoder[Payload.RuntimeError].tryDecode(cursor)

case PayloadType.Poisoned =>
Decoder[Payload.Poisoned].tryDecode(cursor)
case PayloadType.Panic =>
Decoder[Payload.Panic].tryDecode(cursor)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ final class SuggestionsHandler(

override def preStart(): Unit = {
context.system.eventStream
.subscribe(self, classOf[Api.ExpressionValuesComputed])
.subscribe(self, classOf[Api.ExpressionUpdates])
context.system.eventStream
.subscribe(self, classOf[Api.SuggestionsDatabaseModuleUpdateNotification])
context.system.eventStream.subscribe(self, classOf[ProjectNameChangedEvent])
Expand Down Expand Up @@ -167,11 +167,11 @@ final class SuggestionsHandler(
)
}

case Api.ExpressionValuesComputed(_, updates) =>
case Api.ExpressionUpdates(_, updates) =>
log.debug(
s"ExpressionValuesComputed ${updates.map(u => (u.expressionId, u.expressionType))}"
)
val types = updates
val types = updates.toSeq
.flatMap(update => update.expressionType.map(update.expressionId -> _))
suggestionsRepo
.updateAll(types)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class ContextEventsListenerSpec
None,
Vector(),
false,
Api.ExpressionUpdate.Payload.RuntimeError("Method failure", Seq())
Api.ExpressionUpdate.Payload.Panic("Method failure", Seq())
)
)
)
Expand All @@ -199,47 +199,7 @@ class ContextEventsListenerSpec
Vector(),
false,
ContextRegistryProtocol.ExpressionUpdate.Payload
.RuntimeError("Method failure", Seq())
)
),
None
)
)
)
}

"send poisoning error updates" taggedAs Retry in withDb {
(clientId, contextId, _, router, listener) =>
listener ! Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate(
Suggestions.local.externalId.get,
None,
None,
Vector(),
false,
Api.ExpressionUpdate.Payload.Poisoned(
Seq(Suggestions.method.externalId.get)
)
)
)
)

router.expectMsg(
DeliverToJsonController(
clientId,
ContextRegistryProtocol.ExpressionUpdatesNotification(
contextId,
Vector(
ContextRegistryProtocol.ExpressionUpdate(
Suggestions.local.externalId.get,
None,
None,
Vector(),
false,
ContextRegistryProtocol.ExpressionUpdate.Payload
.Poisoned(Seq(Suggestions.method.externalId.get))
.Panic("Method failure", Seq())
)
),
None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,6 @@ object Runtime {
value = classOf[Api.VisualisationModified],
name = "visualisationModified"
),
new JsonSubTypes.Type(
value = classOf[Api.ExpressionValuesComputed],
name = "expressionValuesComputed"
),
new JsonSubTypes.Type(
value = classOf[Api.ExpressionUpdates],
name = "expressionUpdates"
Expand Down Expand Up @@ -251,24 +247,6 @@ object Runtime {
case class LocalCall(expressionId: ExpressionId) extends StackItem
}

/** An update containing information about expression.
*
* @param expressionId expression id.
* @param expressionType the type of expression.
* @param methodCall the pointer to a method definition.
* @param profilingInfo profiling information about the execution of this
* expression
* @param fromCache whether or not the value for this expression came from
* the cache
*/
case class ExpressionValueUpdate(
expressionId: ExpressionId,
expressionType: Option[String],
methodCall: Option[MethodPointer],
profilingInfo: Vector[ProfilingInfo],
fromCache: Boolean
)

/** An update about the computed expression.
*
* @param expressionId the expression id
Expand Down Expand Up @@ -303,12 +281,8 @@ object Runtime {
name = "expressionUpdatePayloadDataflowError"
),
new JsonSubTypes.Type(
value = classOf[Payload.RuntimeError],
name = "expressionUpdatePayloadRuntimeError"
),
new JsonSubTypes.Type(
value = classOf[Payload.Poisoned],
name = "expressionUpdatePayloadPoisoned"
value = classOf[Payload.Panic],
name = "expressionUpdatePayloadPanic"
)
)
)
Expand All @@ -331,17 +305,11 @@ object Runtime {
* @param message the error message
* @param trace the stack trace
*/
case class RuntimeError(
case class Panic(
message: String,
trace: Seq[ExpressionId]
) extends Payload

/** Indicates that the expression was not computed due to a dependency,
* that failed with the runtime exception.
*
* @param trace the list of expressions leading to the root error.
*/
case class Poisoned(trace: Seq[ExpressionId]) extends Payload
}
}

Expand Down Expand Up @@ -397,17 +365,6 @@ object Runtime {
extends InvalidatedExpressions
}

// TODO: [DB] Remove when IDE implements new updates API
/** A notification about updated expressions of the context.
*
* @param contextId the context's id.
* @param updates a list of updates.
*/
case class ExpressionValuesComputed(
contextId: ContextId,
updates: Vector[ExpressionValueUpdate]
) extends ApiNotification

/** A notification about updated expressions of the context.
*
* @param contextId the context's id.
Expand Down
Loading

0 comments on commit e7d0932

Please sign in to comment.