File: test-cluster-disconnect-handles.js

package info (click to toggle)
nodejs 4.8.2~dfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 62,476 kB
  • ctags: 111,183
  • sloc: cpp: 661,544; ansic: 31,406; python: 23,073; makefile: 1,418; sh: 1,384; perl: 255; lisp: 222; ruby: 76; xml: 50
file content (99 lines) | stat: -rw-r--r-- 3,637 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/* eslint-disable no-debugger */
// Flags: --expose_internals
'use strict';

const common = require('../common');
const assert = require('assert');
const cluster = require('cluster');
const net = require('net');

const Protocol = require('_debugger').Protocol;

if (common.isWindows) {
  common.skip('SCHED_RR not reliable on Windows');
  return;
}

cluster.schedulingPolicy = cluster.SCHED_RR;

// Worker sends back a "I'm here" message, then immediately suspends
// inside the debugger.  The master connects to the debug agent first,
// connects to the TCP server second, then disconnects the worker and
// unsuspends it again.  The ultimate goal of this tortured exercise
// is to make sure the connection is still sitting in the master's
// pending handle queue.
if (cluster.isMaster) {
  let isKilling = false;
  const handles = require('internal/cluster').handles;
  const address = common.hasIPv6 ? '[::1]' : common.localhostIPv4;
  cluster.setupMaster({ execArgv: [`--debug=${address}:${common.PORT}`] });
  const worker = cluster.fork();
  worker.once('exit', common.mustCall((code, signal) => {
    assert.strictEqual(code, 0, 'worker did not exit normally');
    assert.strictEqual(signal, null, 'worker did not exit normally');
  }));
  worker.on('message', common.mustCall((message) => {
    assert.strictEqual(Array.isArray(message), true);
    assert.strictEqual(message[0], 'listening');
    let continueRecv = false;
    const address = message[1];
    const host = address.address;
    const debugClient = net.connect({ host, port: common.PORT });
    const protocol = new Protocol();
    debugClient.setEncoding('utf8');
    debugClient.on('data', (data) => protocol.execute(data));
    debugClient.once('connect', common.mustCall(() => {
      protocol.onResponse = common.mustCall((res) => {
        protocol.onResponse = (res) => {
          // It can happen that the first continue was sent before the break
          // event was received. If that's the case, send also a continue from
          // here so the worker exits
          if (res.body.command === 'continue') {
            continueRecv = true;
          } else if (res.body.event === 'break' && continueRecv) {
            const req = protocol.serialize({ command: 'continue' });
            debugClient.write(req);
          }
        };
        const conn = net.connect({ host, port: address.port });
        conn.once('connect', common.mustCall(() => {
          conn.destroy();
          assert.notDeepStrictEqual(handles, {});
          worker.disconnect();
          assert.deepStrictEqual(handles, {});
          // Always send the continue, as the break event might have already
          // been received.
          const req = protocol.serialize({ command: 'continue' });
          debugClient.write(req);
        }));
      });
    }));
  }));
  process.on('exit', () => assert.deepStrictEqual(handles, {}));
  process.on('uncaughtException', function(ex) {
    // Make sure we clean up so as not to leave a stray worker process running
    // if we encounter a connection or other error
    if (!worker.isDead()) {
      if (!isKilling) {
        isKilling = true;
        worker.once('exit', function() {
          throw ex;
        });
        worker.process.kill();
      }
      return;
    }
    throw ex;
  });
} else {
  const server = net.createServer((socket) => socket.pipe(socket));
  const cb = () => {
    process.send(['listening', server.address()]);
    debugger;
  };
  if (common.hasIPv6)
    server.listen(0, '::1', cb);
  else
    server.listen(0, common.localhostIPv4, cb);
  process.on('disconnect', process.exit);
}