Skip to content

JS expressions in Trigger spec#3783

Closed
slinkydeveloper wants to merge 4 commits intoknative:masterfrom
slinkydeveloper:el_spec
Closed

JS expressions in Trigger spec#3783
slinkydeveloper wants to merge 4 commits intoknative:masterfrom
slinkydeveloper:el_spec

Conversation

@slinkydeveloper
Copy link
Contributor

@slinkydeveloper slinkydeveloper commented Aug 5, 2020

Signed-off-by: Francesco Guardiani francescoguard@gmail.com

Reflects the work done in #3771 in the broker trigger spec. For more details, look at #3771

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
@googlebot googlebot added the cla: yes Indicates the PR's author has signed the CLA. label Aug 5, 2020
@knative-prow-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: slinkydeveloper

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@knative-prow-robot knative-prow-robot added size/S Denotes a PR that changes 10-29 lines, ignoring generated files. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Aug 5, 2020

#### Event filters

Implementations of Trigger MUST support both attributes filter and expression
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens when both are given?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote that at the end of this paragraph, the trigger MUST do an and of both results. Do you propose to rephrase it?

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
Trigger. Events that pass the attributes filter MUST include context or
extension attributes that match all key-value pairs exactly.

The expression filter specifying a Javascript expression MUST be supported by
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give a couple examples of javascript expressions? I am not familiar with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in the doc

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
@knative-prow-robot knative-prow-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Aug 5, 2020

#### Event filters

Implementations of Trigger MUST support both attributes filter and jsExpression
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather use Rego. https://www.openpolicyagent.org/docs/v0.11.0/language-reference/

It is designed to do this kind of filtering and they have a cross-compiler to web assembly that is stupid fast for filter functions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc: @grantr

Copy link
Contributor Author

@slinkydeveloper slinkydeveloper Aug 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is designed to do this kind of filtering and they have a cross-compiler to web assembly that is stupid fast for filter functions.

That's not easy as it seems, I've looked into it: you need a wasm engine, then you need to implement this ABI https://www.openpolicyagent.org/docs/latest/wasm/#exports, then you need to bring the event into the wasm context (which requires a serde step). JS is far easier to integrate and easier also for the users to look at it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then rego brings the non-trivial problem that you need to compile the expressions in wasm modules, invoking the rego compiler, and store them somewhere

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is less trivial than embedding a javascript interpreter, and for this to be able to be well understood we need to define or point to a spec of everything you can do in a jsExpression similar to how Rego lists out all the language features.

Plus we don't need to implement rego, we pull OPA in as a sidecar as one impl.

Copy link
Contributor Author

@slinkydeveloper slinkydeveloper Aug 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is less trivial than embedding a javascript interpreter

Look at the code, it's one file of 100 lines of code 😄 And i'm pretty sure it's the very same amount of locs you need in Java to embed a js engine, in rust and so on... All the code to integrate the engine consists in making the event available from the filter code through the engine, then everything else is covered by the js engine itself. Any sidecar solution requires far more, both on sidecar and on filter code + all complexity of configs and tests too. And another point to consider is that this proposal doesn't prevent to have in future rego too.

we need to define or point to a spec of everything you can do in a jsExpression

Not really, I was wondering that all we should say here is: the js engine MUST support EcmaScript 5.1 (which is a requirement every js engine out there supports today) and should serve cloudevent as event (and i think i already covered that part). Maybe we should be more specific on the type coercion between cloudevents types and js types, but overall that's all i think we need here, we don't need to specify all the things you can do in JS

Plus we don't need to implement rego, we pull OPA in as a sidecar as one impl.

That adds quite some overhead to the filtering process and complexity too... I prefer to have something simple that I can embed straight in my code, other solutions that requires some external process are more complex to implement and most notably adds overhead for serializing/deserializing and IPC.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced on the "MUST support both attributes filter and jsExpression".

I actually like the filter dialects the CloudSubscriptions spec talks about. See https://github.com/cloudevents/spec/blob/master/subscriptions-api.md#323-filter-dialects.
The MUST is to support a basic one (Exact, Prefix and Suffix match).
More advanced dialects can be made optional. I can easily see JS being an optional advanced dialect. Maybe REGO, CEL, or whatever, other ones, and so on...

Overall, I think you will be able to reduce contention if you decouple Trigger from a mandatory JS "dialect", and just frame the problem as Trigger with optional dialects... I think conversations will move forward faster, and we will also be more aligned with the Serverless WG (which in general I think is a good thing).

Copy link
Contributor Author

@slinkydeveloper slinkydeveloper Aug 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH I wasn't aware of these filter dialects from subscriptions spec. Still they don't seem to cover basic nested logic and operations on types (in this doc i explain what a user should be able to express https://docs.google.com/document/d/1Pz2vaLWKUrMQDLNyDW7ksjgLG4GAxBY546dT7_jF5Rk/edit?usp=sharing)

My take on optional and mandatory is that, I have no strong opinion if vendors wants to add their filtering capabilities to their system, but IMHO eventing vanilla should be bundled with a filtering capability that covers a 90% of basic use cases. Not providing a "good enough" bundled filtering capability will make too big the divergence between different implementations (basically, if a user wants to port trigger a to another vendor, he needs to rewrite all the filtering logic...)

JS "dialect"

I hardly name it a JS dialect: In the spec here i'm just stating that the expression is ECMAScript 5.1+ and you access to event using event.attrx, I was very careful to avoid defining something that cannot trivially implemented with an already existing js engine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather look at what is missing in the subscription spec and upstream changes and take what is there for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

crazy thought... what if you proposed a javascript dialect to the spec https://github.com/cloudevents/spec/blob/master/subscriptions-api.md#323-filter-dialects

@slinkydeveloper
Copy link
Contributor Author

/retest

1 similar comment
@slinkydeveloper
Copy link
Contributor Author

/retest

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
@slinkydeveloper
Copy link
Contributor Author

/retest

@knative-test-reporter-robot

The following jobs failed:

Test name Triggers Retries
pull-knative-eventing-integration-tests 0/3

Failed non-flaky tests preventing automatic retry of pull-knative-eventing-integration-tests:

test/e2e.TestApiServerSourceV1Alpha2EventTypes

@slinkydeveloper
Copy link
Contributor Author

/retest

@matzew
Copy link
Member

matzew commented Aug 7, 2020

Why do we not want to ship an engine?

I think this is would be a good message if eventing comes with one engine, and not w/ some "crap" that is

  • overriden by every vendor
  • and there has a different syntax

I see zero values on that approach.

So, why against one engine?

That said:

Overall, I think you will be able to reduce contention if you decouple Trigger from a mandatory JS "dialect", and just frame the problem as Trigger with optional dialects... I think conversations will move forward faster, and we will also be more aligned with the Serverless WG (which in general I think is a good thing).

I get this point too -

@matzew
Copy link
Member

matzew commented Aug 7, 2020

I think if there is NO unique API, this would be bad.

I don't really see, why we can not ship this

@n3wscott
Copy link
Contributor

My issue with adding this is eventing should be some common denominator that can be projected into other systems that implement this, and @nachocano has a very good point with the subscription dialects from CloudEvents Subscription Spec. Being spec based means our adoption of an implementation is portable. At the very least we should aim to be directly translatable into the CloudEvents subscription spec and dialects. If they need more dialects, we can propose more, or have our own...

@slinkydeveloper
Copy link
Contributor Author

slinkydeveloper commented Aug 11, 2020

@n3wscott I think we can implement the filtering in the CloudEvents Subscription spec too and even if we plan to expand it, it's still a long road ahead to reach the capabilities of JS or any other expression language. And the CloudEvents Subscription filter might be just another filter capabilities (like our attributes)

@ruromero
Copy link

I think one common use case would be to avoid loopback events in generic services, for example I want to subscribe to any event except the ones my service generates (i.e. ce-source is my-generic-service). That doesn't seem possible with CloudEvents Subscriptions ATM.

filter:
  - type: not
    attribute: source
    value: org.example.service:myservice

or using jsExpressions

filter:
  jsExpression: "source !== 'org.example.service:myservice'"

@github-actions
Copy link

This Pull Request is stale because it has been open for 90 days with
no activity. It will automatically close after 30 more days of
inactivity. Reopen with /reopen. Mark as fresh by adding the
comment /remove-lifecycle stale.

@github-actions github-actions bot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Dec 24, 2020
@slinkydeveloper
Copy link
Contributor Author

Closed as explained here: #3771 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cla: yes Indicates the PR's author has signed the CLA. lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants