有时我的循环返回ok因为超时如何写这个代码在正确的方式.当有一个超时它只是返回ok,但不是我的实际值,我假设.在句柄调用我调用一个函数循环循环中的()()函数我正在接收一条带有receive子句的消息。现在,我使用loop2函数将此数据发送到数据库,无论数据是否已成功保存,都会从数据库返回响应,并将响应返回给循环但是如果有超时,我的循环函数返回ok,但不是实际值。
% @Author: ZEESHAN AHMAD
% @Date: 2020-12-22 05:06:12
% @Last Modified by: ZEESHAN AHMAD
% @Last Modified time: 2021-01-10 04:42:59
-module(getAccDataCons).
-behaviour(gen_server).
-include_lib("deps/amqp_client/include/amqp_client.hrl").
-export([start_link/0, stop/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3,
terminate/2]).
-export([get_account/0]).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
stop() ->
gen_server:cast(?MODULE, stop).
get_account() ->
gen_server:call(?MODULE, {get_account}).
init(_Args) ->
{ok, Connection} = amqp_connection:start(#amqp_params_network{host = "localhost"}),
{ok, Channel} = amqp_connection:open_channel(Connection),
{ok, Channel}.
handle_call({get_account}, _From, State) ->
amqp_channel:call(State, #'exchange.declare'{exchange = <<"get">>, type = <<"topic">>}),
amqp_channel:call(State, #'queue.declare'{queue = <<"get_account">>}),
Binding =
#'queue.bind'{exchange = <<"get">>,
routing_key = <<"get.account">>,
queue = <<"get_account">>},
#'queue.bind_ok'{} = amqp_channel:call(State, Binding),
io:format(" [*] Waiting for logs. To exit press CTRL+C~n"),
amqp_channel:call(State,#'basic.consume'{queue = <<"get_account">>, no_ack = true}),
Returned =loop(),
io:format("~nReti=~p",[Returned]),
{reply, Returned, State};
handle_call(Message, _From, State) ->
io:format("received other handle_call message: ~p~n", [Message]),
{reply, ok, State}.
handle_cast(stop, State) ->
{stop, normal, State};
handle_cast(Message, State) ->
io:format("received other handle_cast call : ~p~n", [Message]),
{noreply, State}.
handle_info(Message, State) ->
io:format("received handle_info message : ~p~n", [Message]),
{noreply, State}.
code_change(_OldVer, State, _Extra) ->
{ok, State}.
terminate(Reason, _State) ->
io:format("server is terminating with reason :~p~n", [Reason]).
loop()->
receive
#'basic.consume_ok'{} -> ok
end,
receive
{#'basic.deliver'{}, Msg} ->
#amqp_msg{payload = Payload} = Msg,
Value=loop2(Payload),
Value
after 2000->
io:format("Server timeout")
end.
loop2(Payload)->
Result = jiffy:decode(Payload),
{[{<<"account_id">>, AccountId}]} = Result,
Doc = {[{<<"account_id">>, AccountId}]},
getAccDataDb:create_AccountId_view(),
Returned=case getAccDataDb:getAccountNameDetails(Doc) of
success ->
Respo = getAccDataDb:getAccountNameDetails1(Doc),
Respo;
details_not_matched ->
user_not_exist
end,
Returned.
2条答案
按热度按时间66bbxpm51#
太长,无法编辑,我将其放入新答案中。
发生超时时接收
ok
的原因在loop()
代码中,在第二个receive块中,2000 ms后,在io:format/1
语句之后立即返回。io:format
返回ok
,它是您在Returned变量中得到的。使用此代码,您的客户端将收到
{ok,Value}
或{error,timeout}
,并能够做出相应的React。但这个版本仍然存在一些问题:-2秒超时可能太短,您错过了有效答案-由于您在接收块中使用模式匹配,并且没有检查每个
amqp_channel:call
的结果,因此可能会出现许多不同的问题,并显示为超时首先让我们看看超时。有可能对
amqp_channel
的4次调用总共需要超过2秒才能成功完成。简单的解决方案是增加超时,将after 2000
更改为after 3000
或更多。但这样会有两个问题:gen_server提供了一些接口函数来解决这类问题:'send_request','wait_response'和reply.下面是一个基本的gen_server,它可以处理3种请求:
服务器模块实现多个用户界面:
最后它包括2个测试功能
代码如下
shell中的会话:
请求无法完成的下一个原因是其中一个amqp_channel:调用失败。根据您想做的事情,有几种可能性:什么都不做、让崩溃、捕获异常或管理所有情况。下一个建议使用全局捕获
客户端应如下所示:
webghufk2#
如果没有
loop
和loop2
代码,很难给予答案,如果这两个函数中的一个检测到超时,您必须首先更改它们的行为以避免任何超时,或者将其增加到一个有效的值。如果超时是必要的,则确保返回值是显式的,例如{error,RequestRef,timeout}
而不是ok
。不过
gen_server
不应等待太长时间才得到答案,您可以修改代码,执行以下操作:在客户端进程中不使用
gen_server:call(ServerRef,Request)
,而可以用途:删除
loop
和/或loop2
中的超时,这样你就可以控制客户端的超时,甚至可以将其设置为无穷大(这不是一个好主意!)也可以将函数拆分为两部分
和更高版本,或在另一个客户端进程中(这需要至少将
RequestRef
传递到此进程)检查请求的结果:最后,您必须修改循环代码以处理
RequestRef
,向服务器发回一条消息(再次使用gen_server:cast
),其中包含结果和RequestRef
,并将此结果存储在服务器状态中。我不认为这第二个解决方案是有价值的,因为它或多或少与第一个相同,但手工制作,它让您管理许多错误情况(如客户端死亡),可能最终成为一种内存泄漏。