Erlang init_per_group terminates gen_server - erlang

Common test init_per_group/2 terminates gen_server when it is started with gen_server:start_link.
But it is ok to start server with gen_server:start.
gen_server can be started with any of these methods (start and start_link) in init_per_suite/1 and init_per_testcase/2.
Why it is not possible to start gen_server in init_per_group/2 with gen_server:start_link?

This happens because init_per_group is run in a separate process, just like each test case, and that process exits with an exit reason that communicates information about success/failure of group initialisation. From test_server:run_test_case_eval:
exit({Ref,Time,Value,Loc,Opts}).
Since the gen_server is linked to the process that runs init_per_group, and since the exit reason is not normal and the gen_server is not trapping exits, the gen_server process exits with that same exit reason.
On the other hand, init_per_testcase is run in the same process as the test case itself, so this problem does not appear.

Related

How can I stop other application in gen_server:terminate/2?

I'm making my own server with erlang OTP and I stuck in the problem when I use Mnesia.
I start Mnesia in gen_server:init/1 of my worker and stop it in gen_server:terminate/2 of the same worker.
Unfortunately, When function mnesia:stop/0 is called by calling application:stop(myApplication) or init:stop(), the application stucks and ends up with this :
=SUPERVISOR REPORT==== 23-Jun-2021::16:54:12.048000 ===
supervisor: {local,temp_sup}
errorContext: shutdown_error
reason: killed
offender: [{pid,<0.159.0>},
{id,myMnesiaTest_sup},
{mfargs,{myMnesiaTest_sup,start_link,[]}},
{restart_type,permanent},
{shutdown,10000},
{child_type,supervisor}]
Of course, this doesn't happen when gen_server:terminate/2 isn't called by setting trap_exit flag as false, but Mnesia also doesn't stop.
I don't know why an application cannot be stopped in other application and want to know it's ok if I don't call mnesia:stop() in the end of my application.
The reason you cannot stop Mnesia when your application is stopping is that at that time the application_controller process is busy with stopping your application. This is a classic deadlock situation when one gen_server (in this case quite indirectly) performs a synchronous call to an other gen_server which in turn wants to do a synchronous call to the first one.
You can break the deadlock by asynchronously shutting down Mnesia after your application stopped. Try calling from your terminate/2 timer:apply_after(0, mnesia, stop, []) for example. (Just spawning a process to do the call is not ideal, it would still belong to your application and would get killed when the application terminates.)
But most of the time you don't really have to bother with stopping Mnesia. Erlang applications by convention leave their dependencies started when stopped. And in case your application is terminated by init:stop(), it will take care of stopping all other applications anyway, including Mnesia.

How do you hook to an application in Erlang

I do not understand how do you hook to an Erlang application since it does not return the Pid.
Consider for example the snippet below.I am starting a Pid which receives messages to process.However my application behaviour does not return anything.
How do i hook to the Pid i am interested in when using application behaviour ?
.app
{
application,simple_app,
[
{description,"something"},
{mod,{simple_app,[]}},
{modules,[proc]}
]
}
app
-module(simple_app).
-behaviour(application).
-export([start/2, stop/1]).
start(_StartType, _StartArgs) ->
proc:start().
stop(_State) ->
ok.
module
-module(proc).
-export([start/0]).
start()->
Pid=spawn_link(?MODULE,loop,[]),
{ok,Pid}.
loop()->
receive
{From,Message}-> From ! {ok,Message},
loop();
_ ->loop()
end.
P.S I am trying to understand how do i get the root Pid to further use it to issue commands ? In my case i need the Pid of the proc:start module.If my root was a supervisor , i would need the Pid of the supervisor.The application does not return a Pid? How do i hook to it ?
The question thus is when starting the application wouldn't i need a Pid returned by it to then be able to issue commands against?
Your application must depend on kernel and stdlib. You should define their names in your .app file, for example:
{
application,simple_app,
[
{description,"something"},
{mod,{simple_app,[]}},
{modules,[proc]},
{applications, [kernel, stdlib]}
]
}
When you want to start your app, you should use the application module which is part of the kernel application.
It starts some processes to manage your application and I/O handling. It calls YOUR_APP:start(_, _) and this function MUST return a Pid which is running the supervisor behaviour. We often call it the root supervisor of app.
So you have to define an application behaviour (as you did) and a supervisor behaviour.
This supervisor process may start your workers which are doing anything your app wants to do.
If you want to start a process, you define its start specification in your supervisor module. So kernel starts your app and your app starts your supervisor and your supervisor starts your worker(s).
You can register your worker pid with a name and you can send it messages by using its name.
If you have lots of workers you can use a pool of pids which maintains your worker pids.
I think it's OK to play with spawn and spawn_link and sending messages manually to processes. But in production code we usually don't do this. We use OTP behaviours and they do this for us in a reliable and clean manner.
I think it's better to write some gen_servers (another behaviour) and play with handle_call and handle_cast, etc callbacks. Then run some gen_servers under a supervision tree and play with the supervisor API to kill or terminate its children, etc. Then start writing a complete application.
Remember to read the documentation for behaviours carefully.

How to spawn a Erlang process dynamically for one activity and kill it once activity done

There are many parallel requests coming to one erlang OTP (gen_server) process.
One process is not sufficient to handle this.
I can have fix number pool of same processes to handle this using Poolboy or worker_pool.
But I dont want to have fix set of process pool.
I want to create dynamically Process to handle that activity and get killed once it done its work.
So I will be having N numbers of active process for N parallel request.
and than it get killed once that process complete the processing.
How I can achieve this?
Use Erlang supervisor module and use transient in its flags.
When your event comes, start new child for doing that and when event done, exit process with reason 'normal'.
Supervisor behavior info: Design - API

Otp application:stop(..) kills all spawned processes, not just spawn_linked ones?

I've set up a simple test-case at https://github.com/bvdeenen/otp_super_nukes_all that shows that an otp application:stop() actually kills all spawned processes by its children, even the ones that are not linked.
The test-case consists of one gen_server (registered as par) spawning a plain erlang process (registered as par_worker) and a gen_server (registered as reg_child), which also spawns a plain erlang process (registered as child_worker). Calling application:stop(test_app) does a normal termination on the 'par' gen_server, but an exit(kill) on all others!
Is this nominal behaviour? If so, where is it documented, and can I disable it? I want the processes I spawn from my gen_server (not link), to stay alive when the application terminates.
Thanks
Bart van Deenen
The application manual says (for the stop/1 function):
Last, the application master itself terminates. Note that all processes with the
application master as group leader, i.e. processes spawned from a process belonging
to the application, thus are terminated as well.
So I guess you cant modify this behavior.
EDIT: You might be able to change the group_leader of the started process with group_leader(GroupLeader, Pid) -> true (see: http://www.erlang.org/doc/man/erlang.html#group_leader-2). Changing the group_leader might allow you to avoid killing your process when the application ends.
I made that mistakes too, and found out it must happen.
If parent process dies, all children process dies no matter what it is registered or not.
If this does not happen, we have to track all up-and-running processes and figure out which is orphaned and which is not. you can guess how difficult it would be. You can think of unix ppid and pid. if you kill ppid, all children dies too. This, I think this must happen.
If you want to have processes independent from your application, you can send a messageto other application to start processes.
other_application_module:start_process(ProcessInfo).

delphi JvCreateProcess1: how to send keys

I run an invisible DOS process thanks to JvCreateProcess component; that works fine.
I need to stop this process by CTRL+C and not by JvCreateProcess1.terminate (or send CTRL+C sequence to JVCreateProcess)
Any idea ?
regards
You can do this:
GenerateConsoleCtrlEvent(CTRL_C_EVENT, myProcessInfo.dwProcessId);
but there are some limitations:
You can only call GenerateConcolseCltrEvent from a process that shares its console with the process you are sending the Ctrl-C-Event to. If you need to catch the console output of the spawned process without it being intermingled with the console output of other spawned processes or the app spawning them, then you can't use this (directly, see below).
The process receiving the Ctrl-C-Event in this way will/may not terminate any processes that it spawned itself. (Possibly dependent on the process group settings and console sharing amongst those processes, I didn't check further into this at the time when I was contemplating Ctrl-C'ing a spawned process.)
If you need to send Ctrl-C from an app that does not share its console with the spawned process you are left with creating an intermediate process that does and telling that to terminate by some other means (pipes, COM, whatever) so it can send a ctrl-c to the actual process that you want to spawn and terminate by Ctrl-C.
More info on this, and how to go about creating an intermediate process, can be found here: http://www.microsoft.com/msj/0698/win320698.aspx

Resources