Skip to content
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

New op values (cancelaction, queryaction,and queryallactions) #335

Open
danielpeintner opened this issue Sep 1, 2021 · 14 comments
Open
Labels
for next iteration Planned or postponed topics for the future priority: high Issues that will be tackled in 2024 wait-for-td

Comments

@danielpeintner
Copy link
Contributor

There is a WIP PR, see w3c/wot-thing-description#1208

Once baked into the TD document we might need to discuss the consequences for the Scripting API.

@danielpeintner
Copy link
Contributor Author

I had a chat with @egekorkan and I would like to describe how he sees the relation between TD and Scripting API w.r.t. cancelling/querying actions.

  • An action in a TD should have a flag to indicate whether an action is async (true/false). Similar to what we have already with safe and idempotent (see ActionAffordance)
    TODO, this is not there yet!
  • action with async == false should describe with output the result it gets back directly (as we do today)
  • action with async == true should describe with output the "handler" it gets back e.g., an object with
    • an href pointing to a cancel operation
    • an href pointing to a query operation
    • an href pointing to where get the actual value if action is finished
      Question from my side: Should/can this object be standardized or somehow annotated to know what is what?
  • Different to what we envisioned (using an ActionHandler with methods to query/cancel actions) he suggests to have 2 new methods besides invokeAction(...)
    • cancelAction(...) with options
    • queryAction(...) with options
      which can be called also from other parts in the code.. no need to have an ActionHandler object
      Question from my side: What is the input for these new methods (we may have static or dynamic hrefs for cancelling/querying)

I'm looking forward to comments!
@egekorkan please comment if I misinterpreted something 🙃

@egekorkan
Copy link
Contributor

Thanks for noting this down! I think it represents my thoughts really well. I had opened w3c/wot-thing-description#1408 after this discussion. Just to avoid some misconceptions:

  • The handler object is not necessarily the output of the action in the payload, it can be in the header. This means that a Scripting API runtime needs to be knowledgable enough to abstract the relevant information. How this information is conveyed can be from our standards or others. Core Profile has define one way, Ege Profile can define another way and the runtime must pick up this information. One payload definition "standard" is https://tools.ietf.org/id/draft-kelly-json-hal-01.html
  • What the input should be is also a bit tricky. I (thus not 100% sure) think that for cancelling and querying we do not need an input other than the id. This id can be passed by the script to the runtime and the runtime knows where to insert it, like in the header, body etc.

@zolkis
Copy link
Contributor

zolkis commented Mar 2, 2022

The "async" terminology is not correct, as all actions are async (on the network). A better name is needed.
Basically we want to express whether an action is cancellable and queryable, which is a better split than inventing a term like "async" which is overloaded on its own, and here it means two different things under the same hat - that is a mess.
Also, there might be cases when an action is cancelable, but not queryable, and when is queryable, but not cancelable. WoT doesn't dictate a new standard here, but models other protocols, right? So we need to be able to model those combinations, instead of sweeping them under the same rug.

As for scripting API design, the action id would be a new thing, but if we want separate op's for queryaction and cancelaction, then the id is needed, and we should model it by separate calls indeed. The reason is the following (discussing design alternatives).

  1. From an idiomatic point of view, we could also use AbortController and AbortSignal to cancel, but we'd still need a method for the status query, so this design would not be clean, nor tracking the TD op's well.

  2. As to the idea of an action control object with 3 methods,

  • query() or Promise<ActionStatus> status(options),
  • cancel() and
  • Promise<InteractionOutput> result().

If a script doesn't want to cancel or query the status, could right away call
result = await action.result();

But then the same result() method should be used for the "sync" type of action, which is a complication.

  1. Alternatively, variable return types (action control object or InteractionOutput) would be a very ugly kludge, so no-no.

In summary, yes, separate methods + id seem to be the cleanest design.
Scripting spec can add support for action id (a breaking change) and 2 new methods for queryAction() and cancelAction() (non-breaking).
Scripting spec doesn't need to expose the TD flag for "async", since if an action is not cancelable, the cancel() method could fail with an appropriate error.

@egekorkan
Copy link
Contributor

I would be open for other names. Just a precision on the following comment:

Basically we want to express whether an action is cancellable and queryable, which is a better split than inventing a term like "async" which is overloaded on its own

An action can be queried even if it is synchronous. It is relatively easy to implement a 10 second lasting response handler in a backend library so the consumer can query it in the meantime. The async flag does not indicate whether an action is queriable or not.

@zolkis
Copy link
Contributor

zolkis commented Mar 2, 2022

Even if an action appears to be synchronous, it is asynchronous, and if it can be queried, just proves it's async. :).
So you're saying all actions are queryable, regardless if they are labeled "sync" or "async"?
Then the only thing needed is whether an action is cancellable or not.
Since cancellation in general cannot be guaranteed, we don't even need the cancellable information, since an attempt to cancel can be make even if the action doesn't support it - then it (the Thing in the other end, or the local scripting implementation) will either signal an error, or ack, or nothing.

@egekorkan
Copy link
Contributor

egekorkan commented Mar 2, 2022

Sort of but I think before future discussion, what I mean by these words is what I have illustrated (literally) at w3c/wot-thing-description#890 . I would be open for alternatives

@zolkis
Copy link
Contributor

zolkis commented Mar 7, 2022

On the call on 7. March several use cases for actions were discussed:

  • canceling an action from another client (needs to identify the action [instance])
  • parametrized actions using the same name, e.g. a timer, and possibility to cancel one given instance
  • running several actions in a transaction and canceling (rolling back) the transaction
  • possibility to record actions history (e.g. into a distributed ledger) together with some kind of id
  • etc.

In addition to the use cases, various policies are possible as well, for instance:

  • one could cancel an action started by another client, only if permitted (e.g. a security token is provided)
  • one could restrict action instances, e.g. only one instance is allowed any time (per client or per Thing), meaning an action can always be identified by name [+client endpoint] only.
  • etc.

@danielpeintner @ashimura @egekorkan @relu91 @JKRhb @k-toumura please complete/edit these
(edit this comment freely).

@zolkis
Copy link
Contributor

zolkis commented Mar 7, 2022

The question is, can we design an API that would support all these variations in use cases and policies.

Generic alternatives were discussed above, were the conclusion was we need the design with separate cancelAction() and queryAction() calls.

However, we could extend invoking an action with more options, and support action id's, even if the TD spec doesn't (yet) support them (since the implementations can always generate an id).

Instead of returning an id, we could also use a returned object instead, which is more future-proof.
For start, the updated API could look something like

Promise<ActionControl> invokeAction(DOMString actionName,  // could also return a tuple
                              optional InteractionInput params = null,
                              optional InteractionOptions options = null);

Promise<undefined> cancelAction(DOMString actionName,
                              optional InteractionInput params = null,  // contains the id
                              optional InteractionOptions options = null);  // or data could contain the id 

Promise<InteractionOutput> queryAction(DOMString actionName,
                              optional InteractionInput params = null,  // contains the id
                              optional InteractionOptions options = null);  // or data could contain the id 

[SecureContext, Exposed=(Window,Worker)]
interface ActionControl {
    readonly attribute Promise<InteractionOutput> result;
    readonly attribute USVString id;
};

Alternatively, invokeAction() could return a tuple of (Promise , USVString), but I thought an object would be more future-proof.

Note that the invokeAction promise can resolve right away, whereas the client would mainly await for the result promise.

const ac = await thing.invokeAction("temperature", { units: "Celsius" });
const id = ac.id;
var output = await ac.result;

or directly

var output = await (await thing.invokeAction("temperature", { units: "Celsius" })).result;

@egekorkan
Copy link
Contributor

I like the proposal. Just that I think it might be too early to define something like a result if it really should signify the end of the physical action process. We do not have any plan on how to map the result of a query to the state of the action, thus we do not know if pending means something else than completed

@danielpeintner
Copy link
Contributor Author

2 comments (which do not affect the proposal itself)

  • I suggest to change ac.result to ac.output since this is the term in the TD
  • I wonder whether we should use a method call instead of an attribute. i.e., ac.output() which is more aligned with value() in InteractionOutput

@danielpeintner danielpeintner changed the title New op values (queryaction and cancelaction) New op values (cancelaction, queryaction,and queryallactions) Mar 9, 2022
@danielpeintner
Copy link
Contributor Author

FYI: besides queryaction and cancelaction there is also queryallactions (I updated the title of the issue accordingly)

@relu91 relu91 added the priority: high Issues that will be tackled in 2024 label Jan 22, 2024
@danielpeintner
Copy link
Contributor Author

danielpeintner commented Jan 22, 2024

I know that cancelaction, queryaction etc are defined in the TD specification but I still have the feeling the "way it works" is under-specified. Having said that, I don't think it is implementable that way.

Do you see it differently @egekorkan ?
see also w3c/wot-thing-description#1408

Hence I propose to add the label:wait-for-td

@egekorkan
Copy link
Contributor

I agree that it is underspecified and we can indeed wait for the TD TF to resolve this first. The parts that are underspecified are mentioned above but to summarise:

  • How to handle dynamic ids (if that is the case)
  • How to describe input and output of both operations.

Of course once those are specified by the TD, the way they are exposed in the scripting level needs a separate discussion.

@danielpeintner
Copy link
Contributor Author

The corresponding TD issue is w3c/wot-thing-description#1408.
I added the label "Needed by other TF"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for next iteration Planned or postponed topics for the future priority: high Issues that will be tackled in 2024 wait-for-td
Projects
None yet
Development

No branches or pull requests

4 participants