Skip to content

Plugins

Plugins let you extend VirtualDB without modifying it. A plugin is any standalone executable that connects to VirtualDB over a Unix socket and communicates using JSON-RPC 2.0. It can intercept queries, transform rows, observe events, and emit its own events — all from outside the VirtualDB process.

How plugins work

When vdb-mysql starts, it scans the directory at VDB_PLUGIN_DIR for plugin subdirectories, launches each plugin as a child process, and waits for it to connect and declare what it wants to do. The plugin registers its pipeline handlers and event subscriptions in a single declare call, then stays connected and running for the lifetime of the server.

VirtualDB calls the plugin whenever a pipeline point it registered is reached. The plugin receives the current payload, can modify it, and returns the updated payload. Writes are applied, queries are rewritten — the plugin's response drives what happens next.

Events work differently: they're fire-and-forget notifications delivered after something has already happened. A plugin subscribes to events to observe state changes without blocking the request path.

Directory layout

/etc/vdb/plugins/
  my-plugin/
    manifest.json
    my-plugin          ← the plugin executable

Set VDB_PLUGIN_DIR=/etc/vdb/plugins and VirtualDB will find and launch my-plugin automatically.

Manifest

Each plugin subdirectory must contain a manifest.json, manifest.yaml, or manifest.yml file.

json
{
  "name": "my-plugin",
  "version": "1.0.0",
  "command": ["./my-plugin"],
  "env": {
    "MY_PLUGIN_API_KEY": "..."
  }
}
FieldRequiredDescription
commandYesCommand and arguments to launch the plugin. The working directory is set to the plugin's subdirectory.
nameNoIdentifier used in logs. Defaults to the subdirectory name.
versionNoInformational. Printed at startup.
envNoAdditional environment variables passed to the plugin process.

Startup handshake

Once launched, the plugin receives the Unix socket path in the VDB_SOCKET environment variable. It must connect to that socket and send a declare notification within 10 seconds. Plugins that miss the deadline are logged and skipped — the server continues without them.

The declare notification tells VirtualDB which pipeline points the plugin handles and which events it wants to receive:

json
{
  "jsonrpc": "2.0",
  "method": "declare",
  "params": {
    "plugin_id": "my-plugin",
    "pipeline_handlers": [
      { "point": "vdb.records.source.transform", "priority": 15 }
    ],
    "event_subscriptions": [
      "vdb.query.completed"
    ],
    "event_declarations": [
      "my-plugin.row.flagged"
    ],
    "pipeline_declarations": []
  }
}
  • pipeline_handlers — the pipeline points the plugin handles, each with a numeric priority. Lower numbers run first.
  • event_subscriptions — events delivered to the plugin as notifications (no response expected).
  • event_declarations — events the plugin will emit. Must be declared upfront.
  • pipeline_declarations — custom pipelines the plugin owns, which other plugins can attach to.

Handling pipeline points

For each registered pipeline point, VirtualDB sends a synchronous handle_pipeline_point request. The plugin's response replaces the current payload and the pipeline continues.

json
{
  "jsonrpc": "2.0",
  "method": "handle_pipeline_point",
  "id": 1,
  "params": {
    "point": "vdb.records.source.transform",
    "payload": { "..." }
  }
}

The plugin responds with the (optionally modified) payload:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": { "payload": { "..." } }
}

If the plugin returns an error, the pipeline stops and the error is sent to the client as a SQL error.

Receiving events

Events arrive as handle_event notifications — no response is expected.

json
{
  "jsonrpc": "2.0",
  "method": "handle_event",
  "params": {
    "event": "vdb.query.completed",
    "payload": { "..." }
  }
}

Emitting events

A plugin can emit any event it declared in its declare notification using emit_event:

json
{
  "jsonrpc": "2.0",
  "method": "emit_event",
  "id": 1,
  "params": {
    "event": "my-plugin.row.flagged",
    "payload": { "..." }
  }
}

VirtualDB acknowledges with an empty result and forwards the event to all subscribers.

Shutdown

When vdb-mysql shuts down, it sends a shutdown request to each plugin. The plugin must send a JSON-RPC response to acknowledge it, then clean up and exit. VirtualDB waits up to 10 seconds for the acknowledgement — if no response arrives, the process is killed. After the response, VirtualDB waits a further 10 seconds for the process to exit before sending SIGKILL.

json
{
  "jsonrpc": "2.0",
  "method": "shutdown",
  "id": 42,
  "params": {}
}

Plugin priorities and the delta overlay

When registering a handler at vdb.records.source.transform, the priority you choose matters:

  • Priority < 10 — your plugin sees raw rows from the source, before the delta overlay is applied.
  • Priority > 10 — your plugin sees post-overlay rows, which already reflect any writes the application has made.

The delta overlay itself is the built-in handler at priority 10.

Error handling

  • If a plugin exits unexpectedly, VirtualDB logs it and continues running without that plugin. There is no automatic restart.
  • Event handler errors are logged but do not affect other subscribers or the request path.

Further reading

Released under the Elastic License 2.0.