rabbah closed pull request #3799: Display proper error when sequence invocation
fails due to missing component
URL: https://github.com/apache/incubator-openwhisk/pull/3799
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git
a/core/controller/src/main/scala/whisk/core/controller/actions/SequenceActions.scala
b/core/controller/src/main/scala/whisk/core/controller/actions/SequenceActions.scala
index dd3e3314f9..cd6c1eab35 100644
---
a/core/controller/src/main/scala/whisk/core/controller/actions/SequenceActions.scala
+++
b/core/controller/src/main/scala/whisk/core/controller/actions/SequenceActions.scala
@@ -34,6 +34,7 @@ import whisk.common.Logging
import whisk.common.TransactionId
import whisk.core.controller.WhiskServices
import whisk.core.database.ActivationStore
+import whisk.core.database.NoDocumentException
import whisk.core.entity._
import whisk.core.entity.size.SizeInt
import whisk.core.entity.types._
@@ -259,14 +260,21 @@ protected[actions] trait SequenceActions {
.foldLeft(initialAccounting) { (accountingFuture, futureAction) =>
accountingFuture.flatMap { accounting =>
if (accounting.atomicActionCnt < actionSequenceLimit) {
- invokeNextAction(user, futureAction, accounting, cause).flatMap {
accounting =>
- if (!accounting.shortcircuit) {
- Future.successful(accounting)
- } else {
- // this is to short circuit the fold
- Future.failed(FailedSequenceActivation(accounting)) //
terminates the fold
+ invokeNextAction(user, futureAction, accounting, cause)
+ .flatMap { accounting =>
+ if (!accounting.shortcircuit) {
+ Future.successful(accounting)
+ } else {
+ // this is to short circuit the fold
+ Future.failed(FailedSequenceActivation(accounting)) //
terminates the fold
+ }
+ }
+ .recoverWith {
+ case _: NoDocumentException =>
+ val updatedAccount =
+
accounting.fail(ActivationResponse.applicationError(sequenceComponentNotFound),
None)
+ Future.failed(FailedSequenceActivation(updatedAccount)) //
terminates the fold
}
- }
} else {
val updatedAccount =
accounting.fail(ActivationResponse.applicationError(sequenceIsTooLong), None)
Future.failed(FailedSequenceActivation(updatedAccount)) //
terminates the fold
diff --git
a/tests/src/test/scala/whisk/core/controller/test/SequenceApiTests.scala
b/tests/src/test/scala/whisk/core/controller/test/SequenceApiTests.scala
index 97842785a4..5bc1996300 100644
--- a/tests/src/test/scala/whisk/core/controller/test/SequenceApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/SequenceApiTests.scala
@@ -19,22 +19,19 @@ package whisk.core.controller.test
import scala.concurrent.duration.DurationInt
import scala.language.postfixOps
-
+import java.time.Instant
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
-
import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.server.Route
-
import spray.json._
import spray.json.DefaultJsonProtocol._
-
import whisk.common.TransactionId
import whisk.core.controller.WhiskActionsApi
import whisk.core.entity._
-import whisk.http.ErrorResponse
-import whisk.http.Messages
+import whisk.http.{ErrorResponse, Messages}
+import whisk.http.Messages.sequenceComponentNotFound
/**
* Tests Sequence API - stand-alone tests that require only the controller to
be up
@@ -53,6 +50,35 @@ class SequenceApiTests extends ControllerTestCommon with
WhiskActionsApi {
val allowedActionDuration = 120 seconds
+ it should "partially invoke a sequence with missing component and produce
component missing error" in {
+ implicit val tid = transid()
+ val seqName = s"${aname()}_seq"
+ val compName1 = s"${aname()}_comp1"
+ val compName2 = s"${aname()}_comp2"
+ val comp1Activation = WhiskActivation(
+ namespace,
+ EntityName(compName1),
+ creds.subject,
+ activationIdFactory.make(),
+ start = Instant.now,
+ end = Instant.now)
+
+ putSimpleSequenceInDB(seqName, namespace, Vector(compName1, compName2))
+ deleteAction(DocId(s"$namespace/$compName2"))
+ loadBalancer.whiskActivationStub = Some((1.milliseconds, comp1Activation))
+
+ Post(s"$collectionPath/$seqName?blocking=true") ~>
Route.seal(routes(creds)) ~> check {
+ deleteAction(DocId(s"$namespace/$seqName"))
+ deleteAction(DocId(s"$namespace/$compName1"))
+ status should be(BadGateway)
+ val response = responseAs[JsObject]
+ response.fields("response") shouldBe
ActivationResponse.applicationError(sequenceComponentNotFound).toExtendedJson
+ val logs = response.fields("logs").convertTo[JsArray]
+ logs.elements.size shouldBe 1
+ logs.elements.head shouldBe comp1Activation.activationId.toJson
+ }
+ }
+
it should "reject creation of sequence with more actions than allowed limit"
in {
implicit val tid = transid()
val seqName = EntityName(s"${aname()}_toomanyactions")
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services