Packages
bpe
4.10.14
13.5.22-aleph
11.4.16
11.4.15
11.4.14
11.4.13
9.9.7
9.9.6
8.12.4
8.12.3
8.12.1
8.12.0
retired
8.2.1
8.2.0
8.1.0
7.11.0
7.10.4
7.10.3
7.10.2
7.10.1
7.9.1
7.9.0
7.8.2
7.8.1
7.8.0
7.6.4
7.6.3
7.6.2
7.6.1
7.6.0
7.5.15
7.5.14
7.5.13
7.5.12
7.5.11
7.5.10
7.5.9
7.5.8
7.5.7
7.5.6
7.5.5
7.5.3
7.5.2
7.5.1
7.5.0
7.4.11
7.4.10
7.4.9
7.4.8
7.4.7
7.4.6
7.4.5
7.4.4
7.4.3
7.4.2
7.4.1
7.4.0
7.3.0
7.2.8
7.2.7
7.2.6
7.1.6
7.1.5
7.1.4
7.1.3
7.1.2
6.12.7
6.12.6
6.12.5
6.12.3
6.12.2
6.12.1
6.12.0
6.11.0
6.10.0
6.5.3
6.5.2
6.5.1
6.5.0
6.4.0
6.3.0
5.12.0
5.11.4
5.11.3
5.11.2
5.11.1
5.11.0
5.8.7
5.8.6
5.8.5
5.8.4
5.8.3
5.8.2
5.8.1
5.8.0
5.7.0
5.6.0
5.5.2
5.5.1
5.4.0
5.2.0
5.1.3
5.1.2
5.1.1
4.12.4
4.12.3
4.12.2
4.12.1
4.12.0
4.11.8
4.11.7
4.11.6
4.11.5
4.11.4
4.11.3
4.11.2
4.11.1
4.11.0
4.10.24
4.10.23
4.10.22
4.10.21
4.10.20
4.10.19
4.10.18
4.10.17
4.10.16
4.10.15
4.10.14
4.10.13
4.10.12
4.10.11
4.10.10
4.10.9
4.10.8
4.10.7
4.10.6
4.10.5
4.10.4
4.10.3
4.10.2
4.10.1
4.10.0
4.9.18
4.9.17
4.9.16
4.9.15
4.9.14
4.9.13
4.9.12
4.9.11
4.9.10
4.9.9
4.9.8
4.9.7
4.9.6
4.9.5
4.9.4
4.9.3
4.9.2
4.9.1
4.9.0
4.8.1
4.8.0
4.7.5
4.7.3
4.7.2
4.7.1
4.7.0
4.6.0
2.4.0
0.7.16
ERP/1: RTP GST WebRTC ICE SDP H.264 H.265 MP4 MPEG-2 HLS HEVC
Current section
Files
Jump to
Current section
Files
src/bpe_proc.erl
-module(bpe_proc).
-author('Maxim Sokhatsky').
-include("bpe.hrl").
-include_lib("kvs/include/cursors.hrl").
-behaviour(gen_server).
-export([start_link/1]).
-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).
-compile(export_all).
start_link(Parameters) -> gen_server:start_link(?MODULE, Parameters, []).
debug(Proc,Name,Targets,Target,Status,Reason) ->
case application:get_env(bpe,debug,true) of
true -> logger:notice("BPE: ~p [~s:~s] ~p/~p ~p~n",
[Proc#process.id,Name,Target,Status,Reason,Targets]);
false -> skip end.
process_event(Event,Proc) ->
EventName = element(#messageEvent.name,Event),
Targets = bpe_task:targets(EventName,Proc),
{Status,{Reason,Target},ProcState} = bpe_event:handle_event(Event,bpe_task:find_flow(Targets),Proc),
bpe:trace(ProcState,[],calendar:local_time(),element(#messageEvent.name,Event)),
debug(ProcState,EventName,Targets,Target,Status,Reason),
fix_reply({Status,{Reason,Target},ProcState#process{task = Target}}).
process_task(Stage,Proc) -> process_task(Stage,Proc,false).
process_task(Stage,Proc,NoFlow) ->
Curr = Proc#process.task,
Task = bpe:step(Proc,Curr),
Targets = case NoFlow of
true -> noflow;
_ -> bpe_task:targets(Curr,Proc) end,
{Status,{Reason,Target},ProcState} =
case {Targets,Curr,Stage} of
{noflow,_,_} -> {reply,{complete,Curr},Proc};
{[],[],_} -> bpe_task:already_finished(Proc);
{[],Curr,_} -> bpe_task:handle_task(Task,Curr,Curr,Proc);
{[],_,_} -> bpe_task:denied_flow(Curr,Proc);
{List,_,[]} -> bpe_task:handle_task(Task,Curr,bpe_task:find_flow(Stage,List),Proc);
{List,_,_} -> {reply,{complete,bpe_task:find_flow(Stage,List)},Proc} end,
case (Status == stop) orelse (NoFlow == true) of
true -> [];
_ -> bpe:add_trace(ProcState,[],Target),
debug(ProcState,Curr,Targets,Target,Status,Reason) end,
fix_reply({Status,{Reason,Target},ProcState#process{task = Target}}).
fix_reply({stop,{Reason,Reply},State}) -> {stop,Reason,Reply,State};
fix_reply(P) -> P.
% BPMN 2.0 Инфотех
handle_call({get}, _,Proc) -> { reply,Proc,Proc };
handle_call({next}, _,Proc) -> try bpe:processFlow(Proc) catch X:Y:Z -> {reply,{error,'next/1',Z},Proc} end;
handle_call({next,Stage}, _,Proc) -> try bpe:processFlow(Stage,Proc) catch X:Y:Z -> {reply,{error,'next/2',Z},Proc} end;
handle_call({amend,Form}, _,Proc) -> try bpe:processFlow(bpe_env:append(env,Proc,Form)) catch X:Y:Z -> {reply,{error,'amend/2',Z},Proc} end;
handle_call({discard,Form}, _,Proc) -> try bpe:processFlow(bpe_env:remove(env,Proc,Form)) catch X:Y:Z -> {reply,{error,'discard/2',Z},Proc} end;
handle_call({event,Event}, _,Proc) -> try process_event(Event,Proc) catch X:Y:Z -> {reply,{error,'event/2',Z},Proc} end;
% BPMN 1.0 ПриватБанк
handle_call({complete}, _,Proc) -> try process_task([],Proc) catch X:Y:Z -> {reply,{error,'complete/1',Z},Proc} end;
handle_call({complete,Stage}, _,Proc) -> try process_task(Stage,Proc) catch X:Y:Z -> {reply,{error,'complete/2',Z},Proc} end;
handle_call({modify,Form,append},_,Proc) -> try process_task([],bpe_env:append(env,Proc,Form),true) catch X:Y:Z -> {reply,{error,'append/2',Z},Proc} end;
handle_call({modify,Form,remove},_,Proc) -> try process_task([],bpe_env:remove(env,Proc,Form),true) catch X:Y:Z -> {reply,{error,'remove/2',Z},Proc} end;
handle_call(Command,_,Proc) -> { reply,{unknown,Command},Proc }.
init(Process) ->
Proc = bpe:load(Process#process.id,Process),
logger:notice("BPE: ~p spawned as ~p~n",[Proc#process.id,self()]),
Till = bpe:till(calendar:local_time(), application:get_env(bpe,ttl,24*60*60)),
bpe:cache({process,Proc#process.id},self(),Till),
[ bpe:reg({messageEvent,element(1,EventRec),Proc#process.id}) || EventRec <- bpe:events(Proc) ],
{ok, Proc#process{timer=erlang:send_after(rand:uniform(10000),self(),{timer,ping})}}.
handle_cast(Msg, State) ->
logger:notice("Unknown API async: ~p.~n", [Msg]),
{stop, {error, {unknown_cast, Msg}}, State}.
timer_restart(Diff) -> {X,Y,Z} = Diff, erlang:send_after(500*(Z+60*Y+60*60*X),self(),{timer,ping}).
ping() -> application:get_env(bpe,ping,{0,0,5}).
handle_info({timer,ping}, State=#process{task=Task,timer=Timer,id=Id,events=Events,notifications=Pid}) ->
case Timer of [] -> skip; _ -> erlang:cancel_timer(Timer) end,
% search for '*' wildcard terminal event in process definition
Terminal = case lists:keytake('*',#messageEvent.name,Events) of
{value,Event,_} -> {'*',element(1,Event),element(#messageEvent.timeout,Event)};
false -> {'*',none,#timeout{spec={none,none}}} end, % forever if none is set
% search the events with the same name as current task, save event type and timeout
% if no event found then use timeout information from terminal event
{Name,Record,#timeout{spec={Days,Pattern}}} = case lists:keytake(Task,#messageEvent.name,Events) of
{value,Event2,_} -> {Task,element(1,Event2),element(#messageEvent.timeout,Event2)};
false -> Terminal end,
% calculate diff from past event
{DD,Diff} = case bpe:head(Id) of
#hist{time=#ts{time=Time1}} -> calendar:time_difference(Time1,calendar:local_time());
_ -> io:format("T~n"), {immediate,timeout} end,
% io:format("Ping: ~p, Task: ~p Hist: ~p~n", [Id,Task,bpe:head(Id)]),
case {{DD,Diff} < {Days,Pattern}, Record} of
{_,none} -> {noreply,State#process{timer=timer_restart(ping())}};
{true,_} -> {noreply,State#process{timer=timer_restart(ping())}};
{false,timeoutEvent} -> % perform auto-complete on timeoutEvents
logger:notice("BPE: ~p complete Timeout: ~p~n",[Id,{DD,Diff}]),
case process_task([],State) of
{reply,_,NewState} -> {noreply,NewState#process{timer=timer_restart(ping())}};
{stop,normal,_,NewState} -> {stop,normal,NewState} end;
{false,Record} -> logger:notice("BPE: ~p close ~p Timeout: ~p~n",[Id,Record,{DD,Diff}]),
case is_pid(Pid) of
true -> Pid ! {direct,{bpe,terminate,{Name,{Days,Pattern}}}};
false -> skip end,
bpe:cache({process,Id},undefined),
{stop,normal,State} end;
handle_info({'DOWN', _MonitorRef, _Type, _Object, _Info} = Msg, State = #process{id=Id}) ->
logger:notice(?MODULE, "connection closed, shutting down session: ~p.~n", [Msg]),
bpe:cache({process,Id},undefined),
{stop, normal, State};
handle_info(Info, State=#process{}) ->
logger:notice("Unrecognized info: ~p~n", [Info]),
{noreply, State}.
terminate(Reason, #process{id=Id}) ->
logger:notice("BPE: ~p terminate Reason: ~p~n", [Id,Reason]),
spawn(fun() -> supervisor:delete_child(bpe_otp,Id) end),
bpe:cache({process,Id},undefined),
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.