<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Erlang API: action init callback not implemented? in NSO Developer Hub Discussions</title>
    <link>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3950864#M4445</link>
    <description>&lt;P&gt;Trying to write an action in Erlang API and wanted to spawn a new worker in init() callback for each new action invocation.&lt;BR /&gt;Action init callback seems to be not implemented in Erlang API: confd_action_cb record in econfd.hrl has no "init" field.&lt;BR /&gt;NSO versions 4.7.4.3 and 5.1.&lt;/P&gt;</description>
    <pubDate>Thu, 31 Oct 2019 02:52:23 GMT</pubDate>
    <dc:creator>alex-filippov</dc:creator>
    <dc:date>2019-10-31T02:52:23Z</dc:date>
    <item>
      <title>Erlang API: action init callback not implemented?</title>
      <link>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3950864#M4445</link>
      <description>&lt;P&gt;Trying to write an action in Erlang API and wanted to spawn a new worker in init() callback for each new action invocation.&lt;BR /&gt;Action init callback seems to be not implemented in Erlang API: confd_action_cb record in econfd.hrl has no "init" field.&lt;BR /&gt;NSO versions 4.7.4.3 and 5.1.&lt;/P&gt;</description>
      <pubDate>Thu, 31 Oct 2019 02:52:23 GMT</pubDate>
      <guid>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3950864#M4445</guid>
      <dc:creator>alex-filippov</dc:creator>
      <dc:date>2019-10-31T02:52:23Z</dc:date>
    </item>
    <item>
      <title>Re: Erlang API: action init callback not implemented?</title>
      <link>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3950891#M4446</link>
      <description>&lt;P&gt;Hi,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I guess you want to avoid a long running action to block other user session invocations of the action?&lt;/P&gt;
&lt;P&gt;Using the erlang api, you do not have to handle that case as you would in the C-api.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;econfd:init_daemon(...):&lt;/P&gt;
&lt;P&gt;Starts and links to a gen_server which connects to ConfD/NSO. This gen_server holds two sockets to ConfD/NSO, one so called control socket and one worker socket (See confd_lib_dp(3) for an explanation of those sockets.)&lt;/P&gt;
&lt;P&gt;To avoid blocking control socket callback requests due to long-running worker socket callbacks, the control socket callbacks are run in the gen_server, while the worker socket callbacks are run in a separate process that is spawned by the gen_server. This means that applications must not share e.g. MAAPI sockets between transactions, since this could result in simultaneous use of a socket by the gen_server and the spawned process.&lt;/P&gt;
&lt;P&gt;...&lt;/P&gt;</description>
      <pubDate>Thu, 31 Oct 2019 05:34:24 GMT</pubDate>
      <guid>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3950891#M4446</guid>
      <dc:creator>sunge</dc:creator>
      <dc:date>2019-10-31T05:34:24Z</dc:date>
    </item>
    <item>
      <title>Re: Erlang API: action init callback not implemented?</title>
      <link>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3951212#M4449</link>
      <description>&lt;P&gt;Thank you. Yes, that blocking is what I try to avoid. And that was initially my hope that Erlang API does not need the init callback for actions, because it somehow spawns workers as needed. But so far I am stuck with only one worker, which blocks other users while it executes one action.&lt;/P&gt;&lt;P&gt;The problem seems to be that there is only one worker socket and only one worker process. The daemon does not spawn a new worker for each incoming action, does not maintain a pool of workers (like Java and Python API do, I think), and there is no way for me to spawn workers myself (like in C API) because action init callback is not supported.&lt;/P&gt;&lt;P&gt;More in detail, as I understand:&lt;/P&gt;&lt;P&gt;econfd:init_daemon calls econfd_daemon:init, which opens one control and one worker socket. Dx#confd_daemon_ctx.wint gets set to 1.&lt;/P&gt;&lt;P&gt;After econfd:register_action_cb, econfd:register_done invokes econfd_daemon:handle_call(register_done..), which spawns a single worker process listening on the worker socket. The daemon is ready.&lt;/P&gt;&lt;P&gt;A user invokes an action, ?CONFD_PROTO_NEW_ACTION arrives via the control socket, the relevant clause of econfd_daemon:confd_fd_ready sends back wint=1, thus telling NCS to use worker socket one. NCS sends ?CONFD_CALL_ACTION via the worker socket and blocks while the worker runs the action callback.&lt;/P&gt;&lt;P&gt;Any further actions get processed quickly on the control socket and queue up on the worker socket. On the control socket, the handler of&amp;nbsp;?CONFD_PROTO_NEW_ACTION does not do any spawning, so there are no new workers and it's always wint=1 back to NCS, and NCS is stuck with one worker socket.&lt;/P&gt;</description>
      <pubDate>Thu, 31 Oct 2019 15:02:58 GMT</pubDate>
      <guid>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3951212#M4449</guid>
      <dc:creator>alex-filippov</dc:creator>
      <dc:date>2019-10-31T15:02:58Z</dc:date>
    </item>
    <item>
      <title>Re: Erlang API: action init callback not implemented?</title>
      <link>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3954258#M4482</link>
      <description>&lt;P&gt;Hi,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I had a talk with the developers responsible for the Erlang API, and they suspect your findings are correct.&lt;/P&gt;
&lt;P&gt;That said, I'm not entirely sure how to help you bypass the issue.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 06 Nov 2019 19:22:21 GMT</pubDate>
      <guid>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3954258#M4482</guid>
      <dc:creator>sunge</dc:creator>
      <dc:date>2019-11-06T19:22:21Z</dc:date>
    </item>
    <item>
      <title>Re: Erlang API: action init callback not implemented?</title>
      <link>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3995757#M4588</link>
      <description>&lt;P&gt;Quick question.&lt;/P&gt;
&lt;P&gt;After calling init_daemon(...), did you run econfd:controlliing_process() to make sure the&lt;/P&gt;
&lt;P&gt;worker process is being called?&lt;/P&gt;</description>
      <pubDate>Mon, 09 Dec 2019 12:20:41 GMT</pubDate>
      <guid>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3995757#M4588</guid>
      <dc:creator>sunge</dc:creator>
      <dc:date>2019-12-09T12:20:41Z</dc:date>
    </item>
    <item>
      <title>Re: Erlang API: action init callback not implemented?</title>
      <link>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3995934#M4589</link>
      <description>&lt;P&gt;No, I did not run that.&lt;/P&gt;&lt;P&gt;The worker process worked well without it. The action was doing its job.&lt;/P&gt;</description>
      <pubDate>Mon, 09 Dec 2019 17:04:51 GMT</pubDate>
      <guid>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/3995934#M4589</guid>
      <dc:creator>alex-filippov</dc:creator>
      <dc:date>2019-12-09T17:04:51Z</dc:date>
    </item>
    <item>
      <title>Re: Erlang API: action init callback not implemented?</title>
      <link>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/4550504#M6821</link>
      <description>&lt;P&gt;Hi,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Sorry for reviving this old thread, but I am running into exactly the same problem with NSO 5.6.2.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I can't get actions callback's written with the Erlang API to run concurrently.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Is it still the case there is no way to spawn new workers for action calls ?&lt;/P&gt;</description>
      <pubDate>Fri, 11 Feb 2022 12:54:21 GMT</pubDate>
      <guid>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/4550504#M6821</guid>
      <dc:creator>radioman</dc:creator>
      <dc:date>2022-02-11T12:54:21Z</dc:date>
    </item>
    <item>
      <title>Re: Erlang API: action init callback not implemented?</title>
      <link>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/4552699#M6827</link>
      <description>&lt;P&gt;Hi,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Seems like there there is limited interest in the Erlang API. But I found this thread when I hit the problem so might be useful for others.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Of all the API's I could not accept the Erlang API, to have no action concurrency options at all. So I made a workaround/hack around this problem, it does re-implement some internal stuff from the econfd application, So would be appreciated if this could be fixed properly upstream at some point in time.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This code will spawn a new process for every action call, to limit the amount of code that needed to be re-implemented, the process is stopped with&amp;nbsp;timer:exit_after/2.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;-module(ec_cfs_test_action_server).

-behaviour(gen_server).

%% API
-export([
         start_link/0
        ]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3, call_action/4]).

-include_lib("econfd/include/econfd.hrl").
-include_lib("econfd/include/econfd_errors.hrl").
-include_lib("econfd/src/econfd_proto.hrl").

-define(SERVER, ?MODULE).

% from econfd_internal.hrl
-define(CLIENT_CAPI,         3).

%%%===================================================================
%%% API
%%%===================================================================

start_link() -&amp;gt;
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

%%%===================================================================
%%% gen_server callbacks
%%%===================================================================

init([]) -&amp;gt;
    process_flag(trap_exit, true), % Triggers call to terminate/2
    Host = {127,0,0,1},
    {ok, Dx} = econfd_daemon:init([?MODULE,?CONFD_SILENT, user, {}, Host, ?NCS_PORT]),

    % While we are in the init state of the gen_server, we can't use the econfd functions,
    % since they rely in the gen_server to be ready.
    {reply, ok, Dx1} = econfd_daemon:handle_call({register_action_cb,
                                                  #confd_action_cb{actionpoint = 'cfs-test-action-erl-ap',
                                                    action = fun call_action/4}
                                                 }, self(), Dx),
    {reply, ok, Dx2} = econfd_daemon:handle_call(register_done, self(), Dx1),
    log(info, "Server started", []),
    {ok, Dx2}.

%%--------------------------------------------------------------------
handle_call(Req, From, State) -&amp;gt;
    econfd_daemon:handle_call(Req, From, State).

%%--------------------------------------------------------------------
handle_cast(Msg, State) -&amp;gt;
    econfd_daemon:handle_cast(Msg, State).

%%--------------------------------------------------------------------
handle_info(State={tcp, _Socket, Data}, Dx) -&amp;gt;
    case econfd_internal:term_get(Data) of
        _ET={_Op=?CONFD_PROTO_NEW_ACTION, _Qref, _Did, _Usid, _CallPoint, _Index, _TH} -&amp;gt;
            {ok, Socket} = econfd_internal:connect(Dx#confd_daemon_ctx.ip, Dx#confd_daemon_ctx.port, ?CLIENT_CAPI, [{active, true}]),
            Int = incr(),
            ok= econfd_internal:term_write(Socket, {?CONFD_PROTO_WORKER, Dx#confd_daemon_ctx.daemon_id, Int}),
            Worker = proc_lib:spawn_link(econfd_daemon, worker, [Dx]),
            % Have some failsafe to not have the worker hanning around forever.
            timer:exit_after(300*1000, Worker,worker_exit),
            Dx1 = Dx#confd_daemon_ctx{ wint=Int, worker=Socket, worker_pid=Worker},
            econfd:controlling_process(Socket, Worker),
            econfd_daemon:handle_info(State, Dx1),
            % Keep using original daemon state since action worker is for one-time usage.
            {noreply, Dx};
        _ -&amp;gt;
            econfd_daemon:handle_info(State, Dx)
    end;
handle_info({'EXIT',_,worker_exit}, State) -&amp;gt;
    {noreply,State};
handle_info(Info, State) -&amp;gt;
    econfd_daemon:handle_info(Info, State).

%%--------------------------------------------------------------------
terminate(Reason, State) -&amp;gt;
    log(info, "Server stopped - ~p", [Reason]),
    econfd_daemon:terminate(Reason, State).

%%--------------------------------------------------------------------
code_change(OldVsn, State, Extra) -&amp;gt;
    econfd_daemon:code_change(OldVsn, State, Extra).

%%%===================================================================
%%% Internal functions
%%%===================================================================

incr() -&amp;gt;
    X = get(sock_int),
    put(sock_int, X+1),
    X.

%%--------------------------------------------------------------------
call_action(_,[_|'test-action'],_,Args) -&amp;gt;
    log(info,"Args ~p ~p",[self(),Args]),
    % Do some heavy lifting :-)
    timer:sleep(10000),
    timer:exit_after(500,worker_exit),
    ok;

call_action(A1,A2,A3,A4) -&amp;gt;
    log(error,"Unknow call ~p ~p ~p ~p",[A1,A2,A3,A4]),
    timer:exit_after(500,worker_exit),
    ok.

%%--------------------------------------------------------------------
log(error, Format, Args) -&amp;gt;
    econfd:log(?CONFD_LEVEL_ERROR, "~p: " ++ Format, [?SERVER | Args]);
log(info, Format, Args) -&amp;gt;
    econfd:log(?CONFD_LEVEL_INFO,  "~p: " ++ Format, [?SERVER | Args]);
log(trace, Format, Args) -&amp;gt;
    econfd:log(?CONFD_LEVEL_TRACE, "~p: " ++ Format, [?SERVER | Args]).&lt;/PRE&gt;</description>
      <pubDate>Tue, 15 Feb 2022 13:07:49 GMT</pubDate>
      <guid>https://community.cisco.com/t5/nso-developer-hub-discussions/erlang-api-action-init-callback-not-implemented/m-p/4552699#M6827</guid>
      <dc:creator>radioman</dc:creator>
      <dc:date>2022-02-15T13:07:49Z</dc:date>
    </item>
  </channel>
</rss>

