NaviServer - programmable web server
4.99  5.0

[ Main Table Of Contents | Table Of Contents | Keyword Index ]

ns_proxy(n) 5.0.0a nsproxy "NaviServer Module Commands"

Name

ns_proxy - Execute Tcl scripts in an external process

Table Of Contents

Synopsis

Description

ns_proxy provides a simple, robust proxy mechanism to evaluate Tcl commands and scripts in a separate, pipe-connected process. This is not to be mixed up with a reverse proxy server or a forwarding proxy server, which both by receiving and forwarding HTPP requests. The ns_proxy just forwards Tcl commands and scripts to a different process.

ns_proxy isolates potentially thread-unsafe code outside the address space of the multithreaded NaviServer process and enables separation and timeout of potentially misbehaving, long running scripts. It is also useful, when fork time becomes large, since the nsproxy workers require typically less memory. This is relevant, e.g., for executing system commands, or performing pipe operations in the Tcl open command.

The ns_proxy command is provided by the nsproxy dynamic library which can be loaded into an interpreter via the Tcl load command, for example:

 load "/usr/local/lib/libnsproxy.so"
 ns_proxy ...

It is also possible to load the library into all interpreters of a NaviServer virtual server by specifying an nsproxy.so entry in the server's module config entry, for example:

 ns_section "ns/server/server1/modules" {
   ns_param nsproxy  nsproxy.so
 }

When loaded, the library adds the single ns_proxy command with takes multiple options as described below. Proxies (i.e. worker processes) are normally created on demand when requested and connected to the parent process via pipes used to send scripts and receive response. Proxies remain active until the parent process exits, effectively closing all pipes to the worker processes, or when their idle timer expires, depending on the setup of the pool (see ns_proxy configure).

Proxies are obtained from their corresponding pool by means of the ns_proxy get command. Only the thread that obtained the proxy can use it to communicate with the worker process. In order to allow other threads to use the same proxy, the thread must return (via the ns_proxy put or ns_proxy cleanup commands) the proxy back to its corresponding pool. One thread can obtain one or a bunch of proxies from a pool in one step. It cannot, however, repeatedly obtain proxy by proxy in a loop, as this may lead to difficult-to-trace deadlock situation (see ns_proxy get command).

All the timeout values below (no matter if these are used in positional or arguments, or as parameters in the configuration file) can be specified with time units. If the timeout value time has no time unit, seconds are assumed.

COMMANDS

ns_proxy active pool ?proxyId?

Returns a list of currently evaluating scripts in proxies for the given pool.

The output is one or more lists, depending on the optional ?proxyId? argument. If the optional argument is given, only the status of the proxy for the given handle is returned and the result is a one-element list. Otherwise, statuses of all active proxies for the given pool are returned and the result is a list of two or more elements.

Each element itself is a list which includes several keys: handle, worker, start, script and their associated values. This format is suitable for filling in a Tcl array with the array set Tcl command. The handle key contains the handle of the proxy. The worker key contains the process-id of the worker process. The start key contains the timestamp with the absolute time when this proxy has been activated. The timestamp is in format that ns_time command understands.

The script contains the script passed to the proxy for execution. It is also possible to view the currently evaluating scripts with the Unix ps command as the proxy worker process re-writes its command argument space with the request script before evaluation and clears it after sending the result.

ns_proxy cleanup

Releases any handles from any pools currently owned by a thread.

This command is intended to be used as part of a garbage collection step. Calling this command within NaviServer is not necessary as the module registers a trace to release all handles via the ns_ictl trace deallocate facility when interpreters are deallocated after some transaction, for example, at the end of a connection.

ns_proxy clear pool ?proxyId?

Stop all worker processes attached to free proxies for the given pool. If the optional proxyId is given, it stops the process only for that proxyId.

ns_proxy configure pool ?-env setId? ?-evaltimeout time? ?-exec value? ?-gettimeout time? ?-idletimeout time? ?-init value? ?-logminduration time? ?-maxruns integer? ?-maxslaves integer? ?-maxworkers integer? ?-recvtimeout time? ?-reinit value? ?-sendtimeout time? ?-waittimeout time?

Configures or queries options for the pool. The pool is created with default options if it does not already exist. Default options for the pool are taken from the NaviServer configuration file under the section "ns/server/$server/module/nsproxy". In case the library is loaded in plain Tcl shell, default configuration options are fixed and cannot be changed w/o recompiling the code.

When "ns_proxy configure" is called without the optional parameters, the configured values are returned.

Configurable options include:

-env setId

Initializes the worker's process environment with keys/values passed in the named NaviServer set (see command ns_set).

-evaltimeout time

Specifies the maximum time to wait for a script to be evaluated in a proxy. This parameter can be overridden on a per-call basis with the optional ?timeout? parameter to ns_proxy eval. The default is 0 milliseconds i.e. infinite.

-exec program

Specifies the filename of a worker proxy program. The default is nsproxy-helper in the bin subdirectory of the NaviServer home. It is possible to create a custom program and enter the proxy event loop with the Ns_ProxyMain application startup routine; see the source code for details.

-gettimeout time

Specifies the maximum time to wait to allocate handles from the pool. The default is 5 seconds.

-idletimeout time

Specifies the maximum time for an idle worker process to live. Minimum value is 5 seconds. After expiry of the idle timeout, the reaper thread will close the connection pipe and wait -waittimeout for the process to die. If the timeout is exceeded, the reaper will send a SIGTERM signal and finally a SIGKILL signal (waiting -waittimeout in between) to ensure the process eventually exits.

Worker processes whose handles are already attached to some Tcl interps by the means of the ns_proxy get command) are not expired automatically. The idle timer starts to count at the moment their handles are put back to the pool by the ns_proxy put or ns_proxy cleanup command.

-init script

Specifies a script to evaluate when proxies are started. This can be used to load additional libraries and/or source script files. The default is no script.

-logminduration time

Specifies a time limit for logging (long) eval operations to the system log (similar to "logminduration" in the db drivers). Set it to a high value to avoid logging (e.g. 1d). The default is 1s.

-maxruns integer

Sets the maximum number of activation of the proxy worker process. When the limit it reached, the worker process is automatically restarted.

-maxworkers integer

Sets the maximum number of proxy worker processes. Requests for proxies beyond the maximum will result in requesting threads waiting for existing proxies to be available instead of creating new proxy processes. Setting this value to 0 disables the pool, causing all subsequent allocation requests to fail immediately (currently allocated proxies, if any, remain valid).

-reinit script

Specifies a script to evaluate after being allocated and before being returned to the caller. This can be used to re-initialize the worker state. The default is no script.

-sendtimeout time
-recvtimeout timeout

Specifies the maximum time to wait to send a script and receive a result from a proxy. The default is 1 second which assumes minimal delay sending and receiving reasonably sized scripts and results over the connecting pipe.

-waittimeout time

Specifies the maximum time to wait for a proxy to exit. The wait is performed in a dedicated reaper thread. The reaper will close the connection pipe and wait the given timeout. If the timeout is exceeded, the reaper will send a SIGTERM signal and finally a SIGKILL signal to ensure the process eventually exits. The default is 1 second which should be ample time for a graceful exit unless the process is hung executing a very long, misbehaving script, resulting in a more disruptive SIGTERM or SIGKILL.

ns_proxy eval proxyId script ?timeout?

Evaluates script in the proxy specified by proxyId. The optional ?timeout? argument specifies a maximum time to wait for the command to complete before raising an error (see ERROR HANDLING below for details on handling errors).

Alternatively, the proxyId itself may be used as Tcl command like in the example below:

 set handle [ns_proxy get mypool]
 $handle "short_running_proc"
 $handle "long_running_proc" 20000
ns_proxy free pool

Returns a list of all free proxies for the given pool. Free proxies are those which are left in the pool queue waiting to be used by the ns_proxy get command. Some proxies may have an active worker process attached, some not. If a worker process is not attached to the free proxy, a new one will be created as soon as the proxy is requested by some thread.

ns_proxy get pool ?-handles integer? ?-timeout time?

Returns one or more handles to proxies from the specified pool. If no worker process has been started yet, or when additional worker processes are required, and it is permitted by the configuration, these worker processes will be started.

The pool will be created with default options if it does not already exist. The optional -handle can be used to specify the number of handles to allocate, the default being 1.

The optional ?-timeout? arguments specifies the maximum time to wait for the handles to become available before raising an error (see ERROR HANDLING below for details on handling errors).

Requesting more than one handle in a single call (if more than one handle is required) is necessary as it is an error to request handles from a pool from which handles are already owned by the thread. This restriction is implemented to avoid possible deadlock conditions.

The handle returned by this command can be used as a scalar value for other ns_proxy commands, or it can be used as Tcl command itself (see ns_proxy eval for more information).

The proxy pool naming convention allows proxy worker to be started under different Unix UID/GID then the server itself. For that to work, the server must be running under root user (UID = 0). The naming convention is simple: pool_name:<optional_user_id>:<optional_group_id>.

For example, to start the proxy for the pool "mypool" with user UID of 100 the pool name can be constructed as: "mypool:100". To start the proxy with UID of 100 and group GID of 200: "mypool:100:200". Instead of numeric values user/group names can also be used.

Beware: if the main server is not running under privileged root user, the startup of the proxy under some alternative UID/GID may/will fail.

ns_proxy handles ?pool?

Returns list of all proxies allocated for the current interpreter. When the optional argument pool is specified, just handles from this pool are returned.

ns_proxy ping proxyId

This command sends a null request to the proxy specified by the proxyId argument. The proxy will be verified alive and restarted if necessary. This command is not normally required as the ns_proxy eval command will also verify and restart proxies as needed.

ns_proxy pools

Returns a list of all currently defined proxy pools.

ns_proxy put proxyId

This command is alternate name for ns_proxy release.

ns_proxy recv proxyId

Reads result from the script from the proxy specified by proxyId (see ERROR HANDLING below for details on handling errors).

ns_proxy release proxyId

Return the proxy proxyId to the pool. All handles owned by a thread to the corresponding pool must be returned before any handles can be allocated again. Within the server, a call to this routine is recommended for clarity but not strictly necessary. NaviServer installs a trace to release all handles at the end of every connection during interpreter deallocation.

ns_proxy send proxyId script

Sends script to the proxy specified by proxyId. (see ERROR HANDLING below for details on handling errors).

ns_proxy stats pool

Provide summative usage statistics in form of a dict from the specified pool. The dict contains the following keys: proxies, waiting, maxworkers, free, used, requests, processes, and runtime.

ns_proxy stop pool ?proxyId?

Stop all worker processes attached to running proxies for the given pool. If the optional proxyId is given, it stops the process only for that proxyId.

ns_proxy wait proxyId ?timeout?

Waits for results from the proxy specified by proxyId. The optional timeout argument specifies a maximum time to wait for the command to complete before raising an error (see ERROR HANDLING below for details on handling errors).

ns_proxy workers pool

Returns a list of the workers of the proxy pool, where every element contains a dict containing the following keys: id, pid, created, runs, and state. The command can be used for fine-tuing the number of workers for an application by checking their load. Creating workers at startup helps to keep the time of spawning low, especially when the memory footprint of the server is large and the server is running in a virtual machine. The value of created stands for the number of spawn operations for the workers.

All time units can be specified with and without a time unit suffix. Valid time units are "ms", "s", "m", "h", "d". If no time unit suffix is specified, seconds are assumed.

ERROR HANDLING

Errors generated by a script evaluated in a proxy interpreter are completely returned to the calling interpreter, including mapping the errorInfo and errorCode global variables from the proxy to the parent and raising a Tcl exception. This approach makes ns_proxy evaluations look very similar to the Tcl eval command.

Errors raised by a failure to communicate with the proxy process due to a timeout or unexpected process exit are also communicated back to the parent interpreter as Tcl exceptions. To distinguish between these cases, communication related errors set the errorCode global variable with the first element NSPROXY. The second element is one of the following:

EDeadlock

The interpreter attempted to allocate handles from a pool from which it already owns one or more handles.

EExec

The worker program specified by the -exec program option could not be started.

EImport

The response from the proxy was invalid.

ERecv

There was an error receiving the result from the worker process.

ESend

There was an error sending the script to the worker process.

EGetTimeout

Timeout while waiting to get a proxy handle from the pool.

EEvalTimeout

Timeout while waiting for the response from the proxy process after sending the command for evaluation.

ERange

Requested too many proxy handles from the pool

EIdle

Proxy is currently in the idle state.

EInit

Evaluation of the init script failed.

EDead

Proxy handle is currently not connected to any process.

EBusy

Proxy handle is currently busy with the evaluation.

CONFIGURATION

The default settings of the configuration parameters of ns_proxy can be provided in the configuration file of NaviServer.

 # Loading the nxproxy module in the modules section
 # of the server.
 ns_section	ns/server/${server}/modules {
   # ...
   ns_param	nsproxy			${homedir}/bin/nsproxy.so
   # ...
 }
 
 # Configuring the nsproxy module
 ns_section ns/server/${server}/module/nsproxy {
 
   # Proxy program to start
   #ns_param	exec			${homedir}/bin/nsproxy-helper
 
   # Timeout when evaluating scripts
   ns_param	evaltimeout		0s
 
   # Timeout when getting proxy handles
   ns_param	gettimeout		0s
 
   # Timeout to send data
   ns_param	sendtimeout		5s
 
   # Timeout to receive results
   ns_param	recvtimeout		5s
 
   # Timeout to wait for workers to die
   ns_param	waittimeout		1s
 
   # Timeout for a worker to live idle
   ns_param	idletimeout		5m
 
   # log eval operations longer than this to the system log
   ns_param	logminduration		1s
 
   # Max number of allowed workers alive
   ns_param	maxworkers		8
 }

EXAMPLES

The following demonstrates sending a script to a remote proxy:

 set handle [ns_proxy get myproxy]
 ns_proxy eval $handle {info patchlevel}
 ns_proxy release $handle

Alternatively, instead of using the scalar handle you can use the handle directly as a Tcl command:

 set handle [ns_proxy get myproxy]
 $handle {info patchlevel}
 rename $handle ""

The following demonstrates using multiple proxies:

 ns_proxy configure myproxy -maxworkers 10
 set handles [ns_proxy get myproxy -handle 10]
 foreach h $handles {
   $h {puts "alive: [pid]"}
 }
 ns_proxy cleanup

See Also

ns_job, revproxy

Keywords

background, exec, module, nsproxy, pools, proxy, server built-in