Passenger hooks
Passenger provides a powerful but simple hooking system, which allows you to extend many aspects of Passenger's behavior. The hooking system works by executing commands during certain events. Event parameters are passed to the command in the form of environment variables.
Hooks are available since Passenger version 4.0.28.
Table of contents
- How to define hooks
- Example
- Environment
- Blocking and concurrency
- Error handling
- Compatibility
- Available hooks
How to define hooks
- Apache
- You can define hooks by setting the configuration option:
Copy
PassengerCtl hook_<HOOK NAME> <COMMAND TO EXECUTE>
- Nginx
- You can define hooks by setting the configuration option:
Copy
passenger_ctl hook_<HOOK NAME> <COMMAND TO EXECUTE>;
- Standalone
- You can define hooks using
--ctl
/ "ctls":Copy--ctl hook_<HOOK NAME>=<COMMAND TO EXECUTE>
Example
The hook system is best demonstrated with a simple example. In the following example we will hook into the attached_process
event. This event is called whenever Passenger has successfully spawned an application processes and added it to the process pool. We print the process's PID and application root.
First, let's create a script /home/phusion/attached.sh
which is to be called during the hook.
Copy#!/bin/sh
echo "Attached process $PASSENGER_PROCESS_PID for app $PASSENGER_APP_ROOT."
Then we make it executable:
Copychmod +x /home/phusion/attached.sh
And we define the hook in the configuration file:
Apache |
|
Nginx, Standalone |
|
Standalone |
|
Now restart the web server and access a web app hosted by Passenger. You should see our message in the web server error log:
Copy[ 2013-12-10 16:12:21.6456 28934/0x1064cb000 Hooks.h:129 ]: Running attached_process hook script: /home/phusion/attached.sh
Attached process 28303 for app /webapps/foobar.
[ 2013-12-10 16:12:21.6580 28934/0x1064cb000 Hooks.h:161 ]: Hook script /home/phusion/attached.sh (PID 28948) exited with status 0
Environment
A lot of information is passed to hook scripts in the form of environment variables. They are all uppercase and begin with PASSENGER_
. Some environment variables are passed to all hook scripts, others are passed depending on the hook.
Here are some of the environment variables which are passed to all hooks, unless documented otherwise:
PASSENGER_HOOK_NAME
PASSENGER_VERSION
PASSENGER_PASSENGER_ROOT
PASSENGER_INSTANCE_DIR
PASSENGER_INSTANCE_REGISTRY_DIR
Blocking and concurrency
Except when otherwise documented, all hooks block in the background. That is, while your hook command is running, Passenger can still handle web requests, but the background thread which is running your hook will be blocked and won't be able to perform any further operations. For example, if you wrote a hook script for the attached_process
event, then Passenger won't be able to attach further processes until your hook script finishes. You should therefore be careful when writing hook scripts.
If you have a bug in your script and it blocks, then you will be able to see that using the command passenger-status --show=backtraces
which prints the backtraces of all threads in the Passenger core process. Look for the runSingleHookScript
function in the backtrace. The following example shows at line 2 that Passenger is waiting for the hook script /home/phusion/badscript.sh
.
CopyThread 'Group process spawner: /home/phusion/webapp.test#default' (0x1062d4000):
in 'bool Passenger::runSingleHookScript(Passenger::HookScriptOptions &, const string &, const vector<pair<string, string> > &)' (Hooks.h:116) -- /home/phusion/badscript.sh
in 'bool Passenger::runHookScripts(Passenger::HookScriptOptions &)' (Hooks.h:159)
in 'void Passenger::ApplicationPool2::Group::spawnThreadRealMain(const SpawnerPtr &, const Passenger::ApplicationPool2::Options &, unsigned int)' (Implementation.cpp:878)
Hooks may be called concurrently, because Passenger sometimes uses multiple background threads. For example, while the attached_process
hook is being called, a detached_process
hook may be called, perhaps even for the same application. It is your responsibility to ensure that your hook scripts are concurrency-safe, e.g. by employing locks and other concurrency control techniques.
Error handling
If a hook script fails – that is, if it exits with anything other than exit code 0 – then the error handling depends on the hook. Some hooks will abort, other hooks will ignore the error. In all cases, the result of the hook script is printed to the log.
Compatibility
Because hooks are inherently tied to the implementation of Passenger, there is no guarantee that hooks that currently work will continue to be available in the future versions of Passenger. The availability of hooks is very much tied to the specific version of Passenger.
Available hooks
before_watchdog_initialization
Version | 4.0.28 and later |
---|---|
Error handling | Aborts on hook script errors. |
Called at the very beginning of Passenger's life cycle, during the start of the Watchdog process. The first hook is called before initialization is performed (before the Passenger core process is started).
Errors in the hook script cause Passenger to abort.
after_watchdog_initialization
Version | 4.0.28 and later |
---|---|
Error handling | Aborts on hook script errors. |
Like before_watchdog_initialization, but called after initialization of all Passenger agent processes.
Errors in the hook script cause Passenger to abort.
before_watchdog_shutdown
Version | 4.0.28 and later |
---|---|
Error handling | Aborts on hook script errors. |
Called after an exit signal has been noticed (e.g. webserver exit), before the Watchdog starts terminating agent processes.
after_watchdog_shutdown
Version | 4.0.28 and later |
---|---|
Error handling | Aborts on hook script errors. |
Called after the Watchdog is done and about to exit.
attached_process
Version | 4.0.28 and later |
---|---|
Error handling | Errors in the hook script are ignored. |
Called when Passenger has successfully spawned an application processes and added it to the process pool.
Extra environment variables:
PASSENGER_PROCESS_PID
PASSENGER_APP_ROOT
detached_process
Version | 4.0.28 and later |
---|---|
Error handling | Errors in the hook script are ignored. |
Called when Passenger has removed an application process from the process pool. This could happen when:
- The process has crashed, and Passenger noticed it.
- Passenger has shut down a process because it's been idle for too long.
- The administrator configured different resource limits, and Passenger is starting or shutting down processes in response.
- Passenger itself is shutting down.
Extra environment variables:
PASSENGER_PROCESS_PID
PASSENGER_APP_ROOT
spawn_failed
Version | 4.0.49 and later |
---|---|
Error handling | Aborts on hook script errors. |
Called when an application process could not be spawned. This could happen when:
- The application failing to start. For example: bugs in the application, database problems causing the application to crash, incorrectly installed dependencies.
- Operating system-level problems, such as running out of memory.
- The application taking too long to start, and hitting Passenger's timeout.
queue_full_error
Version | 5.0.0 RC 1 and later |
---|---|
Error handling | Errors in the hook script are ignored. |
Passenger rejects new requests (default: HTTP 503) while the request queue is full. This hook gets called for each rejection.
This hook does not block anything, because it's always run in an extra background thread.
Extra environment variables:
PASSENGER_APP_ROOT
- The path to the application that failed to spawn.
PASSENGER_APP_GROUP_NAME
- The configured app group name.
PASSENGER_ERROR_MESSAGE
- An error message that describes the problem.
PASSENGER_ERROR_ID
- A unique ID for this error event. If you search for this ID in the web server error log files, you should be able to find details about the error.
PASSENGER_APP_ERROR_MESSAGE
- Output captured from the application at the time the error occurred.
max_request_time_reached
Version | 5.0.2 and later. Available in Passenger Enterprise only. |
---|---|
Error handling | Errors in the hook script are ignored. |
Called when a max request time limit has been reached. Please note that as soon as this hook has finished executing, the application process will be killed with SIGKILL. So if you want to perform any diagnostics on the process in question (e.g. with strace, gdb, etc), please do not exit your hook script until you've obtained all the diagnostics you want.
At present, this hook blocks web request handling. This may be solved in a future version of Passenger.
Extra environment variables:
PASSENGER_APP_ID
- The PID of the process whose request took too long.
PASSENGER_REQUEST_PATH
- The path of the request that took took long, e.g. "/photos/edit?id=123".
PASSENGER_REQUEST_HOST
- The host name of the request that took too long, e.g. "www.example.com". This environment variable is not set if the request doesn't contain a Host header.