serverless / event-gateway

React to any event with serverless functions across clouds
https://www.serverless.com/event-gateway
Apache License 2.0
1.65k stars 97 forks source link

Implement plugin system #147

Closed mthenw closed 7 years ago

mthenw commented 7 years ago

The goal of plugins is to extend the behavior of the Event Gateway core. Examples include authentication, integration with external identity management systems, event validation systems, event persistence.

They should be implemented in any language as a local sidecar that adheres to the plugin calling interface. It listens on a local TCP socket for a nice mix of interoperability and performance.

zdne commented 7 years ago

@mthenw is currently any sort of the middleware functionality implemented?

xtuc commented 7 years ago

Just my two cents.

I think the TCP-based solution suffer from a few issues:

I would use an executable-based solution, which has the following advantages:

Or shared Unix sockets, basically same as the executable-based solution. The plugin author can expose a high-level API such as REST.

Note that you can still implement a TCP server on top of the executable-based solution.

Imagine you need a unique instance of one plugin across your cluster. While the TCP based solution is possible, it will suffer from all the issue we have in distributed systems. Ideally the plugin author shoudn't have to care about the system topology.

Since you'll need proper communication for your state within your cluster, I think the plugins should be part of that. I could imagine at least two master nodes in the cluster managing all the stateful plugins and making sure the information were correctly transmitted.

I'm curious to hear what you think about that approach.

mthenw commented 7 years ago

@zdne nothing is implemented yet. Though it's high in our backlog https://github.com/serverless/event-gateway/projects/2#card-4080295 so we should start implementing this pretty quickly. Could you write more about your use case or about your expectations from plugin system?

mthenw commented 7 years ago

@xtuc thanks for your input. My current thinking is that a plugin needs to run on the same host so there are no issues around unreliable networking. EG should be responsible for running plugin process so there is no need to run it in e.g. separate Docker container. Plugin same as EG instance has to be stateless. Communication could be done via some RPC (gRPC?). What do you think?

xtuc commented 7 years ago

I'm not a fan of the TCP socket for local communication only. There are still a few issues with the network and security (You could accidentally open the server to the outside. localhost could be resolved to another IP than the loopback :smile:. The network interface could be misconfigured. Etc). Do you absolutely need it to be through some network?

RPC/RMI frameworks are quite different in the format they use for communication. You cannot really take the reference RPC framework of your language and use it in the plugin system out of the box.

I forgot to mention it but with the executable-based solution you could talk over stdin/stdout. In that case I would use a JSON stream (JSON objects separated by new lines).

mthenw commented 7 years ago

Summary

Major use-cases:

Technical requirements:

Golang has its own plugin system but it forces to write plugin in golang and those plugins work only on Linux (no Windows support).

I think that the best solution is to use Hashicorp's plugins system for golang that they use in their products. A plugin is run by the gateway on the same instance. Plugin communicates via grpc on localhost (fast & reliable). In case of running EG in multiple containers, each instance has a copy of the plugin.

Benefits:

Implementation

Event Gateway needs to expose the following system events:

and allow plugin so subscribe to those events in two ways, blocking and non-blocking. Blocking/sync means that we need to get a response back to proceed, non-blocking/async means that plugin response is ignored.

Interface to implement by a plugin:

Model

PluginSubscription{
  Event string,
  Type SubscriptionType // can be Async Or Sync 
}

To enable plugin event-gateway needs to be run with new CLI param -plugin=<path to plugin>. This param can be used multiple times.