Ruby script service (systemd + rvm + user privileges)

Introduction

The script for GPS log created by Use soft UART with Raspberry Pi 3 is unexpectedly unstable, so it restarts even if the program ends with an exception. Try using systemd like this.

Premise

--rvm environment --Make ruby script a service with user privileges --Use systemd

Goal

--Restart even if the GPS log script fails due to an unexpected error

See the official documentation for rvm

The following official page was created by Gugu, but I didn't understand it because it was too rough to explain, so I tried it by groping.

https://rvm.io/deployment/init-d

This procedure should also work with cron etc. (I haven't tried it: sweat_drops :)

procedure

The basic procedure is as follows.

--Create a wrapper for rvm --Create a systemd Unit definition file --Execute the script via wrapper with ExecStart

Make a wrapper for rvm

First, check the path of rmv.

[email protected]:~ $ echo $rvm_path
/home/pi/.rvm

A new Gem set in wrappers under that path? I will create it, so I will look at it first just in case.

[email protected]:~ $ ll ~/.rvm/wrappers/
total 0
lrwxrwxrwx 1 pi pi 33 Jul 18 16:22 default -> /home/pi/.rvm/wrappers/ruby-2.7.1
lrwxrwxrwx 1 pi pi 38 Jul 18 16:22 ruby-2.7.1 -> /home/pi/.rvm/gems/ruby-2.7.1/wrappers
lrwxrwxrwx 1 pi pi 45 Jul 18 16:22 [email protected] -> /home/pi/.rvm/gems/[email protected]/wrappers

Create a Gem set with the following command. This time I created it with the name gps. I matched it with the official description, but I don't understand why it is necessary to specify gps and two app names ...

[email protected]:~ $ rvm alias create gps [email protected]
Gemset 'gps' does not exist, 'rvm ruby-2.7.1 do rvm gemset create gps' first, or append '--create'.
Creating alias gps for ruby-2.7.1.....

I get an error as expected, but let's say that I was able to create it properly as follows: sweat_smile:

[email protected]:~ $ ll ~/.rvm/wrappers/
total 0
lrwxrwxrwx 1 pi pi 33 Jul 18 16:22 default -> /home/pi/.rvm/wrappers/ruby-2.7.1
lrwxrwxrwx 1 pi pi 33 Jul 19 20:01 gps -> /home/pi/.rvm/wrappers/ruby-2.7.1
lrwxrwxrwx 1 pi pi 38 Jul 18 16:22 ruby-2.7.1 -> /home/pi/.rvm/gems/ruby-2.7.1/wrappers
lrwxrwxrwx 1 pi pi 45 Jul 18 16:22 [email protected] -> /home/pi/.rvm/gems/[email protected]/wrappers

Create a systemd Unit definition file

All you have to do is create it as usual. The contents of this time are as follows. In WorkingDirectory, specify the directory where the script is located, and in ʻExecStart, execute the bundle command via wrapper. Restart = always` is important: relaxed:

[email protected]:~ $ cat /etc/systemd/system/gps.service
[Unit]
Description=Gps Service
After=network.target

[Service]
Type=simple
User=pi
Group=pi
WorkingDirectory=/home/pi/project/gps
ExecStart=/home/pi/.rvm/wrappers/gps/bundle exe ruby main.rb
Restart=always

[Install]
WantedBy=multi-user.target

Modify the script a little

I tried to put in a process that falls with a logger and an exception in the defeat work.

require 'serialport'
require 'nmea_plus'
require 'logger'

logger = Logger.new('gps.log')

logger.info 'It started'

puts `sudo rmmod soft_uart.ko`
sleep 0.1
puts `cd ~/project/soft_uart && sudo insmod soft_uart.ko`

sp = SerialPort.new('/dev/ttySOFT0', 9600, 8, 1, 0) # see: https://rubydoc.info/gems/serialport/SerialPort#set_modem_params-instance_method

trap 'SIGINT' do
  sp.close if sp
  exit
end

count = 0

source_decorder = NMEAPlus::SourceDecoder.new(sp)
source_decorder.each_complete_message do |message|
  #count up
  count +=1

  # see: https://github.com/ianfixes/nmea_plus/blob/master/lib/nmea_plus/message/nmea/rmc.rb
  if 'GPRMC' == message.data_type
    logger.info message.utc_time
    logger.info message.active? # false:Data invalid
    logger.info message.latitude
    logger.info message.longitude
    logger.info message.faa_mode # A:Independent positioning(Accuracy about 3m), D:Relative positioning(Accuracy 0.About 4m) 
  end

  if count >= 10
    sp.close #I will close it for the time being
    logger.error 'I'll drop it'
    raise 'Forcible error' 
  end
end

I will check

First, reload systemd itself and then start the service.

sudo systemctl daemon-reload
sudo systemctl start gps.service

The log is ... nice! This makes the unstable script a little stronger.

[email protected]:~ $ tail -f ./project/gps/gps.log
I, [2020-07-19T20:59:05.521956 #6437]  INFO -- :It started
I, [2020-07-19T20:59:06.651867 #6437]  INFO -- : 2020-07-19 11:59:06 +0000
I, [2020-07-19T20:59:06.652419 #6437]  INFO -- : true
I, [2020-07-19T20:59:06.652937 #6437]  INFO -- : 33.725631666666665
I, [2020-07-19T20:59:06.653450 #6437]  INFO -- : 131.64383833333332
I, [2020-07-19T20:59:06.654003 #6437]  INFO -- : A
I, [2020-07-19T20:59:07.652485 #6437]  INFO -- : 2020-07-19 11:59:07 +0000
I, [2020-07-19T20:59:07.653032 #6437]  INFO -- : true
I, [2020-07-19T20:59:07.653515 #6437]  INFO -- : 33.725631666666665
I, [2020-07-19T20:59:07.654019 #6437]  INFO -- : 131.64384
I, [2020-07-19T20:59:07.654624 #6437]  INFO -- : A
E, [2020-07-19T20:59:07.694013 #6437] ERROR -- :I'll drop it
I, [2020-07-19T20:59:12.530348 #6460]  INFO -- :It started
I, [2020-07-19T20:59:13.660674 #6460]  INFO -- : 2020-07-19 11:59:13 +0000
I, [2020-07-19T20:59:13.661174 #6460]  INFO -- : true
I, [2020-07-19T20:59:13.661502 #6460]  INFO -- : 33.72563
I, [2020-07-19T20:59:13.661792 #6460]  INFO -- : 131.64383666666666
I, [2020-07-19T20:59:13.662027 #6460]  INFO -- : A
I, [2020-07-19T20:59:14.660078 #6460]  INFO -- : 2020-07-19 11:59:14 +0000
I, [2020-07-19T20:59:14.660613 #6460]  INFO -- : true
I, [2020-07-19T20:59:14.660962 #6460]  INFO -- : 33.72562833333333
I, [2020-07-19T20:59:14.661288 #6460]  INFO -- : 131.64383666666666
I, [2020-07-19T20:59:14.661528 #6460]  INFO -- : A
E, [2020-07-19T20:59:14.662166 #6460] ERROR -- :I'll drop it

Impressions

--Which is easier, rbenv or rvm, to make the script a service? ――The official documentation is too rough to understand ...

Recommended Posts

Ruby script service (systemd + rvm + user privileges)