Riak Commit Hook CRDT Increment Counter - erlang
I have a commit hook that I want to update a counter.
Currently I have:
-module(bucket_counter).
-export([precommit/1]).
-record(crdt_op, {mod, op, ctx}).
-define(CRDT_OP, #crdt_op).
-define(V1_COUNTER_TYPE, riak_kv_pncounter).
precommit(RObj) ->
{ok, Client} = riak:local_client(),
Bucket = {<<"counters">>, <<"update_counts">>},
Id = <<"all">>,
Counter = case Client:get(Bucket, Id) of
{error, notfound} -> riak_object:new(Bucket, Id, 0);
{ok, Obj} -> Obj
end,
io:format("Counter ~p~n", [Counter]),
{{Context,_},_} = riak_kv_crdt:value(Counter, ?V1_COUNTER_TYPE),
Op = ?CRDT_OP{mod=?V1_COUNTER_TYPE, op={increment, 1}, ctx=Context},
Counter2 = riak_kv_crdt:update(Counter, <<"1234">>, Op),
io:format("Gen ~p~n", [Counter2]),
%Counter3 = riak_kv_crdt:merge(Counter2),
Client:put(Counter2),
RObj.
This produces the error:
#riak_kv_put_fsm:decode_precommit:887 Problem invoking pre-commit hook bucket_counter:precommit -> error:function_clause
[{riak_kv_crdt,update_crdt,[[{riak_dt_pncounter,{{dict,5,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[[<<"dot">>|{<<252,97,47,244,1,104,136,26>>,{1,63622971158}}]],[],[],[],[],[],[[<<"content-type">>,97,112,112,108,105,99,97,116,105,111,110,47,114,105,97,107,95,99,111,117,110,116,101,114],[<<"X-Riak-VTag">>,53,87,81,75,79,113,110,77,80,111,117,49,71,101,120,122,52,67,89,115,66,122]],[[<<"index">>]],[],[[<<"X-Riak-Last-Modified">>|{1455,751958,325156}]],[],[]}}},{crdt,riak_dt_pncounter,"application/riak_counter",[{<<252,97,47,244,1,104,136,26>>,1,0}]}}}],<<"1234">>,{crdt_op,riak_kv_pncounter,{increment,1},<<>>}],[{file,"src/riak_kv_crdt.erl"},{line,234}]},{riak_kv_crdt,update,3,[{file,"src/riak_kv_crdt.erl"},{line,61}]},{bucket_counter,precommit,1,[{file,"bucket_counter.erl"},{line,24}]},{riak_kv_put_fsm,invoke_hook,4,[{file,"src/riak_kv_put_fsm.erl"},{line,853}]},{riak_kv_put_fsm,precommit,2,[{file,"src/riak_kv_put_fsm.erl"},{line,503}]},{gen_fsm,handle_msg,7,[{file,"gen_fsm.erl"},{line,505}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]
Looking into riak_kv source, It looks like merge only works with Maps and Sets when you have a context:
https://github.com/basho/riak_kv/blob/master/src/riak_kv_crdt.erl#L246
I have tried removing the context but it then crashes because of siblings:
riak_index:parse_object_hook:116 Siblings not allowed: {r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,49,67,49,85,69,121,66,118,111,84,56,85,118,81,104,104,106,74,101,98,49,71]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,750950,430934}]],[],[]}}},<<69,2,0,0,0,17,114,105,97,107,95,100,116,95,112,110,99,111,117,110,116,101,114,71,2,131,108,0,0,0,1,104,3,109,0,0,0,8,252,97,47,244,156,20,105,128,97,1,97,0,106>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,49,67,49,85,69,121,66,118,111,84,56,85,118,81,104,104,106,74,101,98,49,71]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,750950,430934}]],[],[]}}},<<69,1,71,1,0,0,0,22,70,1,131,108,0,0,0,1,104,2,109,0,0,0,4,49,50,51,52,97,1,106,0,0,0,4,70,1,131,106>>}],[{<<252,97,47,244,156,20,105,128>>,{1,63622970068}}],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined}
Updating to map gives me a sibling error:
-module(bucket_counter).
-export([precommit/1]).
-record(crdt_op, {mod, op, ctx}).
-define(CRDT_OP, #crdt_op).
-define(V1_COUNTER_TYPE, riak_kv_pncounter).
precommit(RObj) ->
{ok, Client} = riak:local_client(),
Bucket = {<<"counters">>, <<"update_counts">>},
Id = <<"all">>,
{Counter, Context} = case Client:get(Bucket, Id) of
{error, notfound} ->
Obj = riak_object:new(Bucket, Id, 0),
{Obj, undefined};
{ok, Obj} ->
{{CountContext,_},_} = riak_kv_crdt:value(Obj, riak_dt_map),
{Obj, CountContext}
end,
io:format("Counter ~p~n", [Counter]),
Op = ?CRDT_OP{mod=riak_dt_map, op={update,[{update,{<<"count">>,riak_dt_emcntr},increment}]}, ctx=Context},
Counter2 = riak_kv_crdt:update(Counter, <<"1234">>, Op),
io:format("Gen ~p~n", [Counter2]),
%Counter3 = riak_kv_crdt:merge(Counter2),
Client:put(Counter2),
RObj.
riak_index:parse_object_hook:116 Siblings not allowed: {r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},<<69,2,0,0,0,11,114,105,97,107,95,100,116,95,109,97,112,77,1,131,80,0,0,0,132,120,1,203,96,206,97,96,96,96,204,96,202,5,82,44,134,70,198,38,137,140,89,80,33,136,32,107,114,126,105,94,73,10,3,95,81,102,98,118,124,74,73,124,106,110,114,94,73,81,6,19,138,42,168,86,184,40,22,227,224,66,25,204,137,140,64,200,144,149,149,193,148,5,4,0,198,254,26,118>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},0}],[],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined}
2016-02-18 00:48:25.966 [debug] <0.2105.0>#riak_kv_put_fsm:decode_precommit:880 Pre-commit hook riak_index:parse_object_hook failed with reason {siblings_not_allowed,{r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},<<69,2,0,0,0,11,114,105,97,107,95,100,116,95,109,97,112,77,1,131,80,0,0,0,132,120,1,203,96,206,97,96,96,96,204,96,202,5,82,44,134,70,198,38,137,140,89,80,33,136,32,107,114,126,105,94,73,10,3,95,81,102,98,118,124,74,73,124,106,110,114,94,73,81,6,19,138,42,168,86,184,40,22,227,224,66,25,204,137,140,64,200,144,149,149,193,148,5,4,0,198,254,26,118>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},0}],[],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined}}
I have figured it out, I was going off of 1.4 documentation and instead I needed to do riak_kv_crdt:new(Bucket, Id, riak_dt_map)
Related
{aborted, {bad_type, {...} } on mnesia:write/3
Supressing irrelevant code, i've the following: % somefile.erl -record(task, {description, date, completed = false}). init() -> {atomic, _} = mnesia:create_table(task, [{attributes, record_info(fields, task)}]). In other file, where the {aborted, {bad_type, {}}} is ocurring: -record(task, {id, description, date, completed = false}). create_task(Req, State) -> Task = create_task_record(), Transaction = fun() -> mnesia:write(task, Task, write) end, {atomic, _} = mnesia:transaction(Transaction), % ... When i'm running the code, in the line {atomic, _} = mnesia:transaction(Transaction), i'm receiving the error {aborted, {bad_type, {task, ...}}}.
After hours trying to find, the problem here is in the record task definition. I wasn't using the hrl to share definitions, so i have the definition where i was using it, because of this, in one file the definition was missing the id attribute, so i was having different types.
Ejabberd get room online occupants within module
I am currently trying to get the occupants of a room in a custom Ejabberd module within the muc_filter_message hook, but all attempts to get the room state are timing out. error: 2016-07-25 10:43:04.802 [error] <0.13909.0>#ejabberd_hooks:run_fold1:368 {timeout,{gen_fsm,sync_send_all_state_event,[<0.13909.0>,get_state]}} imports + hook function (cut down) -behaviour(gen_mod). -include("ejabberd.hrl"). -include("logger.hrl"). -include("jlib.hrl"). -include("mod_muc_room.hrl"). -include("mod_muc.hrl"). -include("ejabberd_http.hrl"). -include("ejabberd_web_admin.hrl"). -include("ejabberd_commands.hrl"). muc_message_sent(Stanza, MUCState, RoomJID, FromJID, FromNick) -> {_, RoomName, Host, _, _, _, _} = RoomJID, OccuList = get_room_occupants(RoomName, Host), ?INFO_MSG("muc_message_sent OccuList ~p~n", [OccuList]), Stanza. Code for room occupants retrieval: get_room_occupants(Room, Host) -> case get_room_pid(Room, Host) of room_not_found -> ?INFO_MSG("muc_message_sent get_room_occ ~p~n", [room]); Pid -> get_room_occupants(Pid) end. get_room_occupants(Pid) -> ?INFO_MSG("muc_message_sent get_room_pstate ~p~n", [Pid]), S = get_room_state(Pid), ?INFO_MSG("muc_message_sent get_room_state S ~p~n", [S]), lists:map( fun({_LJID, Info}) -> {jid:to_string(Info#user.jid), Info#user.nick, atom_to_list(Info#user.role)} end, dict:to_list(S#state.users)). %% #doc Get the Pid of an existing MUC room, or 'room_not_found'. get_room_pid(Name, Service) -> case mnesia:dirty_read(muc_online_room, {Name, Service}) of [] -> ?INFO_MSG("muc_message_sent get_room_pid ~p~n", [failed]), room_not_found; [Room] -> ?INFO_MSG("muc_message_sent get_room_pid ~p~n", [pid]), Room#muc_online_room.pid end. get_room_state(Room_pid) -> {ok, R} = gen_fsm:sync_send_all_state_event(Room_pid, get_state), R. The get_room_occupants code is pulled directly from mod_muc_admin where it works fine (but I couldn't find a way to directly use the functions within that module). Been stuck on this for a while now so any ideas appreciated.
User send packet hook returning `badmatch` error
I am using user send packet hook in my custom module, I am not understanding why getting badmatch error for each of the packet received. i have added declaration part here too. **Code** -module(mod_post_log). -behaviour(gen_mod). -export([start/2,stop/1,log_user_send/4,post_result/1,send_message/3]). **strong text** -include("ejabberd.hrl"). -include("jlib.hrl"). -include("logger.hrl"). start(Host, _Opts) -> ok = case inets:start() of {error, {already_started, inets}} -> ok; ok -> ok end, ejabberd_hooks:add(user_send_packet, Host, ?MODULE, log_user_send, 50), ok. stop(Host) -> ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, log_user_send, 50), ok. log_user_send(Packet, _C2SState, From, To) -> ok = log_packet(From, To, Packet), Packet. log_packet(From, To, #xmlel{name = <<"message">>} = Packet) -> MessageId = xml:get_tag_attr_s(<<"id">>, Packet), Type = xml:get_tag_attr_s(list_to_binary("type"), Packet), send_message(From, To, MessageId, Type), %% send_message(From, To, xml:get_tag_attr_s(list_to_binary("id"), Packet),xml:get_tag_attr_s(list_to_binary("type"), Packet)), %% ?INFO_MSG("mod_ack_receipt - MsgID: ~p To: ~p From: ~p", [MessageId, To, From]), ok = log_message(From, To, Packet); log_packet(_From, _To, _Packet) -> ok. log_message(From, To, #xmlel{attrs = Attrs} = Packet) -> Type = lists:keyfind(<<"type">>, 1, Attrs), log_message_filter(Type, From, To, Packet). log_message_filter({<<"type">>, Type}, From, To, Packet) when Type =:= <<"chat">>; Type =:= <<"groupchat">> -> log_chat(From, To, Packet); log_message_filter(_Other, _From, _To, _Packet) -> ok. log_chat(From, To, #xmlel{children = Els} = Packet) -> case get_body(Els) of no_body -> ok; {ok, _Body} -> log_chat_with_body(From, To, Packet) end. log_chat_with_body(From, To, Packet) -> case should_acknowledge(Packet) of S when (S==true) -> post_xml(From, To, Packet); false -> ok end, Packet. should_acknowledge(#xmlel{name = <<"message">>} = Packet) -> case {xml:get_attr_s(<<"type">>, Packet#xmlel.attrs), xml:get_subtag_cdata(Packet, <<"body">>)} of {<<"error">>, _} -> false; {_, <<>>} -> %% Empty body false; _ -> true end; should_acknowledge(#xmlel{}) -> false. post_xml(From, To, Packet) -> Ts = to_iso_8601_date(os:timestamp()), MessageId = xml:get_tag_attr_s(list_to_binary("id"), Packet), Type = xml:get_tag_attr_s(list_to_binary("type"), Packet), Chat_sent = xml:get_tag_attr_s(list_to_binary("chat_sent"), Packet), Subject = xml:get_path_s(Packet, [{elem, list_to_binary("subject")},cdata]), Body = xml:get_path_s(Packet,[{elem, list_to_binary("body")}, cdata]), Sep = "&", Post = [ "from=", From#jid.luser, Sep, "to=", To#jid.luser, Sep, "body=", binary_to_list(Body), Sep, "type=", binary_to_list(Type),Sep, "chat_sent=", binary_to_list(Chat_sent),Sep, "subject=",binary_to_list(Subject),Sep, "message_id=", binary_to_list(MessageId),Sep, "xml=",xml:element_to_binary(Packet),Sep, "done=11" ], Url = get_opt(url), TsHeader = get_opt(ts_header, "X-Message-Timestamp"), FromHeader = get_opt(from_header, "X-Message-From"), ToHeader = get_opt(to_header, "X-Message-To"), HttpOptions = get_opt(http_options, []), ReqOptions = get_opt(req_options, []), {ok, _ReqId} = httpc:request(post, {Url, [], "application/x-www-form-urlencoded", list_to_binary(Post)}, HttpOptions, [ {sync, false}, {receiver, {?MODULE, post_result, []}} | ReqOptions ]), ?INFO_MSG("post http - MsgID: xml: ~p", [post]), ok. post_result({_ReqId, {error, Reason}}) -> report_error([ {error, Reason } ]); post_result({_ReqId, Result}) -> {StatusLine, Headers, Body} = Result, {_HttpVersion, StatusCode, ReasonPhrase} = StatusLine, if StatusCode < 200; StatusCode > 299 -> ok = report_error([ {status_code, StatusCode}, {reason_phrase, ReasonPhrase}, {headers, Headers}, {body, Body} ]), ok; true -> ok end. send_message(From, To, MessageId,Type) -> Packet = #xmlel{name = <<"iq">>, attrs = [{<<"to">>, From},{<<"ack">>, MessageId}, {<<"type">>, <<"result">>},{<<"chattype">>, Type}], children = [#xmlel{name = <<"ack">>, attrs = [{<<"xmlns">>,<<"xmpp:ack">> }], children = []}]}, ejabberd_router:route(From, From, Packet). get_body(Els) -> XmlEls = [ El || El <- Els, is_record(El, xmlel) ], case lists:keyfind(<<"body">>, #xmlel.name, XmlEls) of false -> no_body; #xmlel{children = InnerEls} -> case lists:keyfind(xmlcdata, 1, InnerEls) of false -> no_body; {xmlcdata, Body} -> {ok, Body} end end. get_opt(Opt) -> get_opt(Opt, undefined). get_opt(Opt, Default) -> F = fun(Val) when is_binary(Val) -> binary_to_list(Val); (Val) -> Val end, gen_mod:get_module_opt(global, ?MODULE, Opt, F, Default). report_error(ReportArgs) -> ok = error_logger:error_report([ mod_post_log_cannot_post | ReportArgs ]). **Error Log** {{badmatch,{xmlel,<<"message">>, [{<<"xml:lang">>,<<"en">>}, {<<"to">>,<<"123456789#xyz.myapp.com">>}, {<<"id">>,<<"AF1xJ-149">>}, {<<"chat_sent">>,<<"2015-12-15T06:45:29.399Z">>}, {<<"type">>,<<"chat">>}], [{xmlel,<<"size">>,[],[{xmlcdata,<<"0">>}]}, {xmlel,<<"subject">>,[],[{xmlcdata,<<"poke">>}]}, {xmlel,<<"body">>,[],[{xmlcdata,<<"95">>}]}, {xmlel,<<"request">>, [{<<"xmlns">>,<<"urn:xmpp:receipts">>}], []}]}}, [{mod_post_log,log_packet,3, [{file,"src/mod_post_log.erl"},{line,44}]}, {mod_post_log,log_user_send,4, [{file,"src/mod_post_log.erl"},{line,33}]}, {ejabberd_hooks,safe_apply,3, [{file,"src/ejabberd_hooks.erl"},{line,382}]}, {ejabberd_hooks,run_fold1,4, [{file,"src/ejabberd_hooks.erl"},{line,365}]}, {ejabberd_c2s,session_established2,2, [{file,"src/ejabberd_c2s.erl"},{line,1296}]}, {p1_fsm,handle_msg,10,[{file,"src/p1_fsm.erl"},{line,582}]}, {proc_lib,init_p_do_apply,3, [{file,"proc_lib.erl"},{line,237}]}]}
In file src/mod_post_log.erl at line 44 in function mod_post_log:log_packet/3 is some match operator which doesn't expect to get {xmlel,<<"message">>, [{<<"xml:lang">>,<<"en">>}, {<<"to">>,<<"123456789#xyz.myapp.com">>}, {<<"id">>,<<"AF1xJ-149">>}, {<<"chat_sent">>,<<"2015-12-15T06:45:29.399Z">>}, {<<"type">>,<<"chat">>}], [{xmlel,<<"size">>,[],[{xmlcdata,<<"0">>}]}, {xmlel,<<"subject">>,[],[{xmlcdata,<<"poke">>}]}, {xmlel,<<"body">>,[],[{xmlcdata,<<"95">>}]}, {xmlel,<<"request">>, [{<<"xmlns">>,<<"urn:xmpp:receipts">>}], []}]}
it would be much better to see full module "mod_post_log.erl" as is. But i think that problem is here : MessageId = xml:get_tag_attr_s(<<"id">>, Packet), Packet is a record, and function wait for iolist, so it should be something like MessageId = xml:get_tag_attr_s(<<"id">>, Packet#xmlel.{{see record declaration}}),
Implementing mod_blocking on MongooseIM
I'm trying to implement mod_blocking that will work only with mod_privacy in odbc module. I keep getting the response: <error code='500' type='wait'><internal-server-error0 xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error> Here is my code: process_blocklist_block(LUser, LServer, JIDs) -> Filter = fun (List) -> AlreadyBlocked = list_to_blocklist_jids(List, []), lists:foldr(fun (JID, List1) -> case lists:member(JID, AlreadyBlocked) of true -> List1; false -> [#listitem{type = jid, value = JID, action = deny, order = 0, match_all = true} | List1] end end, List, JIDs) end, case process_blocklist_block(LUser, LServer, Filter,odbc) of {atomic, {ok, Default, List}} -> UserList = make_userlist(Default, List), broadcast_list_update(LUser, LServer, Default, UserList), broadcast_blocklist_event(LUser, LServer, {block, JIDs}), {result, [], UserList}; _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} end. process_blocklist_block(LUser, LServer, Filter, odbc) -> F = fun () -> Default = case mod_privacy_odbc:sql_get_default_privacy_list_t(LUser) of {selected, [<<"name">>], []} -> Name = <<"Blocked contacts">>, mod_privacy_odbc:sql_add_privacy_list(LUser, Name), mod_privacy_odbc:sql_set_default_privacy_list(LUser, Name), Name; {selected, [<<"name">>], [[Name]]} -> Name end, {selected, [<<"id">>], [[ID]]} = mod_privacy_odbc:sql_get_privacy_list_id_t(LUser, Default), case mod_privacy_odbc:sql_get_privacy_list_data_by_id_t(ID) of {selected, [<<"t">>, <<"value">>, <<"action">>, <<"ord">>, <<"match_all">>, <<"match_iq">>, <<"match_message">>, <<"match_presence_in">>, <<"match_presence_out">>], RItems = [_ | _]} -> List = lists:map(fun mod_privacy_odbc:raw_to_item/1, RItems); _ -> List = [] end, NewList = Filter(List), NewRItems = lists:map(fun mod_privacy_odbc:item_to_raw/1, NewList), mod_privacy_odbc:sql_set_privacy_list(ID, NewRItems), {ok, Default, NewList} end, ejabberd_odbc:sql_transaction(LServer, F). I've checked all the queries. They work fine. I struggling with understanding the logic of this piece of code. What is the best way to debug this code, so i can understand when my logic is failing? Could anyone point me in the right direction? UserList = make_userlist(Default, List), broadcast_list_update(LUser, LServer, Default, UserList), broadcast_blocklist_event(LUser, LServer, {block, JIDs}), {result, [], UserList}; _ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
if you expect _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} is the point where server returns 'internal server error', you can just change this place to _Otherwise -> ?WARNING_MSG("Got some unexpected result in mod_priv ~100000p",[_Otherwise]), {error, ?ERR_INTERNAL_SERVER_ERROR) and then look at log/ejabberd.log Of course you need to start mongooseim with loglevel at least 3 in the ejabberd.cfg
Erlang: supervisor:start_child/2 error has me baffled
I'm making slight modifications to Logan/Merritt/Carlson's simple cache, Chapter 6, pp 149-169, Erlang and OTP in Action. So far, no code changes, just renaming the modules. I start the application: application:start(gridz). ok I insert an item: gridz_maker:insert(blip, blop). I get this error: ** exception error: no match of right hand side value {error, {function_clause, [{gridz_edit,init, [{blop,86400}], [{file,"src/gridz_edit.erl"},{line,51}]}, {gen_server,init_it,6, [{file,"gen_server.erl"},{line,304}]}, {proc_lib,init_p_do_apply,3, [{file,"proc_lib.erl"},{line,227}]}]}} in function gridz_maker:insert/2 (src/gridz_maker.erl, line 15) Here's the code: insert(Key, Value) -> case gridz_store:lookup(Key) of {ok, Pid} -> gridz_edit:replace(Pid, Value); {error, _} -> {ok, Pid} = gridz_edit:create(Value), %% line 15 gridz_store:insert(Key, Pid) end. I look at line 15: {error, _} -> {ok, Pid} = gridz_edit:create(Value), I expect the error because this is a new item. gridz:edit is a gen_server (sc_element in Logan et/al.) Here's the code for create/1: create(Value) -> create(Value, ?DEFAULT_LEASE_TIME). create(Value, LeaseTime) -> gridz_sup:start_child(Value, LeaseTime). And here's the code for gridz_sup:start_child/2: start_child(Value, LeaseTime) -> supervisor:start_child(?SERVER, [Value, LeaseTime]). init([]) -> Grid = {gridz_edit, {gridz_edit, start_link, []}, temporary, brutal_kill, worker, [gridz_edit]}, Children = [Grid], RestartStrategy = {simple_one_for_one, 0, 1}, {ok, {RestartStrategy, Children}}. If I execute supervisor:start_child/2 directly, here's what I get: {error,{function_clause,[{gridz_edit,init, [{blop,50400}], [{file,"src/gridz_edit.erl"},{line,51}]}, {gen_server,init_it,6, [{file,"gen_server.erl"},{line,304}]}, {proc_lib,init_p_do_apply,3, [{file,"proc_lib.erl"},{line,227}]}]}} Line 51 in gridz_edit is an init function: init([Value, LeaseTime]) -> Now = calendar:local_time(), StartTime = calendar:datetime_to_gregorian_seconds(Now), {ok, #state{value = Value, lease_time = LeaseTime, start_time = StartTime}, time_left(StartTime, LeaseTime)}. If I execute it directly, it works: 120> gridz_edit:init([blop, (60 * 60 * 24)]). {ok,{state,blop,86400,63537666408},86400000} So now I'm baffled. What am I missing? Why does supervisor:start_child/2 throw an error? Thanks, LRP
The error says you are passing in a tuple with 2 members, {blop,86400}, when you seem to be expecting a list of 2 members: [Value, LeaseTime]. In your direct execution, you are also using a list, so it works. You should figure out where the tuple is being created, and create a list instead.