<commit_before># About SpawningKit

SpawningKit is a subsystem that handles the spawning of web application processes in a reliable manner.

Spawning an application process is complex, involving many steps and with many failure scenarios. SpawningKit handles all this complexity while providing a simple interface that guarantees reliability.

Here is how SpawningKit is used. The caller supplies various parameters such as where the application is located, what language it's written in, what environment variables to apply, etc. SpawningKit then spawns the application process, checks whether the application spawned properly or whether it encountered an error, and then either returns an object that describes the resulting process or throws an exception that describes the failure.

Reliability and visibility are core features in SpawningKit. When SpawningKit returns, you know for sure whether the process started correctly or not. If the application did not start correctly, then the resulting exception describes the failure in a detailed enough manner that allows users to pinpoint the source of the problem. SpawningKit also enforces timeouts everywhere so that stuck processes are handled as well.

**Table of contents**:

 * Important concepts and features
   - Generic vs SpawningKit-enabled applications
   - Wrappers
   - Preloaders
   - The start command
   - Summary with examples
 * Overview of the spawning journey
   - When spawning a process without a preloader
   - When starting a preloader
   - When spawning a process through a preloader
   - The Journey class
   - The preparation and the HandshakePrepare class
   - The handshake and the HandshakePerform class
   - The SpawnEnvSetupper
 * The work directory
   - Structure
 * Application response properties
 * The preloader protocol
 * Subprocess journey logging
 * Error reporting
   - Information sources
   - How an error report is presented
   - How supplied information affects error report generation
 * Mechanism for waiting until the application is up

---

## Important concepts and features

### Generic vs SpawningKit-enabled applications

SpawningKit can be used to spawn any web application, both those with and without explicit SpawningKit support.

When SpawningKit is used to spawn a generic application (without explicit SpawningKit support), the only requirement is that the application can be instructed to start and to listen on a specific TCP port on localhost. The user needs to specify a command string that tells SpawningKit how that is to be done. SpawningKit then looks for a free port that the application may use and executes the application using the supplied command string, telling it to listen on that specific port. (This approach is inspired by Heroku's Procfile system.) SpawningKit waits until the application is up by pinging the port. If the application fails (e.g. by terminating early or by not responding to pings in time) then SpawningKit will abort, reporting the application's stdout and stderr output.

Applications can also be modified with explicit SpawningKit support. Such applications can improve performance by telling SpawningKit that it wishes to listen on a Unix domain socket instead of a TCP socket; and they can provide more feedback about any spawning failures, such as with HTML-formatted error messages or by providing more information about where internally in the application or web framework the failure occurred.

### Wrappers

In general, it is better if an application has explicit SpawningKit support, because then it is able to provide a nicer experience and better performance. But having to modify the application's code is a major hurdle.

Luckily, it is not always necessary to modify the application. Wrappers are small programs that aid in loading applications written in specific languages -- in particular interpreted languages because they allow modifying application behavior without requiring code modifications. When a wrapper is used, SpawningKit executes the wrapper, not the actual application. The wrapper loads the application and modifies its behavior in such a way that SpawningKit support is added (e.g. ability to report HTML-formatted errors), without requiring modifications to the application code.

Wrappers are only applicable to apps without explicit SpawningKit support.

Passenger comes with a few wrappers for specific languages, but SpawningKit itself is more generic and requires the caller to specify which wrapper to use (if at all).

For example, Ruby applications are typically spawned through the Passenger-supplied Ruby wrapper. The Ruby wrapper activates the Gemfile, loads the application, sets up a lightweight server that listens on a Unix domain socket, and reports this socket address back to SpawningKit.

### Preloaders

Applications written in certain languages are able to save memory and to improve application startup time by using a technique called pre-forking. This works by starting an application process, and instead of using that process to handle requests, we use that process to fork (but not `exec()`) additional child processes that in turn are actually used for processing requests.

In SpawningKit terminology, we call the former a "preloader". Processes that actually handle requests (and these processes may either be forked from a preloader or be spawned directly without a preloader) usually do not have a specific name. But for the sake of clarity, let's call the latter -- within the context of this document only -- "worker processes".

                                             Requests
                                                |
                                                |
                                               \ /
                                                .

    +-----------+                      +------------------+
    | Preloader |  --- forks many ---> | Worker processes |
    +-----------+                      +------------------+

Memory is saved because the preloader and its worker processes are able to share all memory that was already present in the preloader during forking, and that has not been modified in the worker processes. This concept is called Copy-on-Write (CoW) and works through the virtual memory system of modern operating systems.

For example, in Ruby applications a significant amount of memory is taken up by the bytecode representation of dependent libraries (e.g. the Rails framework). Loading all the dependent libraries typically takes time in the order of many seconds. By using a preloader to fork worker processes (instead of starting the worker processes without a preloader), all worker processes can share the memory taken up by the dependent libraries, as well as the application code itself and possibly any resources that the preloder loaded (e.g. a geo-IP database loaded from a file). Forking a worker process from a preloader is also extremely fast, in the order of milliseconds -- much faster than starting a worker processes without a preloader.

SpawningKit provides facilities to use this preforking technique. Obviously, this technique can only be used if the target programming language actually supports forking. This is the case with e.g. C, Ruby (using MRI) and Python (using CPython), but not with e.g. Node.js, Ruby (using JRuby), Go and anything running on the JVM.

Using the preforking technique through SpawningKit requires either application code modifications, or the existance of a wrapper that supports this technique.

### The start command

Regardless of whether SpawningKit is used to spawn an application with or without explicit SpawningKit support, and regardless of whether a wrapper is used and whether the application/wrapper can function as a preloader, SpawningKit asks the caller to supply a "start command" that tells it how to execute the wrapper or the application. SpawningKit then uses the handshaking procedure (see: "Overview of the spawning journey") to communicate with the wrapper/application whether it should start in preloader mode or not.

### Summary with examples

To help you better understand the concepts, the following table displays an example of some of the above concepts map to hypothetically supportable languages.

~~~
| Generic apps (no   | SpawningKit-enabled,   | SpawningKit-enabled,  |
| explicit Passenger | wrapper available      | no wrapper available  |
| support)           |                        |                       |
| ------------------ | ---------------------- | --------------------- |
| Go app without     | Ruby, Python, Node.js, | Go, Ruby, Perl, all   |
| modifications      | Meteor, Perl, all      | with modifications    |
|                    | without modifications  |                       |
~~~

## Overview of the spawning journey

Spawning a process can take one of three routes:

 * If we are spawning a worker process, then it is either (1) spawned through a preloader, or (2) it isn't.
 * We may also (3) spawn the application as a preloader instead of as a worker.

We refer to the walking of this route (performing all the steps involved in a route) a "journey". Below follows an overview of the routes.

In the following descriptions, "(In SpawningKit)" refers to the process that runs SpawningKit, which is typically the Passenger Core.

### When spawning a process without a preloader

The journey looks like this when no preloader is used:

       (In SpawningKit)                  (In subprocess)

        Preparation
          |
        Fork subprocess   --------------> Before first exec
          |                                  |
        Handshake                         Execute spawn env setupper (--before)
          |                                  |
        Finish                            Load OS shell (if option enabled)
                                             |
                                          Execute spawn env setupper (--after)
                                             |
                                          Execute wrapper (if applicable)
                                             |
                                          Execute/load app
                                             |
                                          Start listening
                                             |
                                          Finish

### When starting a preloader

The journey looks like this when starting a preloader:

       (In SpawningKit)                  (In subprocess)
    
        Preparation
           |
        Fork preloader   --------------> Before first exec
           |                                |
        Handshake                        Execute spawn env setupper (--before)
           |                                |
        Finish                           Load OS shell (if option enabled)
                                            |
                                         Execute spawn env setupper (--after)
                                            |
                                         Execute wrapper in preloader mode
                                         (if applicable)
                                            |
                                         Load application
                                         (and if applicable, do so in
                                         preloader mode)
                                            |
                                         Start listening for commands
                                            |
                                         Finish

### When spawning a process through a preloader

The journey looks like this when using a preloader to spawn a process:
    
       (In SpawningKit)                 (In preloader)          (In subprocess)
    
        Preparation
           |
        Tell preloader to spawn  ------> Preparation
           |                              |
        Receive, process                 Fork  ----------------> Preparation
        preloader response                |                         |
           |                             Send response           Start listening<commit_msg>Avoid confusion with "SetUpper(Case)"<commit_after># About SpawningKit

SpawningKit is a subsystem that handles the spawning of web application processes in a reliable manner.

Spawning an application process is complex, involving many steps and with many failure scenarios. SpawningKit handles all this complexity while providing a simple interface that guarantees reliability.

Here is how SpawningKit is used. The caller supplies various parameters such as where the application is located, what language it's written in, what environment variables to apply, etc. SpawningKit then spawns the application process, checks whether the application spawned properly or whether it encountered an error, and then either returns an object that describes the resulting process or throws an exception that describes the failure.

Reliability and visibility are core features in SpawningKit. When SpawningKit returns, you know for sure whether the process started correctly or not. If the application did not start correctly, then the resulting exception describes the failure in a detailed enough manner that allows users to pinpoint the source of the problem. SpawningKit also enforces timeouts everywhere so that stuck processes are handled as well.

**Table of contents**:

 * Important concepts and features
   - Generic vs SpawningKit-enabled applications
   - Wrappers
   - Preloaders
   - The start command
   - Summary with examples
 * Overview of the spawning journey
   - When spawning a process without a preloader
   - When starting a preloader
   - When spawning a process through a preloader
   - The Journey class
   - The preparation and the HandshakePrepare class
   - The handshake and the HandshakePerform class
   - The SpawnEnvSetupper
 * The work directory
   - Structure
 * Application response properties
 * The preloader protocol
 * Subprocess journey logging
 * Error reporting
   - Information sources
   - How an error report is presented
   - How supplied information affects error report generation
 * Mechanism for waiting until the application is up

---

## Important concepts and features

### Generic vs SpawningKit-enabled applications

SpawningKit can be used to spawn any web application, both those with and without explicit SpawningKit support.

When SpawningKit is used to spawn a generic application (without explicit SpawningKit support), the only requirement is that the application can be instructed to start and to listen on a specific TCP port on localhost. The user needs to specify a command string that tells SpawningKit how that is to be done. SpawningKit then looks for a free port that the application may use and executes the application using the supplied command string, telling it to listen on that specific port. (This approach is inspired by Heroku's Procfile system.) SpawningKit waits until the application is up by pinging the port. If the application fails (e.g. by terminating early or by not responding to pings in time) then SpawningKit will abort, reporting the application's stdout and stderr output.

Applications can also be modified with explicit SpawningKit support. Such applications can improve performance by telling SpawningKit that it wishes to listen on a Unix domain socket instead of a TCP socket; and they can provide more feedback about any spawning failures, such as with HTML-formatted error messages or by providing more information about where internally in the application or web framework the failure occurred.

### Wrappers

In general, it is better if an application has explicit SpawningKit support, because then it is able to provide a nicer experience and better performance. But having to modify the application's code is a major hurdle.

Luckily, it is not always necessary to modify the application. Wrappers are small programs that aid in loading applications written in specific languages -- in particular interpreted languages because they allow modifying application behavior without requiring code modifications. When a wrapper is used, SpawningKit executes the wrapper, not the actual application. The wrapper loads the application and modifies its behavior in such a way that SpawningKit support is added (e.g. ability to report HTML-formatted errors), without requiring modifications to the application code.

Wrappers are only applicable to apps without explicit SpawningKit support.

Passenger comes with a few wrappers for specific languages, but SpawningKit itself is more generic and requires the caller to specify which wrapper to use (if at all).

For example, Ruby applications are typically spawned through the Passenger-supplied Ruby wrapper. The Ruby wrapper activates the Gemfile, loads the application, sets up a lightweight server that listens on a Unix domain socket, and reports this socket address back to SpawningKit.

### Preloaders

Applications written in certain languages are able to save memory and to improve application startup time by using a technique called pre-forking. This works by starting an application process, and instead of using that process to handle requests, we use that process to fork (but not `exec()`) additional child processes that in turn are actually used for processing requests.

In SpawningKit terminology, we call the former a "preloader". Processes that actually handle requests (and these processes may either be forked from a preloader or be spawned directly without a preloader) usually do not have a specific name. But for the sake of clarity, let's call the latter -- within the context of this document only -- "worker processes".

                                             Requests
                                                |
                                                |
                                               \ /
                                                .

    +-----------+                      +------------------+
    | Preloader |  --- forks many ---> | Worker processes |
    +-----------+                      +------------------+

Memory is saved because the preloader and its worker processes are able to share all memory that was already present in the preloader during forking, and that has not been modified in the worker processes. This concept is called Copy-on-Write (CoW) and works through the virtual memory system of modern operating systems.

For example, in Ruby applications a significant amount of memory is taken up by the bytecode representation of dependent libraries (e.g. the Rails framework). Loading all the dependent libraries typically takes time in the order of many seconds. By using a preloader to fork worker processes (instead of starting the worker processes without a preloader), all worker processes can share the memory taken up by the dependent libraries, as well as the application code itself and possibly any resources that the preloder loaded (e.g. a geo-IP database loaded from a file). Forking a worker process from a preloader is also extremely fast, in the order of milliseconds -- much faster than starting a worker processes without a preloader.

SpawningKit provides facilities to use this preforking technique. Obviously, this technique can only be used if the target programming language actually supports forking. This is the case with e.g. C, Ruby (using MRI) and Python (using CPython), but not with e.g. Node.js, Ruby (using JRuby), Go and anything running on the JVM.

Using the preforking technique through SpawningKit requires either application code modifications, or the existance of a wrapper that supports this technique.

### The start command

Regardless of whether SpawningKit is used to spawn an application with or without explicit SpawningKit support, and regardless of whether a wrapper is used and whether the application/wrapper can function as a preloader, SpawningKit asks the caller to supply a "start command" that tells it how to execute the wrapper or the application. SpawningKit then uses the handshaking procedure (see: "Overview of the spawning journey") to communicate with the wrapper/application whether it should start in preloader mode or not.

### Summary with examples

To help you better understand the concepts, the following table displays an example of some of the above concepts map to hypothetically supportable languages.

~~~
| Generic apps (no   | SpawningKit-enabled,   | SpawningKit-enabled,  |
| explicit Passenger | wrapper available      | no wrapper available  |
| support)           |                        |                       |
| ------------------ | ---------------------- | --------------------- |
| Go app without     | Ruby, Python, Node.js, | Go, Ruby, Perl, all   |
| modifications      | Meteor, Perl, all      | with modifications    |
|                    | without modifications  |                       |
~~~

## Overview of the spawning journey

Spawning a process can take one of three routes:

 * If we are spawning a worker process, then it is either (1) spawned through a preloader, or (2) it isn't.
 * We may also (3) spawn the application as a preloader instead of as a worker.

We refer to the walking of this route (performing all the steps involved in a route) a "journey". Below follows an overview of the routes.

In the following descriptions, "(In SpawningKit)" refers to the process that runs SpawningKit, which is typically the Passenger Core.

### When spawning a process without a preloader

The journey looks like this when no preloader is used:

       (In SpawningKit)                  (In subprocess)

        Preparation
          |
        Fork subprocess   --------------> Before first exec
          |                                  |
        Handshake                         Execute SpawnEnvSetupper to setup spawn env (--before)
          |                                  |
        Finish                            Load OS shell (if option enabled)
                                             |
                                          Execute SpawnEnvSetupper (--after)
                                             |
                                          Execute wrapper (if applicable)
                                             |
                                          Execute/load app
                                             |
                                          Start listening
                                             |
                                          Finish

### When starting a preloader

The journey looks like this when starting a preloader:

       (In SpawningKit)                  (In subprocess)
    
        Preparation
           |
        Fork preloader   --------------> Before first exec
           |                                |
        Handshake                        Execute SpawnEnvSetupper to setup spawn env (--before)
           |                                |
        Finish                           Load OS shell (if option enabled)
                                            |
                                         Execute SpawnEnvSetupper (--after)
                                            |
                                         Execute wrapper in preloader mode
                                         (if applicable)
                                            |
                                         Load application
                                         (and if applicable, do so in
                                         preloader mode)
                                            |
                                         Start listening for commands
                                            |
                                         Finish

### When spawning a process through a preloader

The journey looks like this when using a preloader to spawn a process:
    
       (In SpawningKit)                 (In preloader)          (In subprocess)
    
        Preparation
           |
        Tell preloader to spawn  ------> Preparation
           |                              |
        Receive, process                 Fork  ----------------> Preparation
        preloader response                |                         |
           |                             Send response           Start listening
{'fraction_non_alphanumeric': 0.04749059996730423, 'fraction_numerical': 0.0002452182442373713, 'mean_word_length': 2.0548064918851434, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 140, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2631910', 'n_tokens_mistral': 4926, 'n_tokens_neox': 4675, 'n_words': 2890}