Ability to distinguish between different action performance events
complete
Brad H (Tekhaus)
Original title: First class tag support for graphql mutations
Would love to be able to just get the result of a graphql mutation in the same manner as a graphql query, without having to check and filter perform actions.
If that isn't viable due to platform/API restrictions, then how about the ability to wrap a custom user event around a mutation, and then being able to just listen for the custom event to get the mutation result?
Isaac Bowen
complete
https://mechanic.canny.io/changelog/action-definitions-now-support-meta-information :)
Isaac Bowen
Current syntax design:
{% action %}
{
"type": "foo",
"options": "bar",
"meta": {
"baz": "qux"
}
}
{% endaction %}
... which compiles to:
{
"action": {
"type": "foo",
"options": "bar",
"meta": {
"baz": "qux"
}
}
}
Super, super simple. This is a third form of the action tag, alongside inline (
{% action "foo", "bar", "baz" %}
), and the existing block form ({% action "foo" %}{"bar": "baz"}{% endaction %}
). Credit to Matt Sodomsky for this one. :) It allows for defining a "meta"
object, as a peer of "type"
and "options"
, which is the level at which we need to define properties of the run itself (as distinct from options scoped to the run type
).Isaac Bowen
New approach:
rather
than using a custom event topic, allow action objects to include metadata, which can be used for hinging in task logic.{
"action": {
"type": "foo",
"options": "bar",
"meta": {
"baz": "qux"
}
}
}
A task subscribing to mechanic/actions/perform could then do something like this to identify the action it's interested in:
{% if action.meta.baz == "qux" %}
Three upsides to this: allowing for nuanced, programmatic identification based on
any
kind of data (not just event topics); allowing for passing arbitrary data on to the next task run (like Tim was saying); better in-app contextual annotation (like PN is talking about in Slack).Thoughts, y'all?
Isaac Bowen
How would the action tag handle this, for a Liquid shorthand? Good question. :D
M
Matt Scheurich
Isaac Bowen: OK, I got a suggestion piggy-backing on the
action.meta
thing (which is a really cool idea, btw):{% action "http" %}
{
"url": "https://api.happydog.com/throw_frisbee",
"method": "POST",
"body": {
"dog_id": 123
},
"meta": {
"perform": "threw_frisbee"
}
}
{% endaction %}
Then I could add a specific topic to task's subscription list like so to subscribe specifically to this one child action:
mechanic/actions/perform/threw_frisbee
(could be cool to ensure support for adding delays, like
+5.minutes
)Also, having this
action.meta
object could maybe also give us space to do some other sneaky tricks, e.g. action.meta.run_at
could allow us to set a specific time to trigger this child action, or maybe this could be something else like action.config.run_at
-- obviously not required for {% action "event" %}
child actions since it already supports run_at
.I also like the idea of the
action.meta
object being free-form as well so I can stuff some information there that could be passed through to multiple successive child actions without needing to refer back to the previous actions' data via event.parent
.Tim Mackey
Isaac Bowen: I think your new proposal is great—simple way to solve multiple problems. Regarding the shorthand version, I’d say don’t support it. In my opinion you’d be a masochist to use that many options in a single line tag when you have the option for the verbose tag format.
Matt Scheurich: I do like the idea of the perform keyword being defined to extend the event topic. Having a way to individually delay or schedule perform topics would be useful too, and something I previously have wanted.
I wonder though, would the extended perform topics have a real advantage, or only a perceived advantage? Offhand I’m not sure—is there a functional difference between a) subscribing to
mechanic/actions/perform
then filtering by metadata when defining actions, vs b) subscribing to a more specific mechanic/actions/perform/user_topic
topic? Would it make the task run log cleaner? Perhaps there would be a platform benefit in reduced overhead?M
Matt Scheurich
Tim Mackey: I agree with what you said re: shorthand -- prob not needed.
For the diff between usage of perform namespace or using meta, I guess it depends on the user. Using perform namespace in conjunction with delay modifiers gives some control there, plus it also means you can put the response code on same level as other event.topic matcher conditions to avoid all the nested if/else statements.
The main point in my view is to have ability to reduce levels of nested conditions, or to provide more direct targeting/specificity for any following actions.
Brad H (Tekhaus)
100% would reduce run log and task run time in certain scenarios, like this...
I have a custom task that:
- Makes an HTTP GET to a microservice, which returns JSON
- Uses mechanic/actions/perform to receive the JSON result
- Starts a bulk operation to get collection and product data
- Uses mechanic/shopify/bulk_operation to receive the JSONL result
- Updates a TON of collection and product metafields
This flow works great. However, on review the job log is littered with thousands of child event IDs, which are there since the task is subscribed to __mechanic/actions/perform__, and of course mutations are actions. The "perform" event block explicitly checks for action type == "http", but that block still has to run 5k+ times to do that. And even though each event run is itself only a few ms, the cap on 2 runs makes this task take a long time to run. (attached screenshot taken after all the mutations were complete, and just watching the empty perform events go through).
My current plan to mitigate this is to split this into two tasks and just post the JSON result from the external call to a custom event for the remainder of the processing.
Isaac Bowen
planned
Isaac Bowen
Renamed this post to more accurately describe the thing we're talking about now. :)
Isaac Bowen
Tim Mackey Yeah, the
perform_topic
action property would work with any
actions, of any type.You make a really, really interesting point about supplying additional information. I think we'd need to introduce a new event property to hold this kind of thing;
event.data
can be any JSON type, so we can't assume that we can merge in arbitrary additional data from the action definition. But, we could conceivably add in event.meta
or event.context
or something.Tim Mackey
Brad mentioned the ability to wrap http actions, is that something that is being considered here? I could see this being useful for pretty much every action type that returns data, actually. I've been in a similar situation the past couple days where a single task has to respond to the /perform event and differentiate between various action types.
Not sure if it's within the scope of this feature request, but it would be additionally useful if
perform_topic
actions or just actions in general could pass additional data like the event action does. Say you need to pass a counter to your child action, you could pass it this way rather than having to read/write a cache value:{% action "http" %}
{
"method": "get",
"url": "https://example.com",
"body": "hello world!",
"additional_data": {
"request_counter": 1
}
}
{% endaction %}
P
Patou Tech
Isaac Bowen: sounds good to me! Being able to label child actions is actually a super awesome feature and should hopefully mean I don't need to subscribe to all
mechanic/actions/perform
child events and see all unwanted child actions, like cache
.Brad H (Tekhaus)
This would be great.... I was literally considering this model for my next orderEdit task. Without this in place, I was just going to have a case/when in the mechanic/actions/perform event topic that then called a custom user event based on the action.run.result.data.[mutation] name
Isaac Bowen
Being able to specify a custom user event - I'm interested in this. It fits Mechanic's architecture priorities well (in a way that adding potential side-effects to task evaluation specifically does not).
{% action perform_topic: "user/order/edit1" %}
mutation { ... }
{% endaction %}
{
"action": {
"type": "shopify",
"options": "mutation { ... }",
"perform_topic": "user/orders/edit1"
}
}
This could totally be a thing.
Matt Scheurich Given your request, how does this feel to you?
M
Matt Scheurich
Isaac Bowen: Super cool, I think. That way instead of subscribing to the bulk
mechanic/actions/perform
I could just subscribe to specifically labelled actions within the current task. It would definitely simplify code when detecting and reacting to graphql and http child actions.Load More
→