Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide different implementations behind common interface in erlang

I have a piece of erlang code which should read some values from a db and should support a couple of dbs. I wanted my code to be somehow not dependent from the db, so I implemented two different gen_servers that register both with the same atom (db_handler). I decide which version should be started reading the .app file.

The two gen_servers expose a common handle_call, so I can use in other parts of my application something like:

gen_server:call(db_handler, {do_something, "value1", "value2"})

This works, but still it is strongly coupled to the fact that each and any future implementation for a new db should be a gen_server.

I was thinking of using the ! operator and handle the command in the handle_info, but still I think that a better solution is possible (maybe passing through another module?).

Can somebody give me some insight on the better way to handle something like this in erlang?

like image 909
user601836 Avatar asked Oct 21 '22 10:10

user601836


1 Answers

For each db server add a common interface to abstract the call:

-module(db_server1).

...

do_something([Value1,Value2]) -> gen_server:call(db_handler, {do_something, "value1", "value2"}).

...

another one not using gen server

-module(db_server2).

...

do_something([Value1,Value2]) -> something_else({do_something, "value1", "value2"}).

...

create a new process (a gen_server :o) which receive as init parameter the param which is used to select the db server and store it in its state (for example db_server2),

for each do_something function, implement a function like:

do_something(Value1,Value2) -> gen_server:call(db_handler, {do_something, ["value1", "value2"]}).

...

handle_call({Func, Args}, _From, DB_server) ->
    R = DB_server:F(Args),
    {reply, R, DB_server}.

same thing for non blocking interfaces, using cast or equivalent

like image 51
Pascal Avatar answered Oct 31 '22 15:10

Pascal