postgresml / pgcat

PostgreSQL pooler with sharding, load balancing and failover support.
MIT License
2.69k stars 160 forks source link

[RFC] Plugins #437

Open levkk opened 1 year ago

levkk commented 1 year ago

I've been playing around with the idea of "plugins", extendible "things" we can inject at any point in the client/server lifecycle to do stuff. A few ideas I've prototyped so far:

These are not prescriptive in any way, and only serve to illustrate the use case behind plugins. PgBouncer had a patch that allowed query rewriting 1, we could introduce that as a plugin as well.

Another interesting discussion topic is how to load/configure these plugins. The way it's done now is plugins are part of the code and are turned on and configured via pgcat.toml. This is not really a plugin system though, since real plugins have to extend the existing code base & be completely optional. Another use case is for projects to add functionality to pgcat that they may not want open sourced (yet, or ever) without having to fork. A plugin could be a great way for someone to introduce a functionality that's specific to their organization/project and dynamically load it, without worrying about maintaining a fork and git conflicts down the line.

What would be great to get out of this RFC is:

liaden commented 1 year ago

A plugin could be a great way for someone to introduce a functionality that's specific to their organization/project and dynamically load it, without worrying about maintaining a fork and git conflicts down the line.

Definitely. Ignoring git conflicts and being able to extend pgcat would be a nice feature relative to other postgres poolers. I wonder if it could be useful way to inject functionality between postgrest and postgres.

My preferred dev experience for writing a plugin:

  1. Create a rust project.
  2. Add pgcat to it as a dependency.
  3. Use a macro from pgcat to construct the main function.
  4. Write my plugin(s).
  5. Add another plugin crate as a dependency to include 3rd party plugins.
  6. Compile the binary.
  7. Ship the binary + config to use.

Some considerations:

Some possibly useful plugins:

There are probably other plugins that would be useful for various postgres forks like TimescaleDB?

calcsam commented 12 months ago

This is awesome. I personally need to intercept writes and validate them with a remote API, and writing a plugin will be much simpler than maintaining a fork.

If I was in your shoes I wouldn't worry about needing to ship a complete lifecycle API out of the gate. You can start with whichever hook you think there's the most need for, especially if you're confident what the API for it should look like.

calcsam commented 12 months ago

Another validation one. I asked a friend who was the CTO of an analytics startup. They stored event data as JSON blobs in Postgres, with some fields as implicit foreign key relationships, but they didn't have a way for the DB to enforce that the IDs being referenced exists in the relevant tables.

adriangb commented 5 months ago

Plugins would be great. Personally I'd be fine making a rust project and adding pgcat as a dependency if pgcat provided a nice way of "insert your code here via callbacks" but still managed everything else so all I have to do is write a couple Rust functions and build the binary. Some use cases I've had are remap usernames/passwords, do more advanced/custom query parsing and rewriting (possibly returning errors, eg. to prohibit EXECUTE), do custom mapping of incoming connections to destination servers.