Skip to main content

Systemd Services

This document describes the background services that are managed by systemd in the Tracker GraphQL application.

Overview

The application uses several background services that run continuously to perform various tasks:

  1. Location History Refresher: Refreshes the location_history materialized view when new data is available
  2. Geofence Processing: Processes location history to update tracker statuses based on geofences
  3. Status Change Notifier: Notifies clients about tracker status changes via Socket.IO

These services are managed by systemd, which ensures they start automatically on system boot and restart if they fail.

Location History Refresher

The Location History Refresher service performs two key functions:

  1. Listens for PostgreSQL notifications and refreshes the location_history materialized view when new data is available
  2. Periodically refreshes the continuous aggregates (at most once per hour) using Redis-based distributed locking

Service File

[Unit]
Description=Location History Refresher Service
After=network.target postgresql.service redis.service

[Service]
User=paulb
Group=paulb
WorkingDirectory=/home/paulb/scripts/tracker-graphql-2
ExecStart=/home/paulb/scripts/tracker-graphql-2/.venv/bin/python /home/paulb/scripts/tracker-graphql-2/app/src/location_history_refresher.py
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=location-history-refresher
Environment="REDIS_HOST=localhost"
Environment="REDIS_PORT=6379"
Environment="REDIS_USERNAME="
Environment="REDIS_PASSWORD="
Environment="REDIS_SSL=false"
Environment="REDIS_DB=0"

# Hardening
ProtectSystem=full
PrivateTmp=true
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

Docker Compose

The service can also be run using Docker Compose:

services:
location-history-refresher:
build:
context: ./build
dockerfile: Dockerfile
image: tracker-services:latest
command: refresher
restart: unless-stopped
environment:
- DB_HOST=${DB_HOST:-postgres}
- DB_PORT=${DB_PORT:-5432}
- DB_NAME=${DB_NAME:-postgres}
- DB_USER=${DB_USER:-postgres}
- DB_PASSWORD=${DB_PASSWORD:-postgres}
- REDIS_HOST=${REDIS_HOST:-redis}
- REDIS_PORT=${REDIS_PORT:-6379}
- REDIS_USERNAME=${REDIS_USERNAME:-}
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
- REDIS_SSL=${REDIS_SSL:-}
- REDIS_DB=${REDIS_DB:-0}
deploy:
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s

Installation

Systemd Installation

# Copy the systemd service file to the systemd directory
sudo cp systemd/location-history-refresher.service /etc/systemd/system/

# Reload systemd to recognize the new service
sudo systemctl daemon-reload

# Enable and start the service
sudo systemctl enable location-history-refresher
sudo systemctl start location-history-refresher

Docker Compose Installation

# Navigate to the fetcher directory
cd fetcher

# Start the services
docker-compose up -d

Geofence Processing

The Geofence Processing service periodically processes location history to update tracker statuses based on geofences.

Service File

[Unit]
Description=Geofence Processing Service
After=network.target

[Service]
User=paulb
WorkingDirectory=/home/paulb/scripts/tracker-graphql-2
ExecStart=/home/paulb/scripts/tracker-graphql-2/.venv/bin/python /home/paulb/scripts/tracker-graphql-2/app/src/process_geofences.py
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

Installation

# Copy the systemd service file to the systemd directory
sudo cp systemd/geofence-processing.service /etc/systemd/system/

# Reload systemd to recognize the new service
sudo systemctl daemon-reload

# Enable and start the service
sudo systemctl enable geofence-processing
sudo systemctl start geofence-processing

Status Change Notifier

The Status Change Notifier service listens for PostgreSQL notifications about tracker status changes and forwards them to connected clients via Socket.IO.

Service File

[Unit]
Description=Tracker Status Change Notifier
After=network.target

[Service]
User=tracker
WorkingDirectory=/home/paulb/scripts/tracker-graphql-2
ExecStart=/usr/bin/python3 app/src/status_change_notifier.py
Restart=always
RestartSec=5
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=status-change-notifier

[Install]
WantedBy=multi-user.target

Installation

# Copy the systemd service file to the systemd directory
sudo cp systemd/status-change-notifier.service /etc/systemd/system/

# Reload systemd to recognize the new service
sudo systemctl daemon-reload

# Enable and start the service
sudo systemctl enable status-change-notifier
sudo systemctl start status-change-notifier

Monitoring Services

Systemd Monitoring

You can monitor the status of these services using standard systemd commands:

# Check the status of a service
sudo systemctl status location-history-refresher

# View the logs for a service
sudo journalctl -u location-history-refresher -f

# Restart a service
sudo systemctl restart geofence-processing

# Stop a service
sudo systemctl stop status-change-notifier

Docker Compose Monitoring

For services running in Docker Compose:

# Check the status of all services
docker-compose -f fetcher/compose.yml ps

# View the logs for a specific service
docker-compose -f fetcher/compose.yml logs -f location-history-refresher

# Restart a service
docker-compose -f fetcher/compose.yml restart location-history-refresher

# Stop a service
docker-compose -f fetcher/compose.yml stop location-history-refresher

Redis Monitoring

For monitoring the Redis-based distributed locking:

# Connect to Redis CLI (standard)
redis-cli

# Connect to Redis CLI with authentication
redis-cli -h localhost -p 6379 -a your_password

# Connect to Redis CLI with username and password
redis-cli -h localhost -p 6379 -u your_username -a your_password

# Connect to Redis CLI with TLS (for AWS MemoryDB)
redis-cli -h your-cluster-endpoint.amazonaws.com --tls -u your_username -a your_password

# Check if Redis is running
ping

# View all keys related to location history refresher
keys location_history:*

# Check when the last aggregate refresh happened
get location_history:last_aggregate_refresh

# Check if a lock is currently held
exists location_history:aggregate_refresh_lock

Redis Cluster Support

When using AWS MemoryDB or other Redis Cluster deployments:

  • The system automatically detects Redis Cluster endpoints (containing "clustercfg" in the hostname)
  • It uses the appropriate Redis Cluster client
  • All keys use hash tags (e.g., {tracker}:pending) to ensure proper slot allocation

For detailed information about Redis Cluster support, including how we solved the CROSSSLOT error and ensured backward compatibility with standalone Redis, see Redis Cluster Support.

Troubleshooting

Service Won't Start

If a service won't start, check the logs:

# For systemd services
sudo journalctl -u service-name -f

# For Docker Compose services
docker-compose -f fetcher/compose.yml logs -f service-name

Common issues include:

  • Python path incorrect in the service file
  • Missing dependencies
  • Permission problems
  • Configuration errors
  • Redis connection issues (for the location-history-refresher)

Service Crashes Repeatedly

If a service crashes repeatedly:

  1. Check the logs for error messages
  2. Verify that the database is accessible
  3. Check that the required tables and functions exist
  4. Ensure that the service has the necessary permissions

Manual Testing

You can test the services manually by running the Python scripts directly:

# Activate the virtual environment
source .venv/bin/activate

# Run the location history refresher
python app/src/location_history_refresher.py

# Run the geofence processing
python app/src/process_geofences.py

# Run the status change notifier
python app/src/status_change_notifier.py

For Docker-based services:

# Run the location history refresher
docker-compose -f fetcher/compose.yml run --rm location-history-refresher

# Run the tracker report fetcher with options
docker-compose -f fetcher/compose.yml run --rm tracker-report-fetcher fetcher --once

This can help identify issues that might be related to the configuration rather than the scripts themselves.

Continuous Aggregate Refresh Issues

If the continuous aggregates aren't being refreshed:

  1. Check if Redis is running and accessible:

    redis-cli ping
  2. Check the Redis keys related to the refresh lock:

    redis-cli keys "location_history:*"
  3. Manually refresh the continuous aggregates:

    -- In PostgreSQL
    CALL refresh_continuous_aggregate('location_history_hourly', NOW() - INTERVAL '48 hours', NOW());
    CALL refresh_continuous_aggregate('location_history_daily', NOW() - INTERVAL '7 days', NOW());
  4. Check the logs for any errors related to Redis:

    # For systemd
    sudo journalctl -u location-history-refresher -f | grep -i redis

    # For Docker
    docker-compose -f fetcher/compose.yml logs -f location-history-refresher | grep -i redis