Przejdź do treści

📦 Service Wrappers Recipes

Service wrappers provide a standardized way to manage applications as system services, handling startup, shutdown, logging, and monitoring. This recipe offers patterns for creating robust service wrappers across different init systems.


🎯 Core Principles

Universal Service Wrapper Framework

Create portable service wrappers that work across different systems.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#!/bin/bash
# service-wrapper.sh - Universal service wrapper framework

# Service configuration
SERVICE_NAME=""
SERVICE_DESCRIPTION=""
SERVICE_USER=""
SERVICE_GROUP=""
SERVICE_PIDFILE=""
SERVICE_LOGFILE=""
SERVICE_ERRFILE=""
SERVICE_WORKDIR=""
SERVICE_EXECUTABLE=""
SERVICE_ARGS=""

# Runtime configuration
SERVICE_DAEMONIZE=true
SERVICE_RESTART_ON_FAILURE=true
SERVICE_RESTART_DELAY=5
SERVICE_MAX_RESTARTS=10
SERVICE_TIMEOUT=30

# Internal state
SERVICE_PID=0
SERVICE_RESTART_COUNT=0

# Logging functions
log_info() {
    local message="$1"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] [$SERVICE_NAME] $message" | tee -a "${SERVICE_LOGFILE:-/dev/null}"
}

log_error() {
    local message="$1"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] [$SERVICE_NAME] $message" | tee -a "${SERVICE_ERRFILE:-/dev/null}" >&2
}

log_debug() {
    if [ "${SERVICE_DEBUG:-false}" = "true" ]; then
        local message="$1"
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] [DEBUG] [$SERVICE_NAME] $message" | tee -a "${SERVICE_LOGFILE:-/dev/null}"
    fi
}

# Configuration loading
load_service_config() {
    local config_file="$1"

    if [ -f "$config_file" ]; then
        log_debug "Loading configuration from $config_file"
        source "$config_file"
    else
        log_debug "Configuration file not found: $config_file"
    fi

    # Validate required configuration
    if [ -z "$SERVICE_NAME" ] || [ -z "$SERVICE_EXECUTABLE" ]; then
        log_error "SERVICE_NAME and SERVICE_EXECUTABLE are required"
        return 1
    fi

    # Set default values
    SERVICE_PIDFILE="${SERVICE_PIDFILE:-/var/run/$SERVICE_NAME.pid}"
    SERVICE_LOGFILE="${SERVICE_LOGFILE:-/var/log/$SERVICE_NAME.log}"
    SERVICE_ERRFILE="${SERVICE_ERRFILE:-/var/log/$SERVICE_NAME.err}"
    SERVICE_WORKDIR="${SERVICE_WORKDIR:-/}"

    # Create log directories
    mkdir -p "$(dirname "$SERVICE_PIDFILE")"
    mkdir -p "$(dirname "$SERVICE_LOGFILE")"
    mkdir -p "$(dirname "$SERVICE_ERRFILE")"

    return 0
}

# Process management
get_service_pid() {
    if [ -f "$SERVICE_PIDFILE" ]; then
        cat "$SERVICE_PIDFILE"
    else
        echo ""
    fi
}

is_service_running() {
    local pid
    pid=$(get_service_pid)

    if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
        return 0
    else
        return 1
    fi
}

# Signal handling
setup_signal_handlers() {
    trap 'handle_shutdown' INT TERM
    trap 'handle_reload' HUP
}

handle_shutdown() {
    log_info "Received shutdown signal"
    stop_service
    exit 0
}

handle_reload() {
    log_info "Received reload signal"
    reload_service
}

# Service operations
start_service() {
    if is_service_running; then
        log_info "Service is already running"
        return 0
    fi

    log_info "Starting service"

    # Change to working directory
    cd "$SERVICE_WORKDIR" || {
        log_error "Failed to change to working directory: $SERVICE_WORKDIR"
        return 1
    }

    # Prepare command
    local cmd="$SERVICE_EXECUTABLE"
    if [ -n "$SERVICE_ARGS" ]; then
        cmd="$cmd $SERVICE_ARGS"
    fi

    # Add PID file argument if supported
    if [ -n "$SERVICE_PIDFILE" ]; then
        cmd="$cmd --pidfile=$SERVICE_PIDFILE"
    fi

    log_debug "Executing: $cmd"

    # Execute service
    if [ "$SERVICE_DAEMONIZE" = true ]; then
        # Daemonize the process
        nohup $cmd >"$SERVICE_LOGFILE" 2>"$SERVICE_ERRFILE" &
        local pid=$!

        # Wait briefly for PID file creation
        sleep 2

        # Verify the process is still running
        if kill -0 "$pid" 2>/dev/null; then
            echo "$pid" > "$SERVICE_PIDFILE"
            log_info "Service started with PID: $pid"
            return 0
        else
            log_error "Service failed to start"
            return 1
        fi
    else
        # Run in foreground
        exec $cmd
    fi
}

stop_service() {
    log_info "Stopping service"

    local pid
    pid=$(get_service_pid)

    if [ -z "$pid" ]; then
        log_info "Service is not running"
        return 0
    fi

    # Send graceful shutdown signal
    if kill -TERM "$pid" 2>/dev/null; then
        log_debug "Sent TERM signal to PID $pid"

        # Wait for graceful shutdown
        local count=0
        while [ $count -lt $SERVICE_TIMEOUT ] && kill -0 "$pid" 2>/dev/null; do
            sleep 1
            count=$((count + 1))
        done

        # Force kill if still running
        if kill -0 "$pid" 2>/dev/null; then
            log_debug "Sending KILL signal to PID $pid"
            kill -KILL "$pid" 2>/dev/null
            sleep 1
        fi
    fi

    # Clean up PID file
    rm -f "$SERVICE_PIDFILE"

    log_info "Service stopped"
    return 0
}

restart_service() {
    log_info "Restarting service"
    stop_service
    sleep 2
    start_service
}

reload_service() {
    log_info "Reloading service"

    local pid
    pid=$(get_service_pid)

    if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
        kill -HUP "$pid" 2>/dev/null
        log_info "Reload signal sent to service"
        return 0
    else
        log_error "Service is not running"
        return 1
    fi
}

status_service() {
    if is_service_running; then
        local pid
        pid=$(get_service_pid)
        log_info "Service is running with PID: $pid"
        return 0
    else
        log_info "Service is not running"
        return 1
    fi
}

# Health checking
check_service_health() {
    if ! is_service_running; then
        log_error "Service is not running"
        return 1
    fi

    # Service-specific health checks can be implemented here
    # This is a generic placeholder

    log_info "Service health check passed"
    return 0
}

# Supervised execution with restart logic
supervised_execution() {
    setup_signal_handlers

    while true; do
        if ! is_service_running; then
            if [ "$SERVICE_RESTART_ON_FAILURE" = true ] && [ $SERVICE_RESTART_COUNT -lt $SERVICE_MAX_RESTARTS ]; then
                SERVICE_RESTART_COUNT=$((SERVICE_RESTART_COUNT + 1))
                log_info "Restarting service (attempt $SERVICE_RESTART_COUNT/$SERVICE_MAX_RESTARTS)"

                start_service
                if [ $? -ne 0 ]; then
                    log_error "Service failed to start"
                    sleep $SERVICE_RESTART_DELAY
                    continue
                fi

                log_info "Service restarted successfully"
            elif [ $SERVICE_RESTART_COUNT -ge $SERVICE_MAX_RESTARTS ]; then
                log_error "Maximum restart attempts reached ($SERVICE_MAX_RESTARTS)"
                exit 1
            else
                log_info "Service stopped normally"
                exit 0
            fi
        fi

        # Check health periodically
        sleep 30
        check_service_health
    done
}

🔧 Systemd Service Integration

Creating Systemd Service Units

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# systemd-wrapper.sh - Systemd integration for service wrappers

# Generate systemd service unit file
generate_systemd_unit() {
    local service_name="$1"
    local wrapper_script="$2"
    local unit_file="/etc/systemd/system/$service_name.service"

    cat > "$unit_file" << EOF
[Unit]
Description=$SERVICE_DESCRIPTION
After=network.target

[Service]
Type=forking
User=$SERVICE_USER
Group=$SERVICE_GROUP
WorkingDirectory=$SERVICE_WORKDIR

ExecStart=$wrapper_script start
ExecStop=$wrapper_script stop
ExecReload=$wrapper_script reload

PIDFile=$SERVICE_PIDFILE
Restart=on-failure
RestartSec=5

StandardOutput=journal
StandardError=journal
SyslogIdentifier=$SERVICE_NAME

Environment=SERVICE_CONFIG=/etc/$SERVICE_NAME/config

[Install]
WantedBy=multi-user.target
EOF

    log_info "Generated systemd unit file: $unit_file"

    # Reload systemd daemon
    systemctl daemon-reload

    return 0
}

# Systemd-aware service wrapper
systemd_service_wrapper() {
    local action="$1"

    case "$action" in
        start)
            if [ -n "$NOTIFY_SOCKET" ]; then
                log_debug "Running under systemd"
                # Notify systemd when ready
                start_service
                local result=$?
                if [ $result -eq 0 ]; then
                    systemd-notify --ready
                fi
                return $result
            else
                start_service
            fi
            ;;
        stop)
            stop_service
            ;;
        restart)
            restart_service
            ;;
        reload)
            reload_service
            ;;
        status)
            status_service
            ;;
        supervise)
            supervised_execution
            ;;
        *)
            echo "Usage: $0 {start|stop|restart|reload|status|supervise}" >&2
            return 1
            ;;
    esac
}

📦 Init Script Integration

SysV Init Script Wrapper

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# init-wrapper.sh - SysV init script integration

# Generate init script
generate_init_script() {
    local service_name="$1"
    local wrapper_script="$2"
    local init_script="/etc/init.d/$service_name"

    cat > "$init_script" << 'EOF'
#!/bin/bash
### BEGIN INIT INFO
# Provides:          SERVICE_NAME
# Required-Start:    $local_fs $network $named $time $syslog
# Required-Stop:     $local_fs $network $named $time $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Description:       SERVICE_DESCRIPTION
### END INIT INFO

WRAPPER_SCRIPT="WRAPPER_SCRIPT_PATH"
LOCK_FILE="/var/lock/subsys/SERVICE_NAME"

# Source function library
if [ -f /etc/rc.d/init.d/functions ]; then
    . /etc/rc.d/init.d/functions
fi

start() {
    echo -n "Starting SERVICE_NAME: "
    if [ -f "$LOCK_FILE" ]; then
        echo "already running"
        return 0
    fi

    $WRAPPER_SCRIPT start
    if [ $? -eq 0 ]; then
        touch "$LOCK_FILE"
        echo "OK"
        return 0
    else
        echo "FAILED"
        return 1
    fi
}

stop() {
    echo -n "Stopping SERVICE_NAME: "
    if [ ! -f "$LOCK_FILE" ]; then
        echo "not running"
        return 0
    fi

    $WRAPPER_SCRIPT stop
    if [ $? -eq 0 ]; then
        rm -f "$LOCK_FILE"
        echo "OK"
        return 0
    else
        echo "FAILED"
        return 1
    fi
}

restart() {
    stop
    start
}

reload() {
    echo -n "Reloading SERVICE_NAME: "
    $WRAPPER_SCRIPT reload
    if [ $? -eq 0 ]; then
        echo "OK"
        return 0
    else
        echo "FAILED"
        return 1
    fi
}

status() {
    $WRAPPER_SCRIPT status
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        restart
        ;;
    reload)
        reload
        ;;
    status)
        status
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|reload|status}"
        exit 1
        ;;
esac

exit $?
EOF

    # Customize the script
    sed -i "s/SERVICE_NAME/$service_name/g" "$init_script"
    sed -i "s|WRAPPER_SCRIPT_PATH|$wrapper_script|g" "$init_script"
    sed -i "s/SERVICE_DESCRIPTION/$SERVICE_DESCRIPTION/g" "$init_script"

    # Make executable
    chmod +x "$init_script"

    # Add to default runlevels
    if command -v chkconfig >/dev/null 2>&1; then
        chkconfig --add "$service_name"
        chkconfig "$service_name" on
    elif command -v update-rc.d >/dev/null 2>&1; then
        update-rc.d "$service_name" defaults
    fi

    log_info "Generated init script: $init_script"
    return 0
}

🔄 Service Monitoring and Management

Advanced Service Management Features

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# service-monitor.sh - Advanced service monitoring and management

# Resource monitoring
monitor_service_resources() {
    local pid
    pid=$(get_service_pid)

    if [ -z "$pid" ] || ! kill -0 "$pid" 2>/dev/null; then
        return 1
    fi

    # Get resource usage
    local cpu_usage
    cpu_usage=$(ps -p "$pid" -o %cpu= 2>/dev/null | tr -d ' ')

    local memory_usage
    memory_usage=$(ps -p "$pid" -o %mem= 2>/dev/null | tr -d ' ')

    local memory_rss
    memory_rss=$(ps -p "$pid" -o rss= 2>/dev/null | tr -d ' ')

    log_debug "Resource usage - CPU: ${cpu_usage}%, Memory: ${memory_usage}%, RSS: ${memory_rss}KB"

    # Check thresholds
    local cpu_threshold="${SERVICE_CPU_THRESHOLD:-90}"
    local memory_threshold="${SERVICE_MEMORY_THRESHOLD:-90}"

    if [ -n "$cpu_usage" ] && [ "$(echo "$cpu_usage > $cpu_threshold" | bc 2>/dev/null)" = "1" ]; then
        log_error "CPU usage (${cpu_usage}%) exceeds threshold (${cpu_threshold}%)"
        return 1
    fi

    if [ -n "$memory_usage" ] && [ "$(echo "$memory_usage > $memory_threshold" | bc 2>/dev/null)" = "1" ]; then
        log_error "Memory usage (${memory_usage}%) exceeds threshold (${memory_threshold}%)"
        return 1
    fi

    return 0
}

# Log monitoring
monitor_service_logs() {
    local log_file="$SERVICE_LOGFILE"
    local error_patterns="$SERVICE_ERROR_PATTERNS"

    if [ ! -f "$log_file" ]; then
        return 0
    fi

    # Check for error patterns
    if [ -n "$error_patterns" ]; then
        IFS=',' read -ra patterns <<< "$error_patterns"
        for pattern in "${patterns[@]}"; do
            if tail -100 "$log_file" | grep -q "$pattern"; then
                log_error "Error pattern detected in logs: $pattern"
                return 1
            fi
        done
    fi

    return 0
}

# Health check with custom validation
custom_health_check() {
    local health_check_script="$SERVICE_HEALTH_CHECK"

    if [ -n "$health_check_script" ] && [ -x "$health_check_script" ]; then
        log_debug "Running custom health check: $health_check_script"

        if ! timeout 30 "$health_check_script"; then
            log_error "Custom health check failed: $health_check_script"
            return 1
        fi

        log_debug "Custom health check passed"
    fi

    return 0
}

# Automatic service restart based on conditions
conditional_restart() {
    local restart_conditions="$SERVICE_RESTART_CONDITIONS"

    if [ -z "$restart_conditions" ]; then
        return 0
    fi

    IFS=',' read -ra conditions <<< "$restart_conditions"
    for condition in "${conditions[@]}"; do
        case "$condition" in
            resource_exceeded)
                if ! monitor_service_resources; then
                    log_info "Restarting due to resource threshold exceeded"
                    restart_service
                    return 0
                fi
                ;;
            log_errors)
                if ! monitor_service_logs; then
                    log_info "Restarting due to log errors detected"
                    restart_service
                    return 0
                fi
                ;;
            custom_check)
                if ! custom_health_check; then
                    log_info "Restarting due to custom health check failure"
                    restart_service
                    return 0
                fi
                ;;
        esac
    done

    return 0
}

# Service supervisor with monitoring
enhanced_supervisor() {
    setup_signal_handlers

    log_info "Starting enhanced supervisor"

    while true; do
        # Check if service should be running
        if ! is_service_running; then
            if [ "$SERVICE_RESTART_ON_FAILURE" = true ] && [ $SERVICE_RESTART_COUNT -lt $SERVICE_MAX_RESTARTS ]; then
                SERVICE_RESTART_COUNT=$((SERVICE_RESTART_COUNT + 1))
                log_info "Automatic restart (attempt $SERVICE_RESTART_COUNT/$SERVICE_MAX_RESTARTS)"

                start_service
                if [ $? -ne 0 ]; then
                    log_error "Service failed to start"
                    sleep $SERVICE_RESTART_DELAY
                    continue
                fi

                log_info "Service restarted successfully"
                SERVICE_RESTART_COUNT=0  # Reset on successful start
            elif [ $SERVICE_RESTART_COUNT -ge $SERVICE_MAX_RESTARTS ]; then
                log_error "Maximum restart attempts reached ($SERVICE_MAX_RESTARTS)"
                exit 1
            fi
        fi

        # Perform conditional checks
        conditional_restart

        # Sleep before next check
        sleep "${SERVICE_MONITOR_INTERVAL:-60}"
    done
}

🎨 Advanced Service Wrapper Features

Configuration Management and Templates

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
# config-management.sh - Service configuration management

# Generate configuration from template
generate_service_config() {
    local template_file="$1"
    local output_file="$2"

    if [ ! -f "$template_file" ]; then
        log_error "Template file not found: $template_file"
        return 1
    fi

    # Process template with environment variables
    envsubst < "$template_file" > "$output_file"

    # Set appropriate permissions
    chmod 644 "$output_file"

    log_info "Generated configuration file: $output_file"
    return 0
}

# Validate configuration
validate_service_config() {
    local config_file="$1"
    local validator_script="$2"

    if [ -n "$validator_script" ] && [ -x "$validator_script" ]; then
        log_debug "Validating configuration: $config_file"

        if ! "$validator_script" "$config_file"; then
            log_error "Configuration validation failed: $config_file"
            return 1
        fi

        log_debug "Configuration validation passed"
    fi

    return 0
}

# Backup configuration
backup_service_config() {
    local config_file="$1"
    local backup_dir="${2:-/var/backups}"

    if [ ! -f "$config_file" ]; then
        return 0
    fi

    mkdir -p "$backup_dir"

    local timestamp
    timestamp=$(date +%Y%m%d_%H%M%S)
    local backup_file="$backup_dir/$(basename "$config_file").$timestamp"

    cp "$config_file" "$backup_file"
    log_debug "Configuration backed up to: $backup_file"

    return 0
}

# Rotate configuration backups
rotate_config_backups() {
    local backup_dir="${1:-/var/backups}"
    local max_backups="${2:-10}"

    if [ ! -d "$backup_dir" ]; then
        return 0
    fi

    # Remove old backups
    find "$backup_dir" -name "*.conf.*" -type f | sort | head -n -$max_backups | xargs rm -f

    return 0
}

# Configuration hot reload
hot_reload_config() {
    local config_file="$1"

    # Backup current configuration
    backup_service_config "$config_file"

    # Validate new configuration
    if ! validate_service_config "$config_file"; then
        log_error "New configuration is invalid, restoring backup"
        # Restore from most recent backup
        local latest_backup
        latest_backup=$(find /var/backups -name "$(basename "$config_file").*" -type f | sort | tail -1)
        if [ -n "$latest_backup" ]; then
            cp "$latest_backup" "$config_file"
            log_info "Restored configuration from backup: $latest_backup"
        fi
        return 1
    fi

    # Trigger service reload
    reload_service

    # Rotate old backups
    rotate_config_backups

    log_info "Configuration hot reload completed"
    return 0
}

🧾 Summary Best Practices

Service Wrapper Guidelines

  1. Portability: Design wrappers to work across different init systems
  2. Process Management: Properly handle PID files and process lifecycle
  3. Signal Handling: Implement proper signal handling for graceful shutdown
  4. Logging: Centralize and structure service logs appropriately
  5. Monitoring: Include resource and health monitoring capabilities
  6. Configuration: Support flexible configuration management
  7. Security: Run services with appropriate user privileges
  8. Error Handling: Implement robust error handling and restart logic
  9. Documentation: Provide clear documentation for service operations
  10. Testing: Thoroughly test service wrapper functionality

Sample Service Configuration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# service-config-example.sh - Service configuration template

# Basic service information
export SERVICE_NAME="my-application"
export SERVICE_DESCRIPTION="My Application Service"
export SERVICE_USER="appuser"
export SERVICE_GROUP="appgroup"

# Executable and arguments
export SERVICE_EXECUTABLE="/opt/myapp/bin/myapp"
export SERVICE_ARGS="--config=/etc/myapp/config.conf --log-level=info"

# Paths and files
export SERVICE_WORKDIR="/opt/myapp"
export SERVICE_PIDFILE="/var/run/myapp.pid"
export SERVICE_LOGFILE="/var/log/myapp.log"
export SERVICE_ERRFILE="/var/log/myapp.err"

# Runtime behavior
export SERVICE_DAEMONIZE=true
export SERVICE_RESTART_ON_FAILURE=true
export SERVICE_RESTART_DELAY=10
export SERVICE_MAX_RESTARTS=5
export SERVICE_TIMEOUT=30

# Monitoring thresholds
export SERVICE_CPU_THRESHOLD=80
export SERVICE_MEMORY_THRESHOLD=80
export SERVICE_MONITOR_INTERVAL=60

# Health checking
export SERVICE_HEALTH_CHECK="/opt/myapp/bin/health-check.sh"
export SERVICE_ERROR_PATTERNS="ERROR,FATAL,Exception"

# Configuration management
export SERVICE_CONFIG_TEMPLATE="/etc/myapp/config.conf.template"
export SERVICE_CONFIG_VALIDATOR="/opt/myapp/bin/validate-config.sh"

🧠 Complete Service Wrapper Script

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/bin/bash
# complete-service-wrapper.sh - Production-ready service wrapper

set -euo pipefail

# Source all modules
source service-wrapper.sh
source systemd-wrapper.sh
source init-wrapper.sh
source service-monitor.sh
source config-management.sh

# Main service wrapper function
main() {
    local action="${1:-}"

    # Load configuration
    local config_file="${SERVICE_CONFIG:-/etc/$SERVICE_NAME/config}"
    if ! load_service_config "$config_file"; then
        exit 1
    fi

    # Execute requested action
    case "$action" in
        start)
            start_service
            ;;
        stop)
            stop_service
            ;;
        restart)
            restart_service
            ;;
        reload)
            reload_service
            ;;
        status)
            status_service
            ;;
        supervise)
            supervised_execution
            ;;
        enhanced-supervise)
            enhanced_supervisor
            ;;
        generate-systemd)
            generate_systemd_unit "$SERVICE_NAME" "$0"
            ;;
        generate-init)
            generate_init_script "$SERVICE_NAME" "$0"
            ;;
        check-health)
            check_service_health
            ;;
        monitor-resources)
            monitor_service_resources
            ;;
        hot-reload)
            local config_file="${2:-}"
            if [ -n "$config_file" ]; then
                hot_reload_config "$config_file"
            else
                echo "Usage: $0 hot-reload <config-file>" >&2
                exit 1
            fi
            ;;
        "")
            echo "Usage: $0 {start|stop|restart|reload|status|supervise|enhanced-supervise|generate-systemd|generate-init|check-health|monitor-resources|hot-reload}" >&2
            exit 1
            ;;
        *)
            # Pass to systemd-aware wrapper
            systemd_service_wrapper "$action"
            ;;
    esac
}

# Run main function
main "$@"

🧾 See Also