OvermindDL1

OvermindDL1

I created a new library (rather I pulled out a couple files from my big project), it manages an operating system PID file for the BEAM.

The reason you might want this it to make a ‘proper’ systemd management file or something, or just an easy way to identify the PID’s of your multiple BEAM processes (I have a lot of BEAM instances running for example, this is useful to figure out which is which).

It’s Hex URL: pid_file | Hex

It’s README.md:

PidFile

Manages a simple OS PID file for this BEAM system.

In other words it just makes a file whose sole contents is the Operating System PID of the running BEAM process.

It should also auto-clean old PID files on load, and clear the PID file on a ‘proper’ shutdown, but even if not a proper shutdown then it will still clear it properly next time.

Hex: pid_file | Hex

Installation

    {:pid_file, "~> 0.1.0"},

Setup

Global Config

Add one of these to your config for it to be managed globally, replacing the values as necessary:

config :pid_file, file: "./my_app.pid"
config :pid_file, file: {:SYSTEM, "PIDFILE"}

Locally Managed

Add the worker to your supervision tree:

worker(PidFile.Worker, [[file: "/run/my_app.pid"]])

Showing Posts 1 to 10

OvermindDL1

OvermindDL1 OP

Also, if it helps, I use this overlay to generate (via distillary) a systemd service file using this PID library:

[Unit]
Description=<%= description %>
After=network.target

[Service]<% full_dir = Path.absname(output_dir)%>
Type=forking
User=<%= deploy_user %>
Group=<%= deploy_group %>
WorkingDirectory=<%= full_dir %>
ExecStart=<%= full_dir %>/bin/<%= p_name %> start
ExecReload=<%= full_dir %>/bin/<%= p_name %> reload_config
ExecStop=<%= full_dir %>/bin/<%= p_name %> stop
PIDFile=<%= full_dir %>/<%= p_name %>.prod.pid
Restart=always
RestartSec=5
Environment=PORT=3000
Environment=LANG=en_US.UTF-8
SyslogIdentifier=<%= p_name %>

[Install]
WantedBy=multi-user.target

Been using it in production ever since migrated the server from Windows 2008 to redhat, so a couple weeks now without issue. This follows the proper systemd model using a PID file with proper restarts (tested it by manually telling the server to stop, killing it, kill -9’ing it, comes back up in 5 seconds every time).

brucepomeroy

brucepomeroy

Thanks for this! I’ve been trying to get systemd to restart my app if it crashes. I used your :pid_file package and it seems to be managing the pidfile correctly. I added the path to the pidfile to my systemd unit file. I can start and stop the app via systemd and the app starts automatically when the server starts but if I kill the app it doesn’t restart. Wondering if you have any suggestions on this. I start my app using systemd, then check the pidfile to get the pid (in this case it was 1645). then run kill 1645 the app stops and is not restarted. I checked the systemd logs using journalctl -u my_app.service and got the following output. Any thoughts? Thanks again!

Aug 22 11:01:25 ip-172-31-4-169 my_app[1682]: Starting up
Aug 22 11:01:26 ip-172-31-4-169 systemd[1]: my_app.service: Supervising process 1645 which is not our child. We'll most likely not notice when it exits.
Aug 22 11:01:26 ip-172-31-4-169 systemd[1]: Started my_app.
Aug 22 11:02:03 ip-172-31-4-169 run_erl[1644]: Erlang closed the connection.

I noticed in the last line of the log messages run_erl[1644], note 1644 is the app’s pid - 1. I also noticed the message “Supervising process 1645 which is not our child. We’ll most likely not notice when it exits”. I think this may be a clue. Is run_erl a process that “wraps” the app process? Maybe systemd interacts with run_erl rather than our app directly and therefore doesn’t notice if the app exits.

OvermindDL1

OvermindDL1 OP

Hmm I just kill -9 beam.smp here and it started back up after 5 seconds. Though I use the systemd service config file I displayed above.

Can you post the systemd service config file that you are using? And I bet the run_erl is pre-forking or something, as you can see I’m calling the release scripts directly.

brucepomeroy

brucepomeroy

Thanks for this. Yea I’m not too sure what the issue is. My server is ubuntu so I couldn’t use the exact command you used to kill it but I tried pkill -9 beam.smp and got the same results. Systemd reported that “Erlang closed the connection” and didn’t appear to attempt a restart. This is my conf file. Maybe I messed something up.

[Unit]
Description=My App
After=network.target

[Service]
Type=forking
User=my_app_deployer
Group=my_app_deployer
WorkingDirectory=/home/my_app_deployer/my_app/staging/my_app
ExecStart=/home/my_app_deployer/my_app/staging/my_app/bin/my_app start
ExecStop=/home/my_app_deployer/my_app/staging/my_app/bin/my_app stop
PIDFile=/home/my_app_deployer/my_app/staging/my_app/my_app.pid
Restart=always
RestartSec=5
EnvironmentFile=/home/my_app_deployer/.my_app_env
SyslogIdentifier=my_app
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Thanks again!

OvermindDL1

OvermindDL1 OP

Well first of all that should not be there. That means ‘pretend everything stays working even when the application closes’. Why do you have that there?! o.O

brucepomeroy

brucepomeroy

Nice. Thanks for your help @OvermindDL1. That was my problem. Removed that line and it’s working :grin:

I had it in there because i saw in the Distillery docs (https://hexdocs.pm/distillery/use-with-systemd.html#content) that “It’s important that you have RemainAfterExit=yes set, or you will get an error trying to start the service.” I didn’t give any thought to the effect that line would have. And contrary to the note in the docs I haven’t had trouble starting the service since removing that line.

Thanks again!

OvermindDL1

OvermindDL1 OP

Distillery does it wrong, I don’t know why they don’t do it right… ^.^;
Using Distillery’s instructions your service will not get restarted, which seems to defeat the point to me? ^.^

You are welcome! Nice to see others are using this too. :slight_smile:

Eiji

Eiji

@OvermindDL1: Just looked at your code - it’s simple and useful.
I don’t understand why your are calling:

:os.getpid() # charlist
|> to_string()
|> String.to_integer()
|> to_string()

i.e. update_pid/1 calls get_pid/0 that returns integer (from string) and you are changing it back to string. I could understand if it’s used in another function, but it’s not, so I’m little curious why you did it.

OvermindDL1

OvermindDL1 OP

:os.getpid() # charlist
|> to_string() # Convert charlist to string
|> String.to_integer() # convert string to integer to make sure it really is an integer or it throws, I needed this in some cases but don't recall where
|> to_string() # Convert it back to a string for later writing out

So yeah, I needed to ensure it was an integer at one point but don’t recall where, this code is old… >.>

aboroska

aboroska

Probably it is worth mentioning in this thread that it is common to supervise the VM via the built-in heart mechanism: heart — OTP 29.0.2 (kernel 11.0.2)

It works by starting a separate process called heart that not only checks if the beam process is still alive but also sends heartbeat messages to it (hence the name).

Of course if you use heart other restart mechanisms should not be in place. Also if you want to manually kill the VM you need to kill the heart process first, then the VM. Better option to stop the VM would be to call init:stop() from a remote node as described here for example: [erlang-questions] How to stop a detached OTP app?

The main advantage of the heart method is that it is OS independent.

Where Next? Top

Trending in Announcing Top

woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
woylie
I released Doggo, a collection of unstyled Phoenix components. https://github.com/woylie/doggo Features Unstyled Phoenix components....
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
anuaralfetahe
Hello Published a new library - ProcessHub! ProcessHub is a library designed to manage process distribution within the Elixir cluster. ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
sergio
It’s not that it’s vocabulary is too advanced. It’s something worse. I get lost trying to follow even a paragraph written by Claude. It’...
New
AstonJ
This showed up on my feed.. anyone heard of it? Just hype? Ox Alpha is a reasoning model designed for coding, sustained ag...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews