我是OTP的新手,我正在尝试创建一个简单的例子来理解主管的行为:
这是简单的增量服务器
-module( inc_serv ).
-behaviour( gen_server ).
-export( [ start/0, inc/1, stop/0 ] ).
-export( [ init/1, handle_call/3, terminate/2 ] ).
start() ->
gen_server:start_link( { local, ?MODULE }, ?MODULE, no_args, [] ).
stop() ->
gen_server:call( ?MODULE, stop ).
inc( Num ) ->
gen_server:call( ?MODULE, { num, Num } ).
init( no_args ) ->
io:format( "~p~n", [ "Increment server started :)" ] ),
{ ok, no_state }.
handle_call( { num, Num }, _From, no_state ) ->
{ reply, Num + …Run Code Online (Sandbox Code Playgroud) 我正在研究Erlang文档,试图了解设置OTP gen_server和supervisor的基础知识.每当我的gen_server崩溃时,我的主管也会崩溃.事实上,每当我在命令行上出错时,我的主管就会崩溃.
我希望gen_server在崩溃时重新启动.我希望命令行错误对我的服务器组件没有任何影响.我的主管不应该崩溃.
我正在使用的代码是一个基本的"回声服务器",它回复你发送的任何内容,以及一个主管,它最多每分钟重启一次echo_server 5次(one_for_one).我的代码:
echo_server.erl
-module(echo_server).
-behaviour(gen_server).
-export([start_link/0]).
-export([echo/1, crash/0]).
-export([init/1, handle_call/3, handle_cast/2]).
start_link() ->
gen_server:start_link({local, echo_server}, echo_server, [], []).
%% public api
echo(Text) ->
gen_server:call(echo_server, {echo, Text}).
crash() ->
gen_server:call(echo_server, crash)..
%% behaviours
init(_Args) ->
{ok, none}.
handle_call(crash, _From, State) ->
X=1,
{reply, X=2, State}.
handle_call({echo, Text}, _From, State) ->
{reply, Text, State}.
handle_cast(_, State) ->
{noreply, State}.
Run Code Online (Sandbox Code Playgroud)
echo_sup.erl
-module(echo_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
start_link() ->
supervisor:start_link(echo_sup, []).
init(_Args) ->
{ok, {{one_for_one, 5, 60},
[{echo_server, {echo_server, start_link, …Run Code Online (Sandbox Code Playgroud) 主要是我想知道我是否可以在分布式erlang设置中的消息中发送函数.
在机器1上
F1 = Fun()-> hey end,
gen_server:call(on_other_machine,F1)
Run Code Online (Sandbox Code Playgroud)
在机器2上
handler_call(Function,From,State) ->
{reply,Function(),State)
Run Code Online (Sandbox Code Playgroud)
合理?
我从GenServer中的句柄信息功能调用elixir genserver来添加电话号码获取表单客户端.但是一旦调用handle_call,所有者进程就会崩溃[timeout].请帮忙.
全局创建一个ETS以在调用任何下面描述的函数之前插入值.
def handle_info(message, state) do
{a,b} = message
phonenumber = b[:body]
add phonenumber
{:noreply, state}
end
def add(phonenumber) do
GenServer.call(__MODULE__, {:add, phonenumber})
end
def handle_call({:add, phonenumber}, from, state) do
:ets.insert(:access_table, {:details, phonenumber})
reply = {:ok, "Added #{phonenumber} to profile"}
new_state = [{username} | state]
{:reply, reply , new_state}
end
Run Code Online (Sandbox Code Playgroud)
错误:
** When Server state == []
** Reason for termination ==
** {timeout,{gen_server,call,['Elixir.Bankrecord',{add,"346534543534"},5000]}}
** (EXIT from #PID<0.150.0>) exited in: :gen_server.call(Bankrecord, {:add, '346534543534'}, 5000)
** (EXIT) time out
Run Code Online (Sandbox Code Playgroud) 我正在使用erlang作为服务之间的桥梁,我想知道人们有什么建议来处理被击落的连接?
我从本地文件中获取输入并将它们输出到AMQP,可以想象AMQP经纪人可能会崩溃.对于这种情况,我想继续重试连接到AMQP服务器,但我不想将CPU与这些连接尝试挂钩.我倾向于在重新启动AMQP代码时进行睡眠.难道"黑客"本能绕过快速失败并让erlang处理它的目的吗?更一般地说,是否应该使用erlang管理员行为来处理故障连接?
免责声明:作者是OTP的新手,具有Erlang语法,过程和消息的一些基本知识.
我试图理解Erlang中的行为概念,但是我头脑中的许多问题使我无法理解像gen_server这样的行为的整个原则.
好的,gen_server的官方文档显示了一个很好的服务器图和三个与查询和回复箭头相关的客户端:http: //www.erlang.org/doc/design_principles/gen_server_concepts.html
但每次我试图进一步理解这个概念时,我都会陷入困境.
有很多概念我无法在脑海中构建成一个更大的概念:
我使用以下资源:
我仍然处于状态"我们在一个模块中调用一个函数,这个函数调用另一个函数,该函数创建一个进程...卡住"
有没有办法在图表中描述gen_server的概念?如何在视觉上显示客户端和服务器之间的交互流?(帮助不那么聪明的新人在视觉上理解这个概念)
例如,像这里:http://support.novell.com/techcenter/articles/img/dnd2003080506.gif
UPD:我试图绘制我自己的图表,但我仍然没有达到图中任何连接器的目的:http://postimage.org/image/qe215ric/full/
UPD2:这与我希望看到的类似:http://cryptoanarchy.org/wiki/Worker_patterns(模型).但是,它没有显示模块,功能和过程之间的交互.
美好的一天,
我有一个gen_server进程,它定期执行一些长期运行的状态更新任务
handle_info:
handle_info(trigger, State) ->
NewState = some_long_running_task(),
erlang:send_after(?LOOP_TIME, self(), trigger),
{noreply, NewState}.
Run Code Online (Sandbox Code Playgroud)
但是当这样的任务运行时,整个服务器都没有响应,任何对它的调用都会导致整个服务器崩溃:
my_gen_server:status().
** exception exit: {timeout,{gen_server,call,[my_gen_server,status]}}
in function gen_server:call/2
Run Code Online (Sandbox Code Playgroud)
如何避免阻止gen_server?当一个人my_gen_server:status()随时打电话时,结果应该是这样的:
{ok, task_active}
有人可以解释gen_server:start()和之间的区别是gen_server:start_link()什么?
我被告知这是多线程的东西.
编辑: 如果我的gen_server是从多个线程调用的,它会一次执行吗?或者它会在这些线程之间创建并发吗?
在这两种方法中,我坚持如何通过给定的一组id或组映射进程,然后将存储的struct映射到过滤数据.
%{group => [users]} 实现.我意识到组将与用户相反,因此我创建了一个使用组名作为键的处理模块.
恐怕在未来还会有在几组很多用户,所以我的问题是我怎么可以拆分当前UserGroupServer模块,以保持按组名称标识许多分离的过程?我想保留当前模块的功能,在init进程中按组列表,另外我不知道如何映射每个进程以通过user_id获取组?
目前我lib/myapp.ex通过在子树列表中包含模块在Phoenix中只启动一个进程,因此我可以UserGroupServer直接在Channels中调用.
defmodule UserGroupServer do
use GenServer
## Client API
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, :ok, opts)
end
def update_user_groups_state(server, data) do
{groups, user_id} = data
GenServer.call(server, {:clean_groups, user_id}, :infinity)
users = Enum.map(groups, fn(group) ->
GenServer.call(server, {:add_user_group, group, user_id}, :infinity)
end)
Enum.count(Enum.uniq(List.flatten(users)))
end
def get_user_groups(server, user_id) do
GenServer.call(server, {:get_user_groups, user_id})
end
def users_count_in_gorup(server, group) do
GenServer.call(server, {:users_count_in_gorup, group})
end
## Callbacks (Server API)
def init(_) do
{:ok, …Run Code Online (Sandbox Code Playgroud) 我有一个gen_server当开始尝试在监督树中的主管下启动一定数量的子进程(通常是10-20)时.gen_server的init回调调用supervisor:start_child/2所需的每个子进程.调用supervisor:start_child/2是同步的,因此在子进程启动之前它不会返回.所有子进程也是gen_servers,因此在init回调返回之前,start_link调用不会返回.在init回调中,对第三方系统进行了调用,这可能需要一段时间才能响应(我发现这个问题,当第三方系统的调用在60秒后超时).与此同时,init调用已被阻止,这意味着supervisor:start_child/2它也被阻止.所以调用的gen_server进程supervisor:start_child/2一直没有响应.在等待start_child函数返回时调用gen_server超时.因为这可以容易地持续60秒或更长时间.我想改变它,因为我的应用程序在等待时暂停在一种半启动状态.
解决此问题的最佳方法是什么?
我能想到的唯一解决方案是将与第三方系统交互的代码从init回调移到handle_cast回调中.这将使init回调更快.缺点是我需要gen_server:cast/2在所有子进程启动后调用.
有没有更好的方法呢?