-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Support array result for common action and sequence action #5290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support array result for common action and sequence action #5290
Conversation
@@ -57,7 +57,7 @@ case class ActivationMessage(override val transid: TransactionId, | |||
activationId: ActivationId, | |||
rootControllerIndex: ControllerInstanceId, | |||
blocking: Boolean, | |||
content: Option[JsObject], | |||
content: Option[JsValue], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- For common action to pass parameter as dict, it would use
Option[JsObject]
- For sequence action to pass parameter as array, it would use
Option[JsArray]
, e.g. the first action's JsArray result as the next action's input param.
@@ -412,7 +412,10 @@ class ElasticSearchActivationStore( | |||
.get("result") | |||
.map { r => | |||
val JsString(data) = r | |||
data.parseJson.asJsObject | |||
data.parseJson match { | |||
case JsArray(elements) => JsArray(elements) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Support store the JsArray result to ElasticSearch
.
var payload = msg.payload.toString(); | ||
var lines = payload.split(separator); | ||
// return array as next action's input | ||
return lines; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As comment said, return array as next action's input
This script file is used as test case for invoke sequence action which support array result
activation.response.result shouldBe Some( | ||
JsArray(JsObject("key1" -> JsString("value1")), JsObject("key2" -> JsString("value2")))) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because nodejs runtime
suports array result by default, add a system test case for return array result for it to test controller/invoker whether works well
@@ -52,6 +52,7 @@ import org.apache.openwhisk.core.containerpool.Container | |||
trait ActionContainer { | |||
def init(value: JsValue): (Int, Option[JsObject]) | |||
def run(value: JsValue): (Int, Option[JsObject]) | |||
def runForJsArray(value: JsValue): (Int, Option[JsArray]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally, need to change def run(...)
as below
def run(value: JsValue): (Int, Option[JsValue]) // Option[JsObject] -> Option[JsValue]
But i just add another new method here, two reasons.
- If change
def run
directly, there has a lot of code changes. - It is just for test, so i just add another new method, there has no need to introduce too many code modifications
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5290 +/- ##
===========================================
+ Coverage 45.04% 75.05% +30.00%
===========================================
Files 238 238
Lines 14179 14202 +23
Branches 617 608 -9
===========================================
+ Hits 6387 10659 +4272
+ Misses 7792 3543 -4249 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It generally looks good to me.
JsHelpers | ||
.getFieldPath(JsObject(fields), ERROR_FIELD, "statusCode") | ||
.orElse(JsHelpers.getFieldPath(JsObject(fields), "statusCode")) | ||
case _ => None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is for the array result case and there could be no statusCode
field in the array result, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, for array result, seems can't get the userDefined statusCode
implicit logging: Logging, | ||
as: ActorSystem, | ||
ec: ExecutionContext, | ||
tid: TransactionId): (Int, Option[JsArray]) = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason that we can't just change the result type to (Int, Option[JsValue])
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def runForJsArray
is added for test case, the return value is(Int, Option[JsArray])
- call chain here is:
def runForJsArray
->private def syncPostForJsArray
->def postForJsArray
Actually, in order to support test, we can change below method to support return (Int, Option[JsValue])
also
But if we change the run directly, there would be a lot of changes in openwhisk repo and all runtime codes should change as well.
So here, i added another extra method to test return array
This is just for impact the original code as little as possible
: #5290 (comment)
@@ -203,7 +203,7 @@ protected[core] object ActivationResponse extends DefaultJsonProtocol { | |||
truncated match { | |||
case None => | |||
val sizeOpt = Option(str).map(_.length) | |||
Try { str.parseJson.asJsObject } match { | |||
Try { str.parseJson } match { | |||
case scala.util.Success(result @ JsObject(fields)) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So even without asJsObject
, the result would match here?
Then, it was not necessary in the first place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val errorField = payloadContent.fields.get(ActivationResponse.ERROR_FIELD) | ||
val errorField: Option[JsValue] = activation.response.result match { | ||
case Some(JsObject(fields)) => fields.get(ActivationResponse.ERROR_FIELD) | ||
case _ => None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So users can't define the explicit error response when the result is a JSON array.
But there would be no difference in the JSON-object-based action, right?
Sometimes, libraries return an error
filed and OW considers that as an error of an action as well.
Since there would be no behavioral difference in the JSON-object-based actions, there would be no difference in existing semantics, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- So users can't define the explicit error response when the result is a JSON array.
Yes, can't define the explicit error response for a JSON array,
but if we want to define the explicit error response, normally, user should return the JSON-object result. - But there would be no difference in the JSON-object-based action, right?
For the JSON-object-based action, have no any bad influences on these actions, have no any change. - Regarding
Sometimes, libraries return an error filed and OW considers that as an error of an action as well.
Since there would be no behavioral difference in the JSON-object-based actions, there would be no difference in existing semantics, right?
I am not sure whether i understand correctly, if libraries return an error
or user's codes has some error, normally, there would has catch(....)
statement in user's code, and in catch statement, user can return the error or some excetion error with JSON-object result.
If user codes run well without any error or exception, can return array result finally.
case None => (Map.empty, JsObject.empty) | ||
case Some(JsObject(fields)) if initArgs.isEmpty => (Map.empty, JsObject(fields)) | ||
case Some(JsObject(fields)) => | ||
val (env, args) = JsObject(fields).fields.partition(k => initArgs.contains(k._1)) | ||
(env, JsObject(args)) | ||
case Some(JsArray(elements)) => (Map.empty, JsArray(elements)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
case None => (Map.empty, JsObject.empty) | |
case Some(JsObject(fields)) if initArgs.isEmpty => (Map.empty, JsObject(fields)) | |
case Some(JsObject(fields)) => | |
val (env, args) = JsObject(fields).fields.partition(k => initArgs.contains(k._1)) | |
(env, JsObject(args)) | |
case Some(JsArray(elements)) => (Map.empty, JsArray(elements)) | |
case None => (Map.empty, JsObject.empty) | |
case Some(JsArray(elements)) => (Map.empty, JsArray(elements)) | |
case Some(fields) if initArgs.isEmpty => (Map.empty, fields) | |
case Some(fields) => | |
val (env, args) = fields.fields.partition(k => initArgs.contains(k._1)) | |
(env, JsObject(args)) | |
This one can be changed like this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, would report error, but there has a optimize point here.
Change JsObject(fields).fields
to fields
@@ -541,6 +541,31 @@ class WskSequenceTests extends TestHelpers with WskTestHelpers with StreamLoggin | |||
} | |||
} | |||
|
|||
it should "invoke a sequence which support array result" in withAssetCleaner(wskprops) { (wp, assetHelper) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should "invoke a sequence which support array result" in withAssetCleaner(wskprops) { (wp, assetHelper) => | |
it should "invoke a sequence which supports array result" in withAssetCleaner(wskprops) { (wp, assetHelper) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated accordingly
val params = Map("params" -> JsObject(wrappedParams ++ escapedParams)) | ||
JsObject(params ++ action ++ state) | ||
} | ||
case _ => JsObject.empty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we just do this, can we support conductor actions with JSON array results?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm..i am not sure, if want to support, i think we can submit in next pr.
Couchdb already suports
This test case is just for nodejs
460fdff
to
84d220f
Compare
It generally looks good to me. |
Yes, has no issue. Should merge this first, because other runtime prs depend on this pr. |
Have any comment? due to there exist several runtime pr depend on this pr, so i just asked. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am ok with this change if there is no side effect to existing features.
* Support array result * Make controller accept json array * Make elasticsearch support json array Couchdb already suports * Make go runtime test cases due to depend on this * Add test case for array result for nodejs runtime * Make sequence action to support array result * Optimize sequence action to support array result * Fix test case for sequence action feature * Add test case for sequence action This test case is just for nodejs * Add extra method runForJsArray for runtime tests * Fix build error * Fix review comment
Description
POEM document pr: #5244
This feature is: provide support array result feature for common action and sequence action. e.g.
The
response.result
must usetext
to store, because different activation's same filed may use different type, e.g.one activation's result's name filed value is string , e.g. {"name": "jack"}
another activation's result's name filed value is int, e.g. {"name": 12}
Elasticsearch doesn't support this, it store like this, it would report error.
As above example, we already know,
nodejs
runtime supports this feature by default.But other runtimes(e.g. go, java, php, etc) don't support,
Related issue and scope
My changes affect the following components
Types of changes
Checklist: