npm.io
1.3.3 • Published 3d agoCLI

farm-orchestrator

Licence
MIT
Version
1.3.3
Deps
60
Size
18.8 MB
Vulns
0
Weekly
0

@device-farm/hub

Hub package with PostgreSQL database support using Sequelize ORM.

Features

  • PostgreSQL database connection management
  • Sequelize ORM integration
  • Type-safe database configuration
  • Connection pooling
  • Model initialization support

Installation

Dependencies are managed at the root level. Run:

npm install

Usage

Basic Setup
import { Database, initializeModels } from '@device-farm/hub';

// Create database instance
const db = new Database({
  host: 'localhost',
  port: 5432,
  database: 'device_farm',
  username: 'postgres',
  password: 'password',
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000,
  },
  logging: console.log, // Optional: log SQL queries
});

// Initialize models
initializeModels(db.getSequelize());

// Connect to database
await db.connect();

// Sync models (development only - use migrations in production)
await db.sync({ alter: true });

// ... use your database connection

// Disconnect when done
await db.disconnect();
Creating Models

Create models in src/models/ directory:

import { Model, DataTypes, Sequelize } from 'sequelize';

export class User extends Model {
  public id!: number;
  public name!: string;
  public email!: string;
  public readonly createdAt!: Date;
  public readonly updatedAt!: Date;
}

export const initUser = (sequelize: Sequelize): typeof User => {
  User.init(
    {
      id: {
        type: DataTypes.INTEGER,
        autoIncrement: true,
        primaryKey: true,
      },
      name: {
        type: DataTypes.STRING,
        allowNull: false,
      },
      email: {
        type: DataTypes.STRING,
        allowNull: false,
        unique: true,
      },
    },
    {
      sequelize,
      modelName: 'User',
      tableName: 'users',
    }
  );

  return User;
};

Then register it in src/models/index.ts:

import { initUser } from './user';

export const initializeModels = (sequelize: Sequelize): void => {
  initUser(sequelize);
  // Add more models here
};

Configuration

Environment Variables

It's recommended to use environment variables for database configuration:

DB_HOST=localhost
DB_PORT=5432
DB_NAME=device_farm
DB_USER=postgres
DB_PASSWORD=your_password
DB_POOL_MAX=5
DB_POOL_MIN=0

Then use them in your code:

const db = new Database({
  host: process.env.DB_HOST || 'localhost',
  port: parseInt(process.env.DB_PORT || '5432', 10),
  database: process.env.DB_NAME || 'device_farm',
  username: process.env.DB_USER || 'postgres',
  password: process.env.DB_PASSWORD || '',
  pool: {
    max: parseInt(process.env.DB_POOL_MAX || '5', 10),
    min: parseInt(process.env.DB_POOL_MIN || '0', 10),
  },
});
WebDriver Session Path Configuration

The WebDriver session endpoint path is configurable. The webdriverSessionPath specifies the base path, and the router automatically appends /session to it. For example, if webdriverSessionPath is /wd/hub, the final endpoint will be /wd/hub/session.

You can set it via:

  1. Configuration File (hub.config.json):

    {
      "webdriverSessionPath": "/wd/hub"
    }
  2. CLI Arguments:

    npm run start -- --webdriver-session-path /custom/path
    # or short form:
    npm run start -- -w /custom/path
  3. Environment Variable:

    WEBDRIVER_SESSION_PATH=/wd/hub
  4. Custom Config File:

    npm run start -- --config /path/to/hub.config.json
    # or short form:
    npm run start -- -c /path/to/hub.config.json

Priority Order: Environment variables > CLI arguments > Config file > Default (/wd/hub)

Note: The router automatically appends /session to the configured path, so the default endpoint will be available at POST /wd/hub/session.

Prepare WDA Command (iOS)

The hub includes a command to build and sign WebDriverAgent (WDA) for iOS real device testing. This command:

  • Finds or builds WebDriverAgent from Appium
  • Signs it with a mobile provisioning profile
  • Creates a signed IPA file ready for deployment

Usage:

# Interactive mode (will prompt for provisioning profile)
npm run start -- prepare-wda

# With specific provisioning file
npm run start -- prepare-wda --mobile-provisioning-file /path/to/profile.mobileprovision

# With custom WDA project path
npm run start -- prepare-wda --wda-project-path /path/to/WebDriverAgent

# Specify platform (ios, tvos, or both)
npm run start -- prepare-wda --platform both

Options:

Option Short Description
--mobile-provisioning-file -m Path to the mobile provisioning file for signing
--wda-project-path -p Path to WebDriverAgent Xcode project
--platform Platform type: ios, tvos, or both (default: ios)

Requirements:

  • macOS with Xcode installed
  • Valid Apple Developer provisioning profile
  • Appium with XCUITest driver installed (for automatic WDA discovery)
Node Monitor Configuration

The hub includes a node monitor service that tracks node liveness by checking for heartbeat signals. This service acts as a backup mechanism to mark nodes as offline when WebSocket disconnect events don't fire properly.

Configuration Options

You can configure the node monitor using either a configuration file or environment variables:

1. Configuration File (hub.config.json):

{
  "nodeMonitor": {
    "checkInterval": 60000,
    "timeoutMs": 120000
  },
  "websocket": {
    "heartbeatInterval": 30000
  }
}

2. Environment Variables:

# Node monitor check interval (default: 60000ms = 60 seconds)
NODE_MONITOR_INTERVAL=60000

# Timeout before marking a node as offline (default: 120000ms = 2 minutes)
NODE_TIMEOUT_MS=120000

# WebSocket heartbeat interval (default: 30000ms = 30 seconds)
WEBSOCKET_HEARTBEAT_INTERVAL=30000

Priority Order: Environment variables > Config file > Default values

Configuration Parameters
  • checkInterval (default: 60000ms = 60 seconds)

    • How often the monitor checks for offline nodes (in milliseconds)
    • Lower values provide faster detection but increase database load
    • Recommended: 10-60 seconds
  • timeoutMs (default: 120000ms = 2 minutes)

    • How long a node can go without sending a heartbeat before being marked offline (in milliseconds)
    • Important: This must be greater than heartbeatInterval to avoid false positives
    • Recommended: At least 2x the heartbeatInterval value (e.g., if heartbeat is 30s, use 60s+ for timeout)
  • heartbeatInterval (default: 30000ms = 30 seconds)

    • How often the hub updates the last_heartbeat_at timestamp in the database (in milliseconds)
    • This is the interval at which the hub-side heartbeat mechanism runs
    • Lower values provide more frequent updates but increase database writes
    • Recommended: 20-60 seconds
How It Works
  1. Heartbeat Updates: When a node connects via WebSocket, the hub sets up a periodic heartbeat that updates the last_heartbeat_at field in the database every heartbeatInterval milliseconds.

  2. Offline Detection: The node monitor service runs every checkInterval milliseconds and checks for nodes that:

    • Are marked as is_online: true in the database
    • Have a last_heartbeat_at timestamp older than timeoutMs (or null)
  3. Automatic Cleanup: When a stale node is detected, the service:

    • Marks the node as is_online: false
    • Marks all devices for that node as not busy and inactive
Important Notes

Configuration Warning: If timeoutMs is set to a value less than heartbeatInterval, nodes will be incorrectly marked as offline before the next heartbeat arrives. The server will log a warning if this condition is detected.

Example Configuration:

{
  "nodeMonitor": {
    "checkInterval": 10000, // Check every 10 seconds
    "timeoutMs": 60000 // Mark offline after 60 seconds of no heartbeat
  },
  "websocket": {
    "heartbeatInterval": 30000 // Update heartbeat every 30 seconds
  }
}

This configuration ensures:

  • Heartbeats are updated every 30 seconds
  • The monitor checks for stale nodes every 10 seconds
  • Nodes are marked offline after 60 seconds (2x the heartbeat interval), providing a safety buffer

Development

# Build the package
npm run build

# Watch mode
npm run build:watch

# Type check
npm run typecheck

# Lint
npm run lint

Dependencies

  • sequelize: ORM for Node.js
  • pg: PostgreSQL client for Node.js
  • pg-hstore: Serialization/deserialization of hstore data type

Resources

Keywords