couch_epi
is extensible plugin interface (EPI) for couchdb.
Service
's APIProvider
{service_id :: atom(), key :: term()}
- for couch_epi_data_source
service_id :: atom()
- for couch_epi_functions
couch_epi:get_handle(EpiKey)
We monitor the modules involved in configuration of the service/provider so we get notified when there is a code upgrade. We use this notification in order to:
Call to notify/3 would be called for both providers and data_providers.
Any application that wants to register some configuration data for a service using module could add an entry in its implementation of couch_epi_plugin behaviour:
data_providers() -> [ {{couch_stats, descriptions}, {priv_file, "stats_descriptions.cfg"}, [{interval, 5000}]} {{couch_stats, descriptions}, {file, "/tmp/extra_stats.cfg"}, [{interval, 5000}]}, {{couch_stats, descriptions}, {static_module, my_stats}}, {{couch_stats, descriptions}, {callback_module, my_stats}} ].
When service provider wants to learn about all the installed config data for it to use it would then just do something like:
couch_epi:get(Handle, Service, Key)
The service provider also has to mention the data keys it is using in its implementation of couch_epi_plugin behaviour
data_subscriptions() -> [{couch_stats, descriptions}].
There are also additional functions to get the same data in various formats
couch_epi:all(Handle)
- returns config data for all services for a given handlecouch_epi:get(Handle, Subscriber)
- returns config data for a given subscribercouch_epi:get_value(Handle, Subscriber, Key)
- returns config data for a given subscriber and keycouch_epi:by_key(Handle, Key)
- returns config data for a given keycouch_epi:by_key(Handle)
- returns config data grouped by keycouch_epi:by_source(Handle)
- returns config data grouped by source (subscriber)couch_epi:keys(Handle)
- returns list of configured keyscouch_epi:subscribers(Handle)
- return list of known subscribersThe difference between static_module
and callback_module
providers is in how couch_epi detects the changes. static_module
is designed for the cases when you have your data hardcoded in the module. For example you might have the following:
-export([data/0]). data() -> [ {[complex, key, 2], [ {type, counter}, {desc, bar} ]}, {[complex, key, 1], [ {type, counter}, {desc, updated_foo} ]} ].
The changes are detected by relying on vsn
module attribute. Therefore we would notice the change only when data source module is recompiled.
The callback_module
provider uses the return value from data/0
to detect changes and it is useful for cases when the data term is constructed dynamically. For example to cache values of CouchDB config one could use the following:
-export([data/0]). data() -> config:get("dreyfus").
Any application that wants to register implementation functions for a service could add the following into it's implementation of couch_epi_plugin behaviour:
providers() -> [{my_service, module_which_implements_the_functions}].
Adding the entry would generate a dispatch methods for any exported function of modules passed.
Services have to be defined in one of the implementations of couch_epi_plugin behaviour as:
services() -> [{my_service, module_to_monitor_for_codechange}].
When app wants to dispatch the call to all service providers it calls
couch_epi:apply(Handle, ServiceId, Function, Args, Opts)
There are multiple ways of doing the apply which is controlled by Opts
Notes:
concurrent
is incompatible with pipe
There are cases when we want to call configured providers until any of them would make a decision. We also would want to be able to find out if any decision has been made so we could call default handler. In order to be able to do so there is couch_epi:decide/5. Every service which uses this feature would get either:
The provider module should return one of the above results. The current logic is to call all configured providers in order of their definition until we get {decided, term()}
. If none of the providers would return this term we would return no_decision
.
The module implementing this behaviour needs to export the following functions: