Skip to content

Restart Services

Restarts all receiver and output services in the system. This operation reinitializes device receivers and outputs based on the current configuration, allowing changes to take effect without a full system restart.

Request

http
GET /api/restart-services

Authentication Required: Must include JWT token in Authorization header.

Required Scope: restart_services

Content-Type: Not required (no request body)

Request Examples

Basic Service Restart

bash
curl -X GET "http://your-server-ip:port/api/restart-services" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN"

Using JavaScript

javascript
const response = await fetch('/api/restart-services', {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

Response

Success (200 OK)

json
{
  "success": true
}

Error Responses

Note: Error responses are returned as plain text, not JSON (unlike most other endpoints).

401 Unauthorized

NOT_LOGGED_IN

403 Forbidden

FORBIDDEN

405 Method Not Allowed

Method Not Allowed

Service Restart Process

What Gets Restarted

The restart operation affects:

  1. Receiver Services: All configured device receivers are stopped and restarted
  2. Output Services: All configured output modules are stopped and restarted
  3. Configuration Reload: Current system configuration is reloaded during restart
  4. Connection Re-establishment: Device connections are re-established with new settings

When to Use Service Restart

Common Use Cases:

  • After modifying receiver or output configuration
  • When device communication issues occur
  • After changing network settings that affect device connectivity
  • To apply configuration changes without full system restart
  • During maintenance procedures

Configuration Changes That Require Restart:

  • Receiver settings modifications
  • Output module configuration changes
  • Network interface changes
  • Device communication parameters
  • Protocol settings updates

Usage Examples

Basic Service Restart

javascript
async function restartServices(token) {
  try {
    const response = await fetch('/api/restart-services', {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${token}`
      }
    });
    
    if (!response.ok) {
      // Handle plain text error responses
      const errorText = await response.text();
      throw new Error(`HTTP ${response.status}: ${errorText}`);
    }
    
    const result = await response.json();
    console.log('Services restarted successfully');
    return result;
  } catch (error) {
    console.error('Failed to restart services:', error);
    throw error;
  }
}

Service Management Class

javascript
class ServiceManager {
  constructor(token) {
    this.token = token;
  }
  
  async restartServices() {
    console.log('Initiating service restart...');
    
    try {
      const response = await fetch('/api/restart-services', {
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${this.token}`
        }
      });
      
      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`Restart failed: ${errorText}`);
      }
      
      const result = await response.json();
      console.log('✓ All services restarted successfully');
      return result;
      
    } catch (error) {
      console.error('✗ Service restart failed:', error.message);
      throw error;
    }
  }
  
  async restartWithStatusCheck(maxWaitTime = 30000) {
    console.log('Restarting services with status monitoring...');
    
    // Initiate restart
    await this.restartServices();
    
    // Wait for services to stabilize
    const startTime = Date.now();
    let servicesReady = false;
    
    while (!servicesReady && (Date.now() - startTime) < maxWaitTime) {
      try {
        // Check if services are responding
        const statusResponse = await fetch('/api/status', {
          headers: { 'Authorization': `Bearer ${this.token}` }
        });
        
        if (statusResponse.ok) {
          const status = await statusResponse.json();
          // Check if essential services are running
          if (status.database_ready && status.services_ready) {
            servicesReady = true;
            console.log('✓ Services are ready and responding');
          }
        }
      } catch (statusError) {
        // Services might still be restarting
        console.log('Services still restarting...');
      }
      
      if (!servicesReady) {
        await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds
      }
    }
    
    if (!servicesReady) {
      console.warn('⚠ Services restart completed, but status check timed out');
    }
    
    return servicesReady;
  }
}

// Usage
const serviceManager = new ServiceManager(authToken);

// Simple restart
await serviceManager.restartServices();

// Restart with status monitoring
const ready = await serviceManager.restartWithStatusCheck();

Configuration Change Workflow

javascript
class ConfigurationManager {
  constructor(token) {
    this.token = token;
    this.serviceManager = new ServiceManager(token);
  }
  
  async updateConfigurationAndRestart(newSettings) {
    console.log('Updating configuration and restarting services...');
    
    try {
      // Step 1: Update settings
      console.log('1. Updating system settings...');
      const settingsResponse = await fetch('/api/settings', {
        method: 'PUT',
        headers: {
          'Authorization': `Bearer ${this.token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(newSettings)
      });
      
      if (!settingsResponse.ok) {
        throw new Error('Failed to update settings');
      }
      
      console.log('✓ Settings updated successfully');
      
      // Step 2: Restart services to apply changes
      console.log('2. Restarting services to apply changes...');
      await this.serviceManager.restartServices();
      
      // Step 3: Verify services are running
      console.log('3. Verifying services are operational...');
      const ready = await this.serviceManager.restartWithStatusCheck();
      
      if (ready) {
        console.log('✓ Configuration update completed successfully');
        return { success: true, message: 'Configuration updated and services restarted' };
      } else {
        console.warn('⚠ Configuration updated but service status unclear');
        return { success: true, message: 'Configuration updated, please verify service status' };
      }
      
    } catch (error) {
      console.error('✗ Configuration update failed:', error.message);
      throw error;
    }
  }
}

// Usage
const configManager = new ConfigurationManager(authToken);

const newSettings = {
  receivers: {
    // Updated receiver configuration
  },
  outputs: {
    // Updated output configuration
  }
};

await configManager.updateConfigurationAndRestart(newSettings);

Maintenance Workflow

javascript
class MaintenanceManager {
  constructor(token) {
    this.token = token;
    this.serviceManager = new ServiceManager(token);
  }
  
  async performMaintenanceRestart(reason = 'Scheduled maintenance') {
    const startTime = new Date();
    console.log(`Starting maintenance restart: ${reason}`);
    
    try {
      // Log maintenance start
      await this.logMaintenanceEvent('restart_start', reason, startTime);
      
      // Perform restart
      await this.serviceManager.restartServices();
      
      // Verify services
      const ready = await this.serviceManager.restartWithStatusCheck(45000); // 45 second timeout
      
      const endTime = new Date();
      const duration = endTime - startTime;
      
      // Log maintenance completion
      await this.logMaintenanceEvent('restart_complete', reason, endTime, duration, ready);
      
      return {
        success: true,
        duration: duration,
        servicesReady: ready,
        startTime: startTime,
        endTime: endTime
      };
      
    } catch (error) {
      const endTime = new Date();
      const duration = endTime - startTime;
      
      // Log maintenance failure
      await this.logMaintenanceEvent('restart_failed', reason, endTime, duration, false, error.message);
      
      throw error;
    }
  }
  
  async logMaintenanceEvent(event, reason, timestamp, duration = null, success = null, error = null) {
    const logEntry = {
      timestamp: timestamp.toISOString(),
      event: event,
      reason: reason,
      duration: duration,
      success: success,
      error: error,
      user: this.getCurrentUser()
    };
    
    console.log('MAINTENANCE_LOG:', JSON.stringify(logEntry));
    
    // Send to audit/logging service
    try {
      await fetch('/api/maintenance/log', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(logEntry)
      });
    } catch (logError) {
      console.error('Failed to log maintenance event:', logError);
    }
  }
  
  getCurrentUser() {
    try {
      const token = localStorage.getItem('authToken');
      const payload = JSON.parse(atob(token.split('.')[1]));
      return payload.username || payload.sub;
    } catch {
      return 'unknown';
    }
  }
}

// Usage
const maintenanceManager = new MaintenanceManager(authToken);

// Scheduled maintenance restart
await maintenanceManager.performMaintenanceRestart('Weekly scheduled restart');

// Emergency restart
await maintenanceManager.performMaintenanceRestart('Emergency restart due to communication issues');

Error Handling and Retry Logic

javascript
class RestartServiceManager {
  constructor(token, maxRetries = 3, retryDelay = 5000) {
    this.token = token;
    this.maxRetries = maxRetries;
    this.retryDelay = retryDelay;
  }
  
  async restartServicesWithRetry() {
    let lastError;
    
    for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
      try {
        console.log(`Restart attempt ${attempt}/${this.maxRetries}...`);
        
        const response = await fetch('/api/restart-services', {
          method: 'GET',
          headers: {
            'Authorization': `Bearer ${this.token}`
          }
        });
        
        if (!response.ok) {
          const errorText = await response.text();
          throw new Error(`HTTP ${response.status}: ${errorText}`);
        }
        
        const result = await response.json();
        console.log(`✓ Services restarted successfully on attempt ${attempt}`);
        return result;
        
      } catch (error) {
        lastError = error;
        console.error(`✗ Restart attempt ${attempt} failed:`, error.message);
        
        if (attempt < this.maxRetries) {
          console.log(`Waiting ${this.retryDelay}ms before retry...`);
          await new Promise(resolve => setTimeout(resolve, this.retryDelay));
        }
      }
    }
    
    throw new Error(`All ${this.maxRetries} restart attempts failed. Last error: ${lastError.message}`);
  }
  
  async handleRestartErrors(error) {
    if (error.message.includes('NOT_LOGGED_IN')) {
      throw new Error('Authentication expired. Please log in again.');
    } else if (error.message.includes('FORBIDDEN')) {
      throw new Error('Insufficient permissions. restart_services scope required.');
    } else if (error.message.includes('Method Not Allowed')) {
      throw new Error('Invalid request method. Use GET for restart endpoint.');
    } else {
      throw new Error(`Service restart failed: ${error.message}`);
    }
  }
}

// Usage with retry logic
const restartManager = new RestartServiceManager(authToken, 3, 10000);

try {
  await restartManager.restartServicesWithRetry();
  console.log('Services restarted successfully');
} catch (error) {
  await restartManager.handleRestartErrors(error);
}

Integration with Monitoring

javascript
class ServiceRestartMonitor {
  constructor(token) {
    this.token = token;
    this.restartHistory = [];
  }
  
  async monitoredRestart(reason) {
    const restartEvent = {
      id: Date.now(),
      reason: reason,
      startTime: new Date(),
      status: 'in_progress'
    };
    
    this.restartHistory.push(restartEvent);
    
    try {
      // Capture pre-restart status
      const preStatus = await this.getSystemStatus();
      restartEvent.preRestartStatus = preStatus;
      
      // Perform restart
      console.log(`Starting monitored restart: ${reason}`);
      const response = await fetch('/api/restart-services', {
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${this.token}`
        }
      });
      
      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(errorText);
      }
      
      const result = await response.json();
      
      // Wait for services to stabilize
      await new Promise(resolve => setTimeout(resolve, 5000));
      
      // Capture post-restart status
      const postStatus = await this.getSystemStatus();
      
      // Update restart event
      restartEvent.endTime = new Date();
      restartEvent.duration = restartEvent.endTime - restartEvent.startTime;
      restartEvent.status = 'completed';
      restartEvent.postRestartStatus = postStatus;
      restartEvent.success = true;
      
      console.log(`✓ Monitored restart completed in ${restartEvent.duration}ms`);
      return restartEvent;
      
    } catch (error) {
      restartEvent.endTime = new Date();
      restartEvent.duration = restartEvent.endTime - restartEvent.startTime;
      restartEvent.status = 'failed';
      restartEvent.error = error.message;
      restartEvent.success = false;
      
      console.error(`✗ Monitored restart failed:`, error.message);
      throw error;
    }
  }
  
  async getSystemStatus() {
    try {
      const response = await fetch('/api/status', {
        headers: { 'Authorization': `Bearer ${this.token}` }
      });
      
      if (response.ok) {
        return await response.json();
      }
    } catch (error) {
      console.warn('Could not fetch system status:', error.message);
    }
    
    return null;
  }
  
  getRestartHistory() {
    return this.restartHistory;
  }
  
  getLastRestart() {
    return this.restartHistory[this.restartHistory.length - 1];
  }
}

// Usage
const restartMonitor = new ServiceRestartMonitor(authToken);

// Perform monitored restart
const restartEvent = await restartMonitor.monitoredRestart('Configuration update');

// Check restart history
const history = restartMonitor.getRestartHistory();
console.log('Recent restarts:', history);

Security Considerations

Access Control

  • Scope Required: Users must have the restart_services scope
  • Admin Privilege: Service restart should typically be restricted to administrators
  • Audit Logging: All restart operations should be logged for security audit

Service Availability

  • Planned Maintenance: Use during scheduled maintenance windows when possible
  • Impact Assessment: Consider impact on connected devices and active operations
  • Recovery Planning: Have rollback procedures in case of restart issues

Monitoring and Alerting

javascript
async function secureServiceRestart(token, reason, userContext) {
  // Validate user permissions
  const userScopes = getUserScopes(token);
  if (!userScopes.includes('restart_services')) {
    throw new Error('Insufficient permissions for service restart');
  }
  
  // Log restart initiation for audit
  await auditLog({
    action: 'service_restart_initiated',
    user: userContext.username,
    reason: reason,
    timestamp: new Date().toISOString()
  });
  
  try {
    // Perform restart
    const result = await restartServices(token);
    
    // Log successful restart
    await auditLog({
      action: 'service_restart_completed',
      user: userContext.username,
      reason: reason,
      success: true,
      timestamp: new Date().toISOString()
    });
    
    return result;
  } catch (error) {
    // Log failed restart
    await auditLog({
      action: 'service_restart_failed',
      user: userContext.username,
      reason: reason,
      success: false,
      error: error.message,
      timestamp: new Date().toISOString()
    });
    
    throw error;
  }
}

Important Notes

  • Scope Required: Users must have the restart_services scope to access this endpoint
  • Error Format: Unlike most endpoints, errors are returned as plain text, not JSON
  • Service Interruption: Brief service interruption occurs during restart process
  • Configuration Reload: Current configuration is reloaded and applied during restart
  • Connection Re-establishment: Device connections are re-established after restart
  • No Request Body: This is a GET request with no request body required
  • Timeout Considerations: Service restart may take time to complete
  • Status Verification: Consider checking system status after restart to verify services are operational
  • Maintenance Planning: Use during planned maintenance windows to minimize operational impact

Released under the MIT License.