We're in the process of adding a mechanism to extend redis with more connection mediums (RDMA, io_uring), and the first step is to extract the TLS code outside of redis so that it can be loaded an an extension, see #9320.

The above PR is nearly complete (TLS can be compiled as an extension, but from all other aspects it behaves as it did before). However, that PR lacks a way for an extension to register configs (for things like certificates or other connection type specific configs / features). (to be clear, for TLS we kept the existing redis config for backwards compatibility, but for other mediums we need a different solution). So we would like to expose the module API for configs (#10285) to extensions too (and also a mechanism to inject INFO fields).

This could be done in at least 4 different ways: 1. In some way extract these interfaces to another header so that both modules and extensions can use them. 2. have the user register the extension as both an extension and as a module (it'll implement both interfaces, and the user will have to refer to it in two config lines) 3. Let extensions register themselves as modules too. The extension will call some API at startup and will become a registered module, but it'll be invisible to users, both in the config file, and also in INFO and elsewhere. 4. completely abandon the concept of extensions, and expose that capability for modules (i.e. modules that require connection.h and server.h, and must be compiled with a specific redis version, no ABI compatibility across versions).

I think we can immediately reject options 1 and 2 (I listed them here just to make a point). What we need to decide now is if extensions and modules are two different things, or maybe instead it's just two different types of modules (i.e. ones with ABI restriction and one without).

IMHO, two types of modules are more confusing than two different ways to extend redis, each with its own name, so I support option 3.

I'd like to state that both extensions and modules can be either first party (bundled with redis), or 3rd part (provided by someone else). i.e. if we some day include some first party module for authentication, auditing, or a new set of command or an extra data type, it'll still be a module that uses only the official module API. And the same with extension, someone can compile a 3rd party extension as part of redis (include server.h).

So to me, the key differences between the two (modules and extensions) is first, the ABI / version compatibility and including server.h, and secondly, the fact that extensions are likely to also replace some built in mechanism of redis. For instance, an extension could some day replace the LZF compression of redis with something else, or provide another way to write persistence (not to files). In these cases redis calls some interface the extension implements, which replaces something redis does and returns a value. unlike module hooks, in which multiple modules can register for a hook (to get notified), but they don't return a value or affect redis.

Comment From: madolson

I'm not really entirely sure I understand what is different between 1-4, but I like the idea of having extensions being a separate interface (such as just importing server.h) and letting them call the module APIs through a custom interface so that we can re-use a lot of the functionality we already built for modules.

I'm not sure we should even consider third-party extensions for the time being, since that implies that we will maintain them to some degree. They should primarily be used for first party extensions.

Comment From: oranagra

[1] means that extensions don't include redismodule.h, and we refactor the config interface we exposed to modules in a way we can expose it to extensions too.

[4] means that extensions don't include server.h, instead we extend the module interface to allow these capabilities (maybe under some ifdef that says these interfaces are not ABI compatible across versions).

from your comment i understand you support [3]. i agree we don't need to consider 3rd party extensions, but i know some will pop up (e.g. the RDMA one.. maybe as a fork of redis that just includes an additional file)

Comment From: madolson

Based on the last comment, I agree, I think I agree with option [3].

Comment From: oranagra

@pizhenwei can you look into it? either as part of #9320 or a followup PR.

Comment From: pizhenwei

Config machnism works as low level core, uplayer could use this directly, like current main config; or wrappering this like module config.

I did some changes in my local branch: - rename config.h to osdep.h - introduce config low level APIs into config.h - then extension could use config API to register configs into redis.

This works fine. is it possible to expose config low level API?

Comment From: oranagra

this will not allow extensions that are loaded dynamically (extension name provided in the config file), to register configs that will be read from the config file too (config file parsing already done). for this reason the modules have a mechanism for deferring config loading / apply, which is what i think we should use.

Comment From: pizhenwei

@pizhenwei can you look into it? either as part of #9320 or a followup PR.

Hi, @oranagra I prefer a followup PR because #9320 has no dependence on this(TLS extension still uses the old style bind/tls-port arguments). Do you have any other concern? And I volunteer this feature if this work does not yet get started ...

Comment From: oranagra

we can do that in a followup PR.. the reason 9320 does have some dependence on this is not that it needs this API, but the fact it introduces a concept of extensions, and here (in this issue), we try to decide if extensions and modules are two different things or maybe extensions are a type of module. so it would be nice to know that what we concluded we wanna do, actually works before we merge the other PR. But anyway, i assume we won't discover anything dramatic that will make that plan invalid, so let's proceed with a separate PR.

I see we didn't get any other comments in the past 5 days since this was discussed in a core-team meeting. @yossigo do you think we can proceed and merge #9320 ?

Comment From: oranagra

we discussed this in a core-team meeting and decided that we rather have just one way to extend redis (modules). This means that TLS and other connection extensions will be loaded with the loadmodule config file directive, and get listed in MODULE LIST, etc. but they could have a way to tell redis (maybe not via a module api), that they're only meant to be loaded on startup (so it'll refuse loading them on runtime or unloading them). and maybe they could also include version.h and release.h, and match that info against the redis being used to load them (to make sure no one tries to load a non-abi compatible module with a different version).

@pizhenwei please try to figure out how to proceed. i suppose there are several options: 1. replace the extensions mechanism in your PR with the one described above. 2. remove the extensions mechanism from that PR to be added in another PR (before or after that one). 3. replace it with a simplified version in your PR (so these are modules instead of extensions), in a way that the other fancy features mentioned above can be added later.

WDYT?

Comment From: pizhenwei

we discussed this in a core-team meeting and decided that we rather have just one way to extend redis (modules). This means that TLS and other connection extensions will be loaded with the loadmodule config file directive, and get listed in MODULE LIST, etc. but they could have a way to tell redis (maybe not via a module api), that they're only meant to be loaded on startup (so it'll refuse loading them on runtime or unloading them). and maybe they could also include version.h and release.h, and match that info against the redis being used to load them (to make sure no one tries to load a non-abi compatible module with a different version).

@pizhenwei please try to figure out how to proceed. i suppose there are several options:

  1. replace the extensions mechanism in your PR with the one described above.
  2. remove the extensions mechanism from that PR to be added in another PR (before or after that one).
  3. replace it with a simplified version in your PR (so these are modules instead of extensions), in a way that the other fancy features mentioned above can be added later.

WDYT?

Hi, @oranagra I prefer option 1, I'll try to implement the full feature in the single PR. If something unexpected occurs during developing, I'll ask help here! Thanks!