-
Notifications
You must be signed in to change notification settings - Fork 261
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
Feature: CloudEvents component #394
Comments
Thanks a lot for yesterday's presentation, @Mossaka! ref #398 After going through the CloudEvents core spec, Responding to HTTP webhooksThe CloudEvents HTTP webhook specification In this scenario, the producer sends a valid HTTP request with a CloudEvents In handling the incoming request, a handler component can use external services #[http_component]
pub fn handle_ce(req: Request) -> Result<Response> {
// perform the spec endpoint validation for abuse protection
// https://github.com/cloudevents/spec/blob/main/cloudevents/http-webhook.md#4-abuse-protection
match req.method {
http::Method::OPTIONS => return spin_sdk::validate_webhook(req),
_ => {}
};
// read the CloudEvents request event from the HTTP request
let request_event = Event::try_from(req)?;
// create a CloudEvents response event
let response_event = Event::new(...);
...
// potentially use other external services here
...
// return the HTTP response
Ok(http::Response::builder()
.status(200)
// optionally add other headers
.body(Some(response_event.into()))?)
} How would we feel about something like the component above? This way, we would follow the HTTP webhook specification (returning an HTTP A CloudEvents subscription managerThe above implementation for HTTP webhooks is great, and it requires minimal Of particular importance could be the Subscriptions API. Specifically, Spin could act as a "subscription manager" In this scenario, we would build a specific CloudEvents executor: // The entry point for a CloudEvents handler.
handle-cloudevent: function(event: event) -> expected<event, error> This executor would be entirely independent of a specific Spin trigger. Rather, This is a CloudEvents Subscription: {
"id": "[a subscription manager scoped unique string]",
"source": "[...]", ?
"types": "[ "[ce-type values]" + ]", ?
"config": { ?
"[key]": [subscription manager specific value], *
},
"filters": [ ?
{ "[dialect name]": [dialect specific object] } +
],
"sink": "[URI to where events are delivered]",
"protocol": "[delivery protocol]",
"protocolsettings": { ?
"[key]": "[type]", *
}
} The
For example, this event subscription defines that after execution, the result {
"id": "sub-193-18365",
"config": {
"data": "hello",
"interval": 5
},
"filters": [
{ "prefix": { "type": "com.example." } }
],
"protocol": "HTTP",
"protocolsettings": {
"method": "POST"
},
"sink": "http://example.com/event-processor"
} So the proposed executor would invoke the Initially, we would implement a subset of the potential protocols. The concepts of the Subscription API, the sink address, and the underlying These are some initial, unstructured thoughts about CloudEvents support. |
A custom executor is one way to approach this, and provides a very immediate solution that we already know well how to do. However, at the moment executors are very intimately linked to triggers. You don't want the HTTP, MQTT, Kafka and NATS triggers to all have to carry around cloud events code. And it would be nice if protocol/product owners could add executors for their own application protocols without needing to touch trigger repos. Obviously we could reorganise things so that executors rather than triggers are the 'units' but we'd need to figure out how one HTTP base could serve multiple executors. But I wonder if it's worth exploring an alternative approach that allows protocol bindings to be built and injected separately from transports/triggers. In a world like .NET or Java we could do this by dynamically loading code, but that's hard to do in Rust. One possibility is to do the binding guest side, via a linked component. This would have an additional benefit that transport-protocol bindings could be written in any language that compiled to Wasm. I'm thinking the idea would be something like:
I haven't thought this through to be clear! Just sharing it for discussion. (Already, thinking about it, we could use the executor setting as the hypothetical magic setting to use a binder, and then the user wouldn't have to care if the binder was internal-Rust or external-Wasm.) |
@radu-matei Thanks for your thoguhts and this is an amazing writing!
For the Webhook use case, I can definitely see the value of reusing the Spin HTTP component to handle the events. I had a working example in spin-kitchensink pr that implements the webhook abuse protection mechanism. I agree that if we can offload the logic of parsing HTTP headers, match header attributes and handle callbacks in the Spin SDK, it will be a much better user experience. I would argue that if eventually a CloudEvents trigger like #[cloudevents_component]
pub fn handle_ce(in: Event) -> Result<Event> {
// before the function is called, the validation HTTP request is handled
// and Spin serializes HTTP request to CloudEvents
// potentially use other external services here
...
// return the event
Ok(in)
} The CloudEvents component will automatically deserialize CloudEvents return value back to HTTP response and return back. The benefits of doing this is that
I really like the subscription spec. In fact, there are three next-gen specficiations for CloudEvents, and I think they work together in an amazing way.
Totally agree! This could unlock the ability to easily chain multiple Spin applications together in a serverless manner. Imagine 2 Spin application running on the cloud, and one's sink is an adress of another Spin application. This creates a pipeline of handling workloads to wasm modules. Check out the CloudEvents extensions, which could be very useful in this scenario:
This worth a few SIP proposals to fully spec out. I am happy to help bringing CloudEvents support to Spin! |
See an disussion here on the use cases of CloudEvents subscription spec: cloudevents/spec#767 |
Enabling CloudEvents component could make spin a great solution to serverless and event-driven applications. I am thinking about an event trigger that subscribes to a addressible broker, and whenever the broker emits an event, the event trigger will instantiate a wasm module to hanlde. Or the trigger itself can emits an event.
For example the trigger can subscribe to a knative event source.
I am proposing the following component sdk. Let me know your thoughts. @radu-matei
The text was updated successfully, but these errors were encountered: