version app + node.exe + nw.exe
This commit is contained in:
217
node_modules/cluster/docs/api.md
generated
vendored
Normal file
217
node_modules/cluster/docs/api.md
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
|
||||
## API
|
||||
|
||||
The Cluster API at its core is extremely simple, all we need to do is pass
|
||||
our tcp or http `server` to `cluster()`, then call `listen()` as we would on the `http.Server` itself.
|
||||
|
||||
|
||||
var cluster = require('../')
|
||||
, http = require('http');
|
||||
|
||||
var server = http.createServer(function(req, res){
|
||||
res.writeHead(200);
|
||||
res.end('Hello World');
|
||||
});
|
||||
|
||||
cluster(server)
|
||||
.listen(3000);
|
||||
|
||||
Alternatively (and recommended) is to export your server instance via `module.exports`, and supply a path to `cluster()`. For example _app.js_:
|
||||
|
||||
module.exports = http.createServer(....);
|
||||
|
||||
and _server.js_ with our cluster logic, allowing our server to be `require()`ed within tests, and preventing potential issues by having open database connections etc within the master processes, as only the workers need access to the `server` instance.
|
||||
|
||||
cluster('app')
|
||||
.listen(3000);
|
||||
|
||||
A good example if this, is a long-lived database connection. Our _app.js_ may have this initialized at the top, which although will work fine stand-alone, may cause cluster's master processes to hang when restarting or closing due to the connection remaining active in the event loop.
|
||||
|
||||
var db = redis.createClient();
|
||||
|
||||
### Abstract Clusters
|
||||
|
||||
Cluster is not bound to servers, cluster can be used to manage processes for processing job queues etc. Below is a minimalist example of this, simply invokes `cluster()` with no object, spawning a worker per cpu:
|
||||
|
||||
var cluster = require('cluster');
|
||||
|
||||
var proc = cluster().start();
|
||||
|
||||
if (proc.isWorker) {
|
||||
// do things within the worker processes
|
||||
} else {
|
||||
// do something within the master
|
||||
}
|
||||
|
||||
### Plugins
|
||||
|
||||
A plugin simple a function that accepts the `master` process. Most plugin functions _return_ another anonymous function, allowing them to accept options, for example:
|
||||
|
||||
function myPlugin(path){
|
||||
return function(master) {
|
||||
// do stuff
|
||||
}
|
||||
}
|
||||
|
||||
To use them, all we need to do is pass it to the `use()` method:
|
||||
|
||||
cluster(server)
|
||||
.use(myPlugin('/some/path'))
|
||||
.listen(3000);
|
||||
|
||||
To use a plugin that is bundled with Cluster simply grab it from the `cluster` object:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.logger())
|
||||
.listen(3000);
|
||||
|
||||
### Settings
|
||||
|
||||
Below are the settings available:
|
||||
|
||||
- `workers` Number of workers to spawn, defaults to the number of CPUs or `1`
|
||||
- `working directory` Working directory defaulting to the script's dir
|
||||
- `backlog` Connection backlog, defaulting to 128
|
||||
- `socket port` Master socket port defaulting to `8989`
|
||||
- `timeout` Worker shutdown timeout in milliseconds, defaulting to `60000`
|
||||
- `title` master process title defaulting to "cluster"
|
||||
- `worker title` worker process title defaulting to "cluster worker"
|
||||
- `user` User id / name
|
||||
- `group` Group id / name
|
||||
|
||||
We can take what we have now, and go on to apply settings using the `set(option, value)` method. For example:
|
||||
|
||||
cluster(server)
|
||||
.set('working directory', '/')
|
||||
.set('workers', 5)
|
||||
.listen(3000);
|
||||
|
||||
### Signals
|
||||
|
||||
Cluster performs the following actions when handling signals:
|
||||
|
||||
- `SIGINT` hard shutdown
|
||||
- `SIGTERM` hard shutdown
|
||||
- `SIGQUIT` graceful shutdown
|
||||
- `SIGUSR2` restart workers
|
||||
|
||||
### Events
|
||||
|
||||
The following events are emitted, useful for plugins or general purpose logging etc.
|
||||
|
||||
- `start`. When the IPC server is prepped
|
||||
- `worker`. When a worker is spawned, passing the `worker`
|
||||
- `listening`. When the server is listening for connections
|
||||
- `closing`. When master is shutting down
|
||||
- `close`. When master has completed shutting down
|
||||
- `worker killed`. When a worker has died
|
||||
- `worker exception`. Worker uncaughtException. Receives the worker and exception object
|
||||
- `kill`. When a `signal` is being sent to all workers
|
||||
- `restarting`. Restart requested by REPL or signal. Receives an object
|
||||
which can be patched in order to preserve plugin state.
|
||||
- `restart`. Restart complete, new master established, previous killed.
|
||||
Receives an object with state preserved by the `restarting` even,
|
||||
patched in the previous master.
|
||||
|
||||
### Master#state
|
||||
|
||||
Current state of the master process, one of:
|
||||
|
||||
- `active`
|
||||
- `hard shutdown`
|
||||
- `graceful shutdown`
|
||||
|
||||
### Master#isWorker
|
||||
|
||||
`true` when the script is executed as a worker.
|
||||
|
||||
cluster = cluster(server).listen(3000);
|
||||
|
||||
if (cluster.isWorker) {
|
||||
// do something
|
||||
}
|
||||
|
||||
Alternatively we can use the __CLUSTER_WORKER__ env var, populated with
|
||||
the worker's id.
|
||||
|
||||
### Master#isMaster
|
||||
|
||||
`true` when the script is executed as master.
|
||||
|
||||
cluster = cluster(server).listen(3000);
|
||||
|
||||
if (cluster.isMaster) {
|
||||
// do something
|
||||
}
|
||||
|
||||
### Master#set(option, value)
|
||||
|
||||
Set `option` to `value`.
|
||||
|
||||
### Master#use(plugin)
|
||||
|
||||
Register a `plugin` for use.
|
||||
|
||||
### Master#in(env)
|
||||
|
||||
Conditionally perform the following action, if
|
||||
__NODE_ENV__ matches `env`.
|
||||
|
||||
cluster(server)
|
||||
.in('development').use(cluster.debug())
|
||||
.in('development').listen(3000)
|
||||
.in('production').listen(80);
|
||||
|
||||
The environment conditionals may be applied to several calls:
|
||||
|
||||
cluster(server)
|
||||
.set('working directory', '/')
|
||||
.in('development')
|
||||
.set('workers', 1)
|
||||
.use(cluster.logger('logs', 'debug'))
|
||||
.use(cluster.debug())
|
||||
.listen(3000)
|
||||
.in('production')
|
||||
.set('workers', 4)
|
||||
.use(cluster.logger())
|
||||
.use(cluster.pidfiles())
|
||||
.listen(80);
|
||||
|
||||
If we perform the same action for environments, set them before
|
||||
the first `in()` call, or use `in('all')`.
|
||||
|
||||
cluster(server)
|
||||
.set('working directory', '/')
|
||||
.do(function(){
|
||||
console.log('some arbitrary action');
|
||||
})
|
||||
.in('development')
|
||||
.set('workers', 1)
|
||||
.use(cluster.logger('logs', 'debug'))
|
||||
.use(cluster.debug())
|
||||
.in('production')
|
||||
.set('workers', 4)
|
||||
.use(cluster.logger())
|
||||
.use(cluster.pidfiles())
|
||||
.in('all')
|
||||
.listen(80);
|
||||
|
||||
### Master#spawn(n)
|
||||
|
||||
Spawn `n` additional workers.
|
||||
|
||||
### Master#close()
|
||||
|
||||
Graceful shutdown, waits for all workers to reply before exiting.
|
||||
|
||||
### Master#destroy()
|
||||
|
||||
Hard shutdown, immediately kill all workers.
|
||||
|
||||
### Master#restart([signal])
|
||||
|
||||
Defaults to a graceful restart, spawning a new master process, and sending __SIGQUIT__ to the previous master process. Alternatively a custom `signal` may be passed.
|
||||
|
||||
### Master#kill([signal])
|
||||
|
||||
Sends __SIGTERM__ or `signal` to all worker processes. This method is used by `Master#restart()`, `Master#close()` etc.
|
||||
59
node_modules/cluster/docs/cli.md
generated
vendored
Normal file
59
node_modules/cluster/docs/cli.md
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
## CLI
|
||||
|
||||
Adds a command-line interface to your cluster.
|
||||
|
||||
### Usage
|
||||
|
||||
This plugin requires that you use `pidfiles()`
|
||||
above `cli()`, so that the pidfile directory
|
||||
is exposed.
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.pidfiles())
|
||||
.use(cluster.cli())
|
||||
.listen(3000);
|
||||
|
||||
Once set up our server script serves as both
|
||||
the master, and the CLI. For example we may
|
||||
still launch the server(s) as shown below.
|
||||
|
||||
$ nohup node server.js &
|
||||
|
||||
However now we may also utilize commands
|
||||
provided by this plugin.
|
||||
|
||||
$ node server.js status
|
||||
|
||||
master 3281 alive
|
||||
worker 0 3282 dead
|
||||
worker 1 3283 alive
|
||||
worker 2 3284 alive
|
||||
worker 3 3285 alive
|
||||
|
||||
$ node server.js restart
|
||||
$ node server.js shutdown
|
||||
|
||||
For more command information use `--help`.
|
||||
|
||||
$ node server.js --help
|
||||
|
||||
### Defining CLI Commands
|
||||
|
||||
Plugins may define additional commands, simply by invoking `cluster.cli.define()` passing the flag(s), a callback function,
|
||||
and a description. Below is the implementation of `--help` for reference:
|
||||
|
||||
var cli = require('cluster').cli;
|
||||
|
||||
cli.define('-h, --help, help', function(master){
|
||||
console.log('\n Usage: node <file> <command>\n');
|
||||
commands.forEach(function(command){
|
||||
console.log(' '
|
||||
+ command.flags.join(', ')
|
||||
+ '\n '
|
||||
+ '\033[90m' + command.desc + '\033[0m'
|
||||
+ '\n');
|
||||
});
|
||||
console.log();
|
||||
process.exit();
|
||||
}, 'Show help information');
|
||||
31
node_modules/cluster/docs/debug.md
generated
vendored
Normal file
31
node_modules/cluster/docs/debug.md
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
## Debug
|
||||
|
||||
Outputs verbose debugging information to _stderr_.
|
||||
|
||||
info - master started
|
||||
info - worker 0 spawned
|
||||
info - worker 1 spawned
|
||||
info - worker 2 spawned
|
||||
info - worker 3 spawned
|
||||
info - worker 2 connected
|
||||
info - worker 0 connected
|
||||
info - worker 3 connected
|
||||
info - worker 1 connected
|
||||
info - listening for connections
|
||||
^C info - shutting down
|
||||
warning - kill(SIGKILL)
|
||||
info - shutdown complete
|
||||
warning - worker 2 died
|
||||
warning - worker 0 died
|
||||
warning - worker 3 died
|
||||
|
||||
## Usage
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.debug())
|
||||
.listen(3000);
|
||||
|
||||
### Options
|
||||
|
||||
- `colors` enable color output, defaults to true
|
||||
33
node_modules/cluster/docs/logger.md
generated
vendored
Normal file
33
node_modules/cluster/docs/logger.md
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
## Logger
|
||||
|
||||
File-based logging of both the _master_ and _worker_ processes.
|
||||
|
||||
### Usage
|
||||
|
||||
The `logger([path[, level]])` plugin accepts an optional `path`, and optional `level` to control the verbosity of the master process logs. By default the log level is _info_.
|
||||
|
||||
Outputting to `./logs`:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.logger())
|
||||
.listen(3000);
|
||||
|
||||
|
||||
Outputting to `./tmp/logs`:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.logger('tmp/logs'))
|
||||
.listen(3000);
|
||||
|
||||
Outputting to `/var/log/node` with a log level of `debug`:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.logger('/var/log/node', 'debug'))
|
||||
.listen(3000);
|
||||
|
||||
Generated files:
|
||||
|
||||
master.log
|
||||
workers.access.log
|
||||
workers.error.log
|
||||
41
node_modules/cluster/docs/pidfiles.md
generated
vendored
Normal file
41
node_modules/cluster/docs/pidfiles.md
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
## PID Files
|
||||
|
||||
Saves out PID files, for example:
|
||||
|
||||
master.pid
|
||||
worker.0.pid
|
||||
worker.1.pid
|
||||
worker.2.pid
|
||||
worker.3.pid
|
||||
|
||||
### Usage
|
||||
|
||||
The `pidfiles([path])` plugin saves pid (process-id) files to the given `path` or `./pids`.
|
||||
|
||||
save to `./pids`:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.pidfiles())
|
||||
.listen(3000);
|
||||
|
||||
save to `/var/run/node`:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.pidfiles('/var/run/node'))
|
||||
.listen(3000);
|
||||
|
||||
### master.pidfiles
|
||||
|
||||
The pidfiles directory.
|
||||
|
||||
### master.pidof(name)
|
||||
|
||||
Return a __PID__ for the given `name`.
|
||||
|
||||
master.pidof('master')
|
||||
// => 5978
|
||||
|
||||
master.pidof('worker.0')
|
||||
// => 5979
|
||||
|
||||
44
node_modules/cluster/docs/reload.md
generated
vendored
Normal file
44
node_modules/cluster/docs/reload.md
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
## Reload
|
||||
|
||||
Restart the server the given js `files` have changed.
|
||||
`files` may be several directories, filenames, etc, defaulting
|
||||
to the script's directory.
|
||||
|
||||
### Options
|
||||
|
||||
- `signal` Signal to send, defaults to __SIGTERM__
|
||||
- `interval` Watcher interval, defaulting to `100`
|
||||
|
||||
### Usage
|
||||
|
||||
The `reload(paths[, signal])` plugin accepts a single path, or an array of paths, watching for __mtime__ changes, and re-loading the workers when a change has been made. By default the __SIGTERM__ signal is sent, killing the workers immediately, however we may pass a `signal` for graceful termination as well.
|
||||
|
||||
Reload when files in `./` (`__dirname`) change:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.reload())
|
||||
.listen(3000);
|
||||
|
||||
Reload when files in `./lib` change:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.reload('lib'))
|
||||
.listen(3000);
|
||||
|
||||
Reload when files in `./lib`, `./tests`, or the `./index.js` file change:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.reload(['lib', 'tests', 'index.js']))
|
||||
.listen(3000);
|
||||
|
||||
Graceful shutdown:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.reload('lib', { signal: 'SIGQUIT' }))
|
||||
.listen(3000);
|
||||
|
||||
Watching coffee-script files as well.
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.reload('lib', { extensions: ['.js', '.coffee'] }))
|
||||
.listen(3000);
|
||||
165
node_modules/cluster/docs/repl.md
generated
vendored
Normal file
165
node_modules/cluster/docs/repl.md
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
|
||||
## REPL
|
||||
|
||||
Provides live administration tools for inspecting state, spawning and killing workers, and more. The __REPL__ plugin itself is extensible, for example the `stats()` plugin provides a __REPL__ function named `stats()`.
|
||||
|
||||
### Usage
|
||||
|
||||
The `repl([port | path])` accepts a `port` or unix domain socket `path`, after which you may telnet to at any time.
|
||||
|
||||
Launch the __REPL__ with a local socket:
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.repl('/var/run/cluster.sock'))
|
||||
.listen(3000);
|
||||
|
||||
Start a telnet session:
|
||||
|
||||
$ telnet /var/run/cluster.sock
|
||||
|
||||
cluster> help()
|
||||
|
||||
Commands
|
||||
help(): Display help information
|
||||
spawn(n): Spawn one or more additional workers
|
||||
pids(): Output process ids
|
||||
kill(id, signal): Send signal or SIGTERM to the given worker
|
||||
shutdown(): Gracefully shutdown server
|
||||
stop(): Hard shutdown
|
||||
restart(): Gracefully restart all workers
|
||||
echo(msg): echo the given message
|
||||
stats(): Display server statistics
|
||||
|
||||
__NOTE__: a local socket is recommended, otherwise this may be a secure hole.
|
||||
|
||||
### pids()
|
||||
|
||||
Outputs the master / worker process ids.
|
||||
|
||||
cluster> pids()
|
||||
|
||||
pids
|
||||
master: 1799
|
||||
worker #0: 1801
|
||||
worker #1: 1802
|
||||
worker #2: 1803
|
||||
worker #3: 1804
|
||||
|
||||
### spawn()
|
||||
|
||||
Spawn an additional worker.
|
||||
|
||||
cluster> spawn()
|
||||
spawning 1 worker
|
||||
cluster> pids()
|
||||
|
||||
pids
|
||||
master: 1799
|
||||
worker #0: 1801
|
||||
worker #1: 1802
|
||||
worker #2: 1803
|
||||
worker #3: 1804
|
||||
worker #4: 1809
|
||||
|
||||
### spawn(n)
|
||||
|
||||
Spawn `n` workers:
|
||||
|
||||
cluster> spawn(4)
|
||||
spawning 4 workers
|
||||
cluster> pids()
|
||||
|
||||
pids
|
||||
master: 1817
|
||||
worker #0: 1818
|
||||
worker #1: 1819
|
||||
worker #2: 1820
|
||||
worker #3: 1821
|
||||
worker #4: 1825
|
||||
worker #5: 1826
|
||||
worker #6: 1827
|
||||
worker #7: 1828
|
||||
|
||||
### kill(id[, signal])
|
||||
|
||||
Kill worker `id` with the given `signal` or __SIGTERM__. For graceful termination use __SIGQUIT__.
|
||||
|
||||
cluster> pids()
|
||||
|
||||
pids
|
||||
master: 1835
|
||||
worker #0: 1837
|
||||
worker #1: 1838
|
||||
worker #2: 1839
|
||||
worker #3: 1840
|
||||
|
||||
cluster> kill(2)
|
||||
sent SIGTERM to worker #2
|
||||
cluster> kill(3)
|
||||
sent SIGTERM to worker #3
|
||||
cluster> pids()
|
||||
|
||||
pids
|
||||
master: 1835
|
||||
worker #0: 1837
|
||||
worker #1: 1838
|
||||
worker #2: 1843
|
||||
worker #3: 1844
|
||||
|
||||
### restart()
|
||||
|
||||
Gracefully restart all workers.
|
||||
|
||||
cluster> pids()
|
||||
|
||||
pids
|
||||
master: 1835
|
||||
worker #0: 1837
|
||||
worker #1: 1838
|
||||
worker #2: 1843
|
||||
worker #3: 1844
|
||||
|
||||
cluster> restart()
|
||||
restarting 4 workers
|
||||
cluster> pids()
|
||||
|
||||
pids
|
||||
master: 1835
|
||||
worker #0: 1845
|
||||
worker #1: 1849
|
||||
worker #2: 1848
|
||||
worker #3: 1847
|
||||
|
||||
### Defining REPL Functions
|
||||
|
||||
To define a function accessible to the __REPL__, all we need to do is call `cluster.repl.define()`, passing the function, as well as a description string.
|
||||
|
||||
Below we define the `echo()` function, simply printing the input `msg` given. As you can see our function receivers the `Master` instance, the __REPL__ `sock`, and any arguments that were passed. For example `echo("test")` would pass the `msg` as `"test"`, and `echo("foo", "bar")` would pass `msg` as `"foo"`, and `arguments[3]` as `"bar"`.
|
||||
|
||||
repl.define('echo', function(master, sock, msg){
|
||||
sock.write(msg + '\n');
|
||||
}, 'echo the given message');
|
||||
|
||||
Shown below is a more complete example.
|
||||
|
||||
var cluster = require('../')
|
||||
, repl = cluster.repl
|
||||
, http = require('http');
|
||||
|
||||
var server = http.createServer(function(req, res){
|
||||
var body = 'Hello World';
|
||||
res.writeHead(200, { 'Content-Length': body.length });
|
||||
res.end(body);
|
||||
});
|
||||
|
||||
// custom repl function
|
||||
|
||||
repl.define('echo', function(master, sock, msg){
|
||||
sock.write(msg + '\n');
|
||||
}, 'echo the given message');
|
||||
|
||||
// $ telnet localhots 8888
|
||||
|
||||
cluster(server)
|
||||
.use(repl(8888))
|
||||
.listen(3000);
|
||||
83
node_modules/cluster/docs/stats.md
generated
vendored
Normal file
83
node_modules/cluster/docs/stats.md
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
## Stats
|
||||
|
||||
The stats plugin collects statistics from the events emitter by the master process, and exposes a `stats()` __REPL__ function.
|
||||
|
||||
|
||||
### Usage
|
||||
|
||||
To utilize simply `use()` both the `stats()` and `repl()` plugins.
|
||||
|
||||
cluster(server)
|
||||
.use(cluster.stats())
|
||||
.use(cluster.repl(8888))
|
||||
.listen(3000);
|
||||
|
||||
Telnet to the repl:
|
||||
|
||||
$ telnet localhost 8888
|
||||
|
||||
### stats()
|
||||
|
||||
After manually killing two workers, the stats below show information regarding system load average, uptime, total workers spawned, deaths, worker-specific stats and more.
|
||||
|
||||
cluster> stats()
|
||||
|
||||
Master
|
||||
os: Darwin 10.5.0
|
||||
state: active
|
||||
started: Fri, 11 Feb 2011 16:58:48 GMT
|
||||
uptime: 2 minutes
|
||||
workers: 4
|
||||
deaths: 2
|
||||
|
||||
Resources
|
||||
load average: 0.35 0.23 0.15
|
||||
cores utilized: 4 / 4
|
||||
memory at boot (free / total): 2.18gb / 4.00gb
|
||||
memory now (free / total): 2.08gb / 4.00gb
|
||||
|
||||
Workers
|
||||
0: 2 minutes
|
||||
1: 2 minutes
|
||||
2: 1 minute
|
||||
3: 22 seconds
|
||||
|
||||
### Options
|
||||
|
||||
- `connections` enable connection statistics
|
||||
- `requests` enable request statistics
|
||||
|
||||
### Connection Statistics
|
||||
|
||||
Cluster can report on connections made to the server in each worker. To utilize simply pass `{ connections: true }`, and then view the stats in the REPL. You will now see the total number of connections made, and the total active connections, along with a break-down of connections per-worker, leading the pipe is the active, trailing the pipe is the total number of connections.
|
||||
|
||||
Workers
|
||||
connections total: 60
|
||||
connections active: 0
|
||||
0: 15 seconds 0|4
|
||||
1: 15 seconds 0|1
|
||||
2: 15 seconds 0|25
|
||||
3: 15 seconds 0|30
|
||||
|
||||
### Request Statistics
|
||||
|
||||
Cluster supports reporting on requests as well, currently only tallying up the total number, however is capable of much more. The REPL `stats()` output below is the result of passing `.use(cluster.stats({ connections: true, requests: true }))`.
|
||||
|
||||
|
||||
Workers
|
||||
connections total: 60
|
||||
connections active: 0
|
||||
requests total: 24064
|
||||
0: 15 seconds 0|4|3358
|
||||
1: 15 seconds 0|1|1126
|
||||
2: 15 seconds 0|25|9613
|
||||
3: 15 seconds 0|30|9967
|
||||
|
||||
### Events
|
||||
|
||||
When the options shown above are used, events are also emitted, so even if you do not plan on using the REPL, these events may be helpful to other plugins.
|
||||
|
||||
- `client connection`, worker
|
||||
- `client disconnection`, worker
|
||||
- `client request`, worker, request
|
||||
Reference in New Issue
Block a user