# CommandBox Service Manager

This module adds the ability for CommandBox to help you create and manage services for your CommandBox servers and Task Runners.

![](/files/-LmPZezBHX8kEt6SNgru)

## Supported OS's

* Windows&#x20;
* Linux (systemd)
* Mac


# Purchasing

This module is a commercial module by Ortus Solutions. You can purchase it here: <https://www.ortussolutions.com/products/commandbox-service-manager>

{% hint style="info" %}
Once purchased we will add your FORGEBOX user to the Service Manager package so you can install, update and use it.
{% endhint %}

##


# Installation

Once you have been granted access to the package on ForgeBox, you will be able to install the module from your CommandBox CLI. Check and make sure you are logged into the CLI with your ForgeBox account.

```
forgebox whoami
```

If you're not logged in, you can authenticate like so:

```
forgebox login
```

Now you're ready to install the Service Manager module!

```bash
install commandbox-service-manager@ortus
```

The module will be installed as a global/system CommandBox module. You can update all your system modules or just the service manager like so:

```bash
# Check and update all system dependencies
update --system
# Update only the service manager
update commandbox-service-manager@ortus --system

# List all system dependencies
list --system
# Check for oudated dependencies
outdated --system
```

## CommandBox Home Directory

The recommendation for specifying a CommandBox home directory using `commandbox.properties` will make service creation using CommandBox Service Manager straightforward. See the [CommandBox Installation](https://commandbox.ortusbooks.com/setup/installation) documentation for instructions on defining the CommandBox home directory.

The service creation must be performed as an administrator user. In a secured server environment, the administrator is not the user that will be running the CFML application. By specifying a pinned CommandBox home directory, the discrepancy between the administrator user's home directory and the CFML application user's home directory will be irrelevant. This configuration also allows the correct permissions to be applied to the CommandBox working files for all users executing CommandBox.


# Server Services

This module can be used to create an OS service for a given CommandBox Server.  This allows the server to start when your computer boots and be controlled by the operating system's service manager.  Each service will only control a single CommandBox server, but you can create as many as you like. &#x20;

The simplest form of this is to `cd` into the web root for a server and run this command:

```bash
server service create --start
```

This will create a service and start it for you.  Once you've created a service for a given server, use the service to start and stop the server.


# Usage

Here is an overview of the new commands this module adds into CommandBox for you.

```bash
server service create
server service remove
server service update
server service start
server service stop
server service restart
server service status
```

Each of the `server service XXX` commands above accept the same three parameters that every other server command accepts.

* `name` - The name of an existing server
* `directory` - The web root of an existing server
* `serverConfigFile` - The path to a `server.json` file. (name can actually be anything)

If you provide no params, by default, the commands will find the server in that directory. This is suitable for working with a single server in the current working directory. If you want to manage a service for another directory or you have more than one server defined, you can use the params above to be more specific.

#### `server service create`

Create a new service. To customize the service, pass params, set values in your `server.json` or set global config defaults. Use `--start` to also start the service after creating it.

{% hint style="warning" %}
Note: you must be using an **Administrator** user (Windows) or **root** (\*nix) to create services. You can start box as such, but keep in mind on \*nix, this changes your runtime user, and thus your CommandBox home.
{% endhint %}

#### `server service remove`

Remove an existing service. Does not affect the CommandBox server itself. Use `--force` to also stop the service if necessary.

#### `server service update`

Update an existing service. To customize the service, pass params, set values in your `server.json` or set global config defaults. Use `--force` to also stop the service if necessary. (Service will be restarted if it was originally running)

#### `server service start`

Start a service. Once you start a server via the service, you should also stop and start it via the service as well.

#### `server service stop`

Stop a service. Note, stopping a server directly with `server stop` instead of `server service stop` may cause the service to start again by itself if the `exitAction` is set to `restart`.

#### `server service restart`

Restart a service

#### `server service status`

Get status information for a service. Use `--verbose` to get additional information.

## CommandBox Home

CommandBox installs system modules and saves settings and servers into a `.CommandBox` folder inside the home directory of the current user running the `box` process.  For instance, a `brad` user on Windows and \*nix might have their CommandBox home in these locations:

```bash
C:/Users/brad/.Commandbox/
/home/brad/.CommandBox/
```

What happens when you run a Windows service as the "Local System" account (the default) or a Linux service as `root` (required to bind to ports below 1024) is the CommandBox home directory changes to match the new user that the process runs as. &#x20;

```bash
C:/Windows/System32/config/systemprofile/.CommandBox/
/root/.CommandBox/
```

This is unexpected and often times catches people off guard.  This "second" installation of CommandBox will not have your modules like [CFConfig](https://www.forgebox.io/view/commandbox-cfconfig) or [HostUpdater](https://www.forgebox.io/view/commandbox-hostupdater) installed, neither will it have any default config settings or servers present as all of this data is stored on a per-user basis. &#x20;

This can be made to work, but is undesirable since it prevents you from running `server start` inside CommandBox as yourself and getting the same results.  The easy fix is to lock all users into using the same CommandBox home dir.  To do this, choose a folder that has read/write permissions to all users who need to use CommandBox.  Then create a `commandbox.properties` file in the same directory as your `box` or `box.exe` binary.  Add a line defining a property called `commandbox_home` that points to the shared home dir.  Remember to either use forward slashes or escape all backslashes.

```bash
commandbox_home=E:\\CommandBox
or
commandbox_home=E:/CommandBox
or
commandbox_home=/opt/box/.CommandBox
```

This setting will take affect on your next run of `box` and a new, empty home will be created there.  if you wish, you can transfer all your settings, by stopping CommandBox and all servers, manually copying over the current `.CommandBox` folder to the new location first.  CommandBox will pick up the folder and use it if it's already there and everything inside is portable.


# Configuration

Each operating system may vary on which config items they choose to support.

You can provide configuration to the `server service create` and `server service update` commands as CLI parameters like so:

```bash
server service create startType=auto standardOutPath=logs/out.txt
```

Or you can put them in your `server.json` like so:

```bash
server set service.startType=auto
server set service.standardOutPath=logs/out.txt
```

Or you can set them as global defaults for all services like so:

```bash
config set server.defaults.service.startType=auto
config set server.defaults.service.standardOutPath=logs/out.txt
```

* **serviceName** - The name/ID of the service
* **displayName** - The human readable name of the service
* **description** - The description of the service
* **username** - The username to run as.  On Windows, format of `domain\user` or `machine\login`
* **password** - The password of the user above *(Windows only)*
* **startType** - one of the strings `auto`, `delayed`, `ondemand`, `disabled`
* **dependOnGroup** - An array of service groups that need started first.  Comma-delimited list when passed the CLI *(Windows only)*
* **dependOnService** - An array of other services that need started first.  Comma-delimited list when passed the CLI
* **processPriority** - One of the strings `realtime`, `high`, `aboveNormal`, `normal`, `belowNormal`, `idle` *(Windows only)*
* **CPUAffinity** - The string "all" or CPU IDs, starting from 0 such as "0-2,4" which would use the first, second, third, and 5th CPU core. *(Windows only)*
* **exitAction** - One of the strings `Restart`, `Ignore`, `Exit`
* **restartDelayMS** - Number of milliseconds to delay restart when `exitAction` is `restart`.&#x20;
* **restartThrottleMS** - Throttles how quickly to restart if the app runs for only a short time. Set the number of milliseconds for this threshold. *(Windows only)*
* **standardOutPath** - Path to a file to write the "out" logs. Similar to the `server log` but also includes the raw output of the `server start` command itself.  Useful for debugging failed starts.  *(Windows only)*
* **errorOutPath** - Path to a file to write the "error" logs. Similar to the `server log` but also includes the raw output of the `server start` command itself.  Useful for debugging failed starts.  Can be set to the same path as the "out" log. *(Windows only)*
* **rotateLog** - true/false to enable log rotation *(Windows only)*
* **rotateLogOnline** - true/false to enable log rotation while service is running as opposed to only during a restart. *(Windows only)*
* **rotateLogSeconds** - Number of seconds between log rotations. *(Windows only)*
* **rotateLogKB** - Number of Kilobytes of log file size before rotating. When using online rotation, time is ignored and only file size taken into account. *(Windows only)*

Note, the `standardOutPath` and `errorOutPath` can be absolute or relative. When relative, the following logic is used to expand the paths.

* Paths provided from the CLI are relative to the current working directory of the command
* Paths provided in `server.json` are relative to the location of the `server.json` file.
* Paths provided in `server.defaults.service` config defaults are relative to the web root of the server.

On Linux, the systemd journal will be used for the server out. Any issues with startup can be viewed like so:

```bash
journalctl -u nameOfService
```


# Task Services

CommandBox Task Runners are a powerful way to accomplish CLI scripting.  You may have a task you'd like to run as a daemon so it's always executing.  This could be a message queue consumer, a scheduled task, or a file system watcher.  It is important that your tasks never exits, but always stays running forever.  Make sure you use an uninterruptible method of blocking the task such as `sleep()` so that when the service is shutdown, the interrupt signal will stop the task cleanly. &#x20;

Here is example of a task that uses sleep to stay running, but any command that stops when you press Ctrl-C from the command line will work (such as a file system watcher).

Create an empty task runner like so:

```bash
task create --open
```

And now put some code into it.  The `while( true )` loop makes it run forever (daemon) and the sleep will throw an exception when the thread is interrupted so it can be stopped.

{% code title="task.cfc" %}

```javascript
component {
    
  function run() {
    try{
      while( true ) {
        print.line( "still running!" ).toConsole()
        sleep( 5000 );
      }
    // Catching this will give us a clean shutdown so the service doesn't show as failed
    } catch( java.lang.InterruptedException e ) {
      print.line( 'Task interrupted ...' ).toConsole();
    } finally {
      // Any logic needed to clean up here
    }

}
```

{% endcode %}

You can test your task like so:

```bash
task run
```

Hit Ctrl-C to stop it.  Now, create a service out of.

```bash
task service create --start
```

{% hint style="warning" %}
Warning: if you don't create a task that keeps running forever, the service will just restart your task every time it stops (the default exit action is `restart`.  This will use a lot more CPU than you want!
{% endhint %}


# Usage

Here is an overview of the new commands this module adds into CommandBox for you.

```bash
task service create
task service remove
task service update
task service start
task service stop
task service restart
task service status
```

Each of the `task service XXX` commands above accept the `taskFile` parameter that points to the Task Runner. &#x20;

If you provide no params, the default is `task.cfc`.  If you want to create a service for a task of a different name or in a different folder, you will need to provide this parameter.

#### `server service create`

Create a new service. To customize the service, pass params, set values in your `task.cfc` in a struct located in `this.service`. &#x20;

{% hint style="warning" %}
Note: you must be using an **Administrator** user (Windows) or **root** (\*nix) to create services. You can start box as such, but keep in mind on \*nix, this changes your runtime user, and thus your CommandBox home.
{% endhint %}

#### `server service remove`

Remove an existing service. Does not affect the `task.cfc` itself. Use `--force` to also stop the service if necessary.

#### `server service update`

Update an existing service. To customize the service, pass params, or set them in the `task.cfc` in a `this.service` struct at the top of the CFC.  Use `--force` to also stop the service if necessary. (Service will be restarted if it was originally running)

#### `server service start`

Start a service. Once you start a task via the service, you should also stop and start it via the service as well.

#### `server service stop`

Stop a service. Note, killing the task process directly instead of `server service stop` may cause the service to start again by itself if the `exitAction` is set to `restart`.

#### `server service restart`

Restart a service

#### `server service status`

Get status information for a service. Use `--verbose` to get additional information.

## CommandBox Home

CommandBox installs system modules and saves settings and servers into a `.CommandBox` folder inside the home directory of the current user running the `box` process.  For instance, a `brad` user on Windows and \*nix might have their CommandBox home in these locations:

```bash
C:/Users/brad/.Commandbox/
/home/brad/.CommandBox/
```

What happens when you run a Windows service as the "Local System" account (the default) or a Linux service as `root` (required to bind to ports below 1024) is the CommandBox home directory changes to match the new user that the process runs as. &#x20;

```bash
C:/Windows/System32/config/systemprofile/.CommandBox/
/root/.CommandBox/
```

This is unexpected and often times catches people off guard.  This "second" installation of CommandBox will not have your modules installed, neither will it have any default config settings as all of this data is stored on a per-user basis. &#x20;

This can be made to work, but is undesirable since it prevents you from running `task run` inside CommandBox as yourself and getting the same results.  The easy fix is to lock all users into using the same CommandBox home dir.  To do this, choose a folder that has read/write permissions to all users who need to use CommandBox.  Then create a `commandbox.properties` file in the same directory as your `box` or `box.exe` binary.  Add a line defining a property called `commandbox_home` that points to the shared home dir.  Remember to either use forward slashes or escape all backslashes.

```bash
commandbox_home=E:\\CommandBox
or
commandbox_home=E:/CommandBox
or
commandbox_home=/opt/box/.CommandBox
```

This setting will take affect on your next run of `box` and a new, empty home will be created there.  if you wish, you can transfer all your settings, by stopping CommandBox and all servers, manually copying over the current `.CommandBox` folder to the new location first.  CommandBox will pick up the folder and use it if it's already there and everything inside is portable.


# Configuration

Each operating system may vary on which config items they choose to support.

You can provide configuration to the `task service create` and `task service update` commands as CLI parameters like so:

```bash
task service create startType=auto standardOutPath=logs/out.txt
```

Or you can put them in your `task.cfc` like so:

```bash
component {

    this.service = {
        startType : 'auto',
        standardOutPath : 'logs/out.txt'
    };
        
    function run() {
    }

}
```

The same settings available to server services also work for task services.

* **serviceName** - The name/ID of the service
* **displayName** - The human readable name of the service
* **description** - The description of the service
* **username** - The username to run as.  On Windows, format of `domain\user` or `machine\login`
* **password** - The password of the user above *(Windows only)*
* **startType** - one of the strings `auto`, `delayed`, `ondemand`, `disabled`
* **dependOnGroup** - An array of service groups that need started first.  Comma-delimited list when passed the CLI *(Windows only)*
* **dependOnService** - An array of other services that need started first.  Comma-delimited list when passed the CLI
* **processPriority** - One of the strings `realtime`, `high`, `aboveNormal`, `normal`, `belowNormal`, `idle` *(Windows only)*
* **CPUAffinity** - The string "all" or CPU IDs, starting from 0 such as "0-2,4" which would use the first, second, third, and 5th CPU core. *(Windows only)*
* **exitAction** - One of the strings `Restart`, `Ignore`, `Exit`
* **restartDelayMS** - Number of milliseconds to delay restart when `exitAction` is `restart`.&#x20;
* **restartThrottleMS** - Throttles how quickly to restart if the app runs for only a short time. Set the number of milliseconds for this threshold. *(Windows only)*
* **standardOutPath** - Path to a file to write the "out" logs. Similar to the `server log` but also includes the raw output of the `server start` command itself.  Useful for debugging failed starts.  *(Windows only)*
* **errorOutPath** - Path to a file to write the "error" logs. Similar to the `server log` but also includes the raw output of the `server start` command itself.  Useful for debugging failed starts.  Can be set to the same path as the "out" log. *(Windows only)*
* **rotateLog** - true/false to enable log rotation *(Windows only)*
* **rotateLogOnline** - true/false to enable log rotation while service is running as opposed to only during a restart. *(Windows only)*
* **rotateLogSeconds** - Number of seconds between log rotations. *(Windows only)*
* **rotateLogKB** - Number of Kilobytes of log file size before rotating. When using online rotation, time is ignored and only file size taken into account. *(Windows only)*

Note, the `standardOutPath` and `errorOutPath` can be absolute or relative. When relative, the following logic is used to expand the paths.

* Paths provided from the CLI are relative to the current working directory of the command
* Paths provided in `task.cfc` are relative to the location of the `task.cfc` file.

On Linux, the systemd journal will be used for the server out. Any issues with startup can be viewed like so:

```bash
journalctl -u nameOfService
```


# Bullet Train Integration

If you are using the [CommandBox Bullet Train](https://www.forgebox.io/view/commandbox-bullet-train) module, the Service Manager will contribute its own bullet train car that shows you the stats of the default server for a given directory.

{% embed url="<https://www.forgebox.io/view/commandbox-bullet-train>" %}

```bash
install commandbox-bullet-train
```

You can turn this additional car on or off by setting the following config setting in the bullet train module:

```bash
config set modules.commandbox-bullet-train.serverServiceEnable=false
```

You can customize the background color as well like so:

```bash
config set modules.commandbox-bullet-train.serverServiceBG=grey
```

Remember, the status text in the car can be green, red, yellow, or orange, so choose a color that doesn't render the text unreadable.

You can change the order the car appears in the prompt using the name `serverService` like so:

```bash
config set modules.commandbox-bullet-train.carOrder=boxVersion,package,serverService,status,execTime
```


# Discussion & Help

The Ortus Community

![](/files/-MSZSKFTQzHZR3mPCUHj)

The Ortus Community is the way to get any type of help for our entire platform and modules: <https://community.ortussolutions.com>


