Introduce 'couch_epi:register_service/1'

COUCHDB-2796
diff --git a/src/couch_epi.erl b/src/couch_epi.erl
index 417b3fc..7bd4ea1 100644
--- a/src/couch_epi.erl
+++ b/src/couch_epi.erl
@@ -14,6 +14,7 @@
 
 %% subscribtion management
 -export([subscribe/5, unsubscribe/1, get_handle/1]).
+-export([register_service/1]).
 
 %% queries and introspection
 -export([
@@ -164,3 +165,16 @@
 
 is_configured(Handle, Function, Arity) ->
     [] /= couch_epi_functions_gen:modules(Handle, Function, Arity).
+
+
+-spec register_service({ServiceId :: service_id(), Key :: key()}) -> ok;
+                (ServiceId :: service_id()) -> ok.
+
+register_service({_ServiceId, _Key} = EPIKey) ->
+    register_service(couch_epi_data_gen, EPIKey);
+register_service(ServiceId) when is_atom(ServiceId) ->
+    register_service(couch_epi_functions_gen, ServiceId).
+
+register_service(Codegen, Key) ->
+    Handle = Codegen:get_handle(Key),
+    couch_epi_module_keeper:register_service(Codegen, Handle).
diff --git a/src/couch_epi_data_gen.erl b/src/couch_epi_data_gen.erl
index e4e0889..ad84b80 100644
--- a/src/couch_epi_data_gen.erl
+++ b/src/couch_epi_data_gen.erl
@@ -185,6 +185,11 @@
             throw({Class, {Source, Reason}})
     end.
 
+save(Handle, undefined, []) ->
+    case get_current_data(Handle) of
+        [] -> generate(Handle, []);
+        _Else -> ok
+    end;
 save(Handle, Source, Data) ->
     CurrentData = get_current_data(Handle),
     NewDefs = lists:keystore(Source, 1, CurrentData, {Source, Data}),
diff --git a/src/couch_epi_functions_gen.erl b/src/couch_epi_functions_gen.erl
index 84ecc5f..2fba66f 100644
--- a/src/couch_epi_functions_gen.erl
+++ b/src/couch_epi_functions_gen.erl
@@ -201,6 +201,11 @@
             throw({Class, {Source, Reason}})
     end.
 
+save(Handle, undefined, []) ->
+    case get_current_definitions(Handle) of
+        [] -> generate(Handle, []);
+        _Else -> ok
+    end;
 save(Handle, Source, Modules) ->
     CurrentDefs = get_current_definitions(Handle),
     Definitions = definitions(Source, Modules),
diff --git a/src/couch_epi_module_keeper.erl b/src/couch_epi_module_keeper.erl
index f538cf5..2d8c439 100644
--- a/src/couch_epi_module_keeper.erl
+++ b/src/couch_epi_module_keeper.erl
@@ -19,6 +19,8 @@
 %% ------------------------------------------------------------------
 
 -export([maybe_start_keeper/2]).
+-export([register_service/2]).
+
 -export([start_link/2, save/3]).
 -export([stop/1]).
 
@@ -35,8 +37,17 @@
 %% API Function Definitions
 %% ------------------------------------------------------------------
 
+register_service(Codegen, Module) ->
+    {ok, Server} = maybe_start_keeper(Codegen, Module),
+    compile_dummy_module(Server).
+
 maybe_start_keeper(Codegen, Module) ->
-    catch couch_epi_keeper_sup:start_child(Codegen, Module).
+    case couch_epi_keeper_sup:start_child(Codegen, Module) of
+        {ok, Pid} ->
+            {ok, Pid};
+        {error, {already_started, Pid}} ->
+            {ok, Pid}
+    end.
 
 start_link(Codegen, Module) ->
     gen_server:start_link({local, Module}, ?MODULE, [Codegen, Module], []).
@@ -76,3 +87,6 @@
 %% ------------------------------------------------------------------
 %% Internal Function Definitions
 %% ------------------------------------------------------------------
+
+compile_dummy_module(Server) ->
+    save(Server, undefined, []).
diff --git a/test/couch_epi_tests.erl b/test/couch_epi_tests.erl
index 78eab4d..a43ade9 100644
--- a/test/couch_epi_tests.erl
+++ b/test/couch_epi_tests.erl
@@ -91,6 +91,7 @@
         test_app, {epi_key, Key}, {file, File}, [{interval, 100}]),
     ok = couch_epi_data_source:wait(Pid),
     KV = state_storage(),
+    ok = couch_epi:register_service(Key),
     #ctx{
         file = File,
         key = Key,
@@ -108,6 +109,7 @@
         test_app, {epi_key, Key}, provider, []),
     ok = couch_epi_data:wait(Pid),
     KV = state_storage(),
+    ok = couch_epi:register_service(Key),
     #ctx{
         key = Key,
         handle = couch_epi:get_handle(Key),
@@ -126,6 +128,7 @@
         [{interval, 100}]),
     ok = couch_epi_functions:wait(Pid),
     KV = state_storage(),
+    ok = couch_epi:register_service(Key),
     #ctx{
         key = Key,
         handle = couch_epi:get_handle(Key),