Skip to content

Beginner · Linux for DevOps · topic 7 of 53 · 30 min

Processes, signals and systemd services

Explanation

A process is a running program with an ID called the PID. You list processes with ps and top, stop them with kill (SIGTERM first, SIGKILL only if needed), and read exit codes where 0 means success. Long-running apps should be systemd services, managed with systemctl and read with journalctl, and you check server health with free, df, du and uptime.

What is a process?

A program is a file on disk. A process is that program while it is running, with its own memory and a unique number called the PID (process ID). Running the same program twice makes two processes with two PIDs. Every process has a parent; the first process (PID 1) on most modern Linux systems is systemd.

bash
ps aux                     # every process: user, PID, %CPU, %MEM, command
ps aux | grep nginx        # just the nginx processes
pgrep -a node              # PIDs and command lines of node processes
top                        # live view, sorted by CPU (press M to sort by memory, q to quit)
htop                       # a friendlier top, if installed
Finding processes. In ps aux, the second column is the PID.

Signals: asking a process to stop

A signal is a short message the kernel delivers to a process. kill sends signals, despite its name.

SignalNumberMeaning
SIGTERM15Please stop. The default for kill. The app can finish requests, save data and exit cleanly.
SIGKILL9Stop now. The kernel ends the process; it cannot catch or ignore this, and gets no chance to clean up.
SIGINT2Interrupt, what Ctrl+C sends.
SIGHUP1Hang up. Many daemons, such as nginx, reload their config on SIGHUP.
bash
kill 4321          # send SIGTERM (15) to PID 4321
kill -9 4321       # send SIGKILL, only if SIGTERM did not work
pkill -f "node server.js"   # signal processes by command line
Always try a normal kill first.
Careful: Common mistake: using kill -9 first. SIGKILL gives the app no chance to finish writing a file or a database transaction, which can corrupt data or lose orders. Send SIGTERM, wait a few seconds, and use -9 only if the process is truly stuck. Kubernetes does the same: it sends SIGTERM, waits a grace period, then SIGKILL.

Exit codes

When a process ends, it returns an exit code (exit status). 0 means success; anything from 1 to 255 means some kind of failure. CI pipelines rely on this: if any command exits with non-zero, the step fails. Some codes are worth remembering: 127 means "command not found", and 128 plus a signal number means "killed by that signal", so 137 is 128 + 9 (SIGKILL, often the out-of-memory killer in containers) and 130 is 128 + 2 (Ctrl+C).

bash
ls /nope
echo $?            # prints 2: ls failed
true; echo $?      # prints 0
$? holds the exit code of the last command.

Foreground and background

A command normally runs in the foreground: the shell waits for it. Add & to run it in the background and get the prompt back. jobs lists background jobs, fg brings one back, and Ctrl+Z pauses the current job (bg resumes it in the background). If you log out, background jobs usually die. nohup keeps a command running after logout, but for real services use systemd instead.

bash
nohup ./import-data.sh > import.log 2>&1 &
jobs
fg %1
Run a one-off long job that survives logout, with output saved to a file.

systemd services

systemd is the service manager on almost all modern distributions. A unit file describes a service: what to run, as which user, and what to do if it crashes. systemd starts it at boot, restarts it on failure and collects its logs.

ini
# /etc/systemd/system/orders-api.service
[Unit]
Description=Orders API
After=network.target

[Service]
User=deploy
WorkingDirectory=/opt/orders-api
ExecStart=/usr/bin/node server.js
Environment=NODE_ENV=production
Restart=on-failure

[Install]
WantedBy=multi-user.target
A simple unit file. Restart=on-failure brings the app back if it crashes.
bash
sudo systemctl daemon-reload            # after creating or editing a unit file
sudo systemctl enable --now orders-api  # start now AND at every boot
sudo systemctl status orders-api        # running? since when? last log lines
sudo systemctl restart orders-api       # after a deploy
sudo systemctl stop orders-api
journalctl -u orders-api -f             # follow this service's logs
journalctl -u orders-api --since "1 hour ago"
The systemctl and journalctl commands you will use most.
Tip: enable and start are different. start runs the service now; enable makes it start at boot. A classic mistake is starting a service, seeing it work, and finding it missing after the next reboot. enable --now does both.

Checking resources

bash
free -h        # memory: total, used, available
df -h          # disk space per filesystem
du -sh /var/log/*   # size of each item in /var/log
uptime         # time since boot and load average
nproc          # number of CPU cores
The first five commands to run when a server feels slow.

uptime shows three load averages, for the last 1, 5 and 15 minutes. Load is roughly the number of processes running or waiting to run. Compare it with the number of cores from nproc: a load of 4 on a 4-core server means the CPUs are fully busy; a load of 12 on 4 cores means work is queuing up.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Processes, signals and systemd services · 1/8

Process = running program PID = its ID

A process is a running program, and each one has a number called the PID.

Prefer a video by a teacher? Find free videos on “linux processes signals systemctl journalctl tutorial” on YouTube ↗

In real life: A ticket API that disappears after reboot

A bus-ticket startup runs its API with nohup on a cloud VM. After the provider reboots the VM for maintenance at 3 am, the API is down until someone notices at 9 am. The fix is a systemd unit with Restart=on-failure, enabled with systemctl enable --now. A week later the app crashes because of a bug; systemd restarts it in seconds and journalctl -u shows the stack trace for the developers.

Practice (0/3 done)

Task 1 · Question

A process does not stop after "kill 2201". What is the reasonable next step?

Task 2 · Code · Python

ps aux prints a header line, then one line per process with 11 columns: USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND. The COMMAND column can contain spaces. Write top_memory(ps_text) that returns a tuple (pid, command) for the process with the highest %MEM, where pid is an int and command is the full command string. Skip the header and blank lines.

Task 3 · Practice

Write a systemd unit file for a Python web app at /opt/notes/app.py that must run as the user notes, start after the network is up, restart if it crashes, and start at boot. Then list the commands to install it, start it, check it and follow its logs.

Quick quiz

Question 1

1.What exit code means a command succeeded?

Question 2

2.A container keeps exiting with code 137. What does that usually mean?

Question 3

3.You started a service with systemctl start, but after a reboot it is not running. What did you forget?

Question 4

4.Which command shows the logs of the service orders-api and keeps following new lines?

Question 5

5.A 4-core server shows a load average of 11.5, 10.8, 9.9. What does this suggest?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What exit code means a command succeeded?

Answer: 0

0 is success. Any non-zero code is a failure; 127 means command not found.

A container keeps exiting with code 137. What does that usually mean?

Answer: The process was killed with SIGKILL, often for using too much memory

137 = 128 + 9, so the process received SIGKILL, commonly from the out-of-memory killer.

You started a service with systemctl start, but after a reboot it is not running. What did you forget?

Answer: systemctl enable

start runs it now; enable makes it start at boot.

Which command shows the logs of the service orders-api and keeps following new lines?

Answer: journalctl -u orders-api -f

journalctl -u selects the unit and -f follows new entries.

A 4-core server shows a load average of 11.5, 10.8, 9.9. What does this suggest?

Answer: Far more work is waiting than the CPUs can handle

A load well above the number of cores means processes are queuing for CPU (or stuck waiting on I/O).

Which command continues a stopped job in the background?Related

Answer: bg

bg resumes a stopped job in the background.

From Processes: ps, top and jobs

What does Ctrl+C send to the foreground process?Related

Answer: SIGINT

Ctrl+C sends SIGINT (2).

From Signals, kill and process priority

A service shows "active" and "disabled". What happens after a reboot?Related

Answer: It does not start

Disabled means it is not started at boot.

From systemd services and systemctl

Which command lists services by how long they took to start?Related

Answer: systemd-analyze blame

blame sorts units by start-up time.

From The boot process, step by step

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Linux for DevOps” before its exam: Bash scripting, text tools and cron, Linux networking for DevOps.
  2. Module 2 exam: Linux for DevOps · 13 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Git in depth. 53 topics left in the course before the final exam.

← Previous: Users, groups and permissions