-
Notifications
You must be signed in to change notification settings - Fork 5
Conversation
Having given it a quick glance, I think we should store a bit more metadata with the capabilities, mainly adding the type of the capability. Basically storing this in a JSON like: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very cool! Few inline comments plus probably could use a merge from master.
src/utils/db/sql.ts
Outdated
await server.db.createPluginLogEntry( | ||
pluginConfig, | ||
PluginLogEntrySource.System, | ||
PluginLogEntryType.Info, | ||
`Set plugin capabilities (instance ID ${server.instanceId}).`, | ||
server.instanceId | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if the capabilities haven't changed, there's no need to update them nor log that we set them. That would be needless logspam :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH I don't believe these logs are valuable user-side at all. Plugin loaded/unloaded events can be important because of plugin setup/teardown methods – while capabilities
are just an internal optimization of ours.
src/worker/plugins/loadPlugin.ts
Outdated
// infer on load implies there's no lazy loading, but all workers get | ||
// these properties loaded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could lazy load them. We won't do anything with the loaded capabilities for the moment, and eventually set them in a separate "install" step anyway. No need to block for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I could unblock them, but that still doesn't mean the VMs are lazy loaded right? since inferPluginCapabilities()
will load the VM on startup, before the worker gets any event.
Maybe I should just remove this comment, just realised it's confusing w.r.t what is being lazy loaded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The funny code here is this:
void pluginConfig.vm?.initialize!(server, pluginConfig, plugin.source, pluginDigest(plugin))
await inferPluginCapabilities(server, pluginConfig, prevConfig)
The first function is run in the background, the second one we await for. The second function awaits for a promise (resolveInternalVm
) that gets set when the first function that's running in the background finishes.
In essence, the plugin is not lazy anymore, but we block until the VM setup has completed.
To get around it, we could just void
the inferPluginCapabilities
call and let them run in the background, however that also feels slightly hacky.
A possibly better idea is to put this inferPluginCapabilities
inside the LazyVM.initialize
function. There you probably won't need prevConfig
either. Just check if the current pluginConfig.plugin.capabilities
matches reality or not. If not, update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that.. makes a lot of sense. Ha, would've been nice if I made this leap myself when thinking about the implementation.
Come to think of it, I don't need the prevConfig
in the current setup either, for similar reasons - I already have a pluginConfig.plugin.capabilities
to check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few more flyby comments and suggestions :)
src/worker/plugins/loadPlugin.ts
Outdated
await setPluginCapabilities(server, pluginConfig, capabilities) | ||
} | ||
|
||
pluginConfig.plugin!.capabilities = capabilities |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here again the !
could cause subtle issues. After all, we're not sure this function will always be called with pluginConfigs that contain a plugin. It might be the case when we follow the current trail that leads to this function, but it might not be the case in the future.
Often the solution is to use a guard, such as if (!pluginConfig.plugin) { throw new Error('how the hell did you get here?') }
, or just return
, depends on the case. Guards are best placed at the top of a function as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Just some minor comments
src/utils/db/sql.ts
Outdated
await server.db.createPluginLogEntry( | ||
pluginConfig, | ||
PluginLogEntrySource.System, | ||
PluginLogEntryType.Info, | ||
`Set plugin capabilities (instance ID ${server.instanceId}).`, | ||
server.instanceId | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH I don't believe these logs are valuable user-side at all. Plugin loaded/unloaded events can be important because of plugin setup/teardown methods – while capabilities
are just an internal optimization of ours.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stamp of approval
expect(pluginConfig.plugin!.capabilities!.methods!.sort()).toEqual([ | ||
'onSnapshot', | ||
'processEvent', | ||
'processEventBatch', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems a bit quirky that processEventBatch
is listed as a capability when it's only an autogenerated version based on actually provided processEvent
, but that seems OK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still some inline comments to check :)
src/worker/plugins/loadPlugin.ts
Outdated
// infer on load implies there's no lazy loading, but all workers get | ||
// these properties loaded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The funny code here is this:
void pluginConfig.vm?.initialize!(server, pluginConfig, plugin.source, pluginDigest(plugin))
await inferPluginCapabilities(server, pluginConfig, prevConfig)
The first function is run in the background, the second one we await for. The second function awaits for a promise (resolveInternalVm
) that gets set when the first function that's running in the background finishes.
In essence, the plugin is not lazy anymore, but we block until the VM setup has completed.
To get around it, we could just void
the inferPluginCapabilities
call and let them run in the background, however that also feels slightly hacky.
A possibly better idea is to put this inferPluginCapabilities
inside the LazyVM.initialize
function. There you probably won't need prevConfig
either. Just check if the current pluginConfig.plugin.capabilities
matches reality or not. If not, update.
tests/plugins.test.ts
Outdated
await setupPlugins(mockServer) | ||
const newPluginConfig = mockServer.pluginConfigs.get(39)! | ||
|
||
expect(newPluginConfig.plugin!.capabilities).toBe(pluginConfig.plugin!.capabilities) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also check that:
expect(newPluginConfig.plugin).not.toBe(pluginConfig.plugin)
otherwise the capabilities are the same because it's literally the same object :)
@@ -38,7 +39,7 @@ afterEach(async () => { | |||
}) | |||
|
|||
test('setupPlugins and runProcessEvent', async () => { | |||
getPluginRows.mockReturnValueOnce([plugin60]) | |||
getPluginRows.mockReturnValueOnce([{ ...plugin60 }]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it took me more than an hour on Friday night to figure out this was the issue with tests! :/ (since it affected plugin60 directly, and wouldn't show up if I simply ran the tests in isolation) - only when things run in sequence did this bork things up. 🤦 .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooh... that's a nice rabbit hole :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
…rver#384) * add tests for plugin capabilities * address comments, update tests * clean up * update capabilities type definition
Changes
Adds support for Plugins Capabilities. Resolves #379
Companion PostHog/posthog PR (PostHog/posthog#4371) to be merged first.
Will write tests now, but just wanted to get a PoC out.Checklist