I'm new to erlang, new to this list and I hope here's the right place to ask this question.
I'm currently implementing a module for ejabberd where I need to log certain packets to a MySQL DB and I'm using the MySQL Native Driver for it.
My current implementation is on github:
https://github.com/amiadogroup/mod_log_chat_mysql5/blob/master/src/mod_log_chat_mysql5.erl
In this file you see that I'm opening the MySQL Connection in the function "open_mysql_connection" and assign it to a ETS Table because I didn't find another way to store the DB Reference (I tried something with records but didn't succeed).
This worked pretty well but I ran into the problem that after some days/weeks the ets table didn't have the DB Reference anymore.
To prevent this, I want to create functions which setup the DB Connection again, if it doesn't have it anymore.
As I'm trying to do this I run into the problem that the informations about how to connect to the db is only in the init-function available and I don't really want to store this information also in the ets table.
Can anyone help me or point me to a site on how to do this?
Thanks,
Michael
_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://erlang.org/mailman/listinfo/erlang-questions
On line 48 in your code you store the connection information used in
open_mysql_connection/1 in the state of the server. Perhaps you can
make use of that?
Regards,
Gustav Simonsson
Note, for instance, how you have access to the state when a info message
is received in handle_info/2 of your module.
Also the proper syntax for accessing record fields is Expr#Name.Field
which would translate to DBref = State#state.dbref in your case.
I hope that clarifies things a little :)
Regards,
Gustav Simonsson
On Wed, 2011-10-05 at 16:26 +0200, Michael Weibel - Amiado Group wrote:
> Hi Gustav,
>
> Wow, thanks for your _quick_ reply! :)
> Yeah at first I thought also that I could use that but didn't really figure out how to do that (maybe I don't really understand records yet).
>
> Because the "log_packet_send" is called from ejabberd (it's a hook) and from this function, as you see, I call some other functions until it arrives at the "insert_row" function.
> In the insert_row function I'd need the DB Reference as you see.
> There, can I just use it like this:
> DBref = #state.dbref
>
> Is this the correct way?
>
> thanks,
> Michael
On Wed, Oct 5, 2011 at 8:36 AM, Michael Weibel - Amiado Group
<michael...@amiadogroup.com> wrote:
> Hi all,
>
> I'm new to erlang, new to this list and I hope here's the right place to ask this question.
Welcome!
>
> I'm currently implementing a module for ejabberd where I need to log certain packets to a MySQL DB and I'm using the MySQL Native Driver for it.
>
> My current implementation is on github:
> https://github.com/amiadogroup/mod_log_chat_mysql5/blob/master/src/mod_log_chat_mysql5.erl
>
> In this file you see that I'm opening the MySQL Connection in the function "open_mysql_connection" and assign it to a ETS Table because I didn't find another way to store the DB Reference (I tried something with records but didn't succeed).
>
> This worked pretty well but I ran into the problem that after some days/weeks the ets table didn't have the DB Reference anymore.
> To prevent this, I want to create functions which setup the DB Connection again, if it doesn't have it anymore.
You typically don't want to do this. There's a much, much better way...
> As I'm trying to do this I run into the problem that the informations about how to connect to the db is only in the init-function available and I don't really want to store this information also in the ets table.
The "go to" pattern in Erlang for what you're trying to do is a
supervised process. Using standard OTP facilities, you get this:
- Registration of process IDs using atoms (analogous to you storing a
connection PID in ets)
- Well defined "init" logic that's automatically applied when a
process needs to be restarted
- Encapsulation of the messy details of handling service provisioning
Fortunately, the MySQL driver (at the more recent ones - there are
several lineages out there) provides an OTP compliant connection
process, so you can do something as simple as this:
-module(my_db).
-export([start_link/0, fetch/1]).
start_link() ->
Host = "localhost",
Port = 3306,
Db = "`my-db`",
User = "root",
Password = "password",
mysql:start_link(?MODULE, Host, Port, User, Password, Db, fun mysql_log/4).
fetch(Sql) ->
mysql:fetch(?MODULE, Sql).
mysql_log(_Module, _Line, _Level, _FormatFun) ->
ok.
This is a registered process (i.e. there's one of them at runtime)
that provides access to your database.
The connection config in start_link/0 would typically come from an
application config, which you can read using application:get_env/2.
You can also create a start_link that takes the params.
To use this module as a service, you need to plug it into your
supervisory hierarchy. Here's what your top-level supervisor might
look like:
-module(my_app_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
-define(SERVER, ?MODULE).
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
init([]) ->
{ok, {{one_for_one, 5, 5},
[{my_db, {my_db, start_link, []},
permanent, 5000, worker, [my_db]}]}}.
If your my_db service crashes, the supervisor will restart it. The
"config" that you'd use for that restart would come from either the
OTP app config. (You *could* provide it in the supervisor child spec,
but I wouldn't go that way.)
Erlang gives you very nice facilities to create a mini "service
oriented architecture" -- you want to look for ways to create very
opaque services that have drop-dead simple start/restart semantics
(i.e. simple as pushing a button) and let supervisors monitor and
recover failed services as needed.
If for some reason you needed to dynamically configure your MySQL
connection params, you could store the config in a database, external
file, etc. and force a restart of your my_db process to re-read that
config on init.
Garrett