Skip to content

Latest commit

 

History

History
237 lines (193 loc) · 7.46 KB

examples.md

File metadata and controls

237 lines (193 loc) · 7.46 KB

Examples

Zones and express

This example show a very simple case where Zones can:

  • Store user provided data with different lifetimes
  • Capture unexpected Exceptions in asynchronous callbacks
  • Provide a long stack-trace of exceptions

Example code:

require('zone').enable();
express = require('express');
var Zone = zone.Zone;

var app = express();
var router = express.Router();
Zone.longStackSupport = true;

//Initialize the Request id in the root zone. 
//This value will be  available to all child zones.
zone.data.requestId = 0;

app.use(function(req, res, next) {
  //Increment the request ID for every new request
  ++zone.data.requestId;

  //Create a new Zone for this request
  zone.create(
           function RequestZone() {
             //Store the request URL in the Request zone
             //This value will be only to this zone and its children
             zone.data.requestURL = req.url;
             
             //Continue to run other express middleware within this child zone
             next();
           })
      .then(
          //The call was succesful
          function successCallback(err) {
            res.write('Transaction succesful\n');
            res.end();
          },
          
          //An error was thrown while processing this request
          function errorCallback(err) {
            res.write('Transaction failed\n');
            res.write('x' + err.zoneStack + '\n');
            res.end();
          });
});

router.get('/', function(req, res) {
  if (Math.random() > 0.5) {
    //Simulate some async I/O call that throws an exception
    process.nextTick(function() { throw new Error("monkey wrench"); });
  }
  
  res.write('Running request #' + zone.data.requestId + ' within zone: ' +
            zone.name + ' (URL:' + zone.data.requestURL + ')\n');
});

app.use('/', router);
app.listen(3001);

Output:

> curl localhost:3001?q=ghi
Running request #3 within zone: RequestZone (URL:/?q=ghi)
Transaction failed
xError: monkey wrench
    at Zone.<anonymous> (/scratch/server.js:44:41)
    at Zone._apply (/scratch/node_modules/zone/lib/zone.js:588:15)
    at Zone.apply (/scratch/node_modules/zone/lib/zone.js:611:23)
    at processCallbacks (/scratch/node_modules/zone/lib/scheduler.js:47:10)
    at processQueues (/scratch/node_modules/zone/lib/scheduler.js:67:5)
    at process._tickCallback (node.js:343:11)
In zone: RequestZone
    at Zone.create (/scratch/node_modules/zone/lib/zone.js:273:10)
    at Layer.handle (/scratch/server.js:17:8)
    at trim_prefix (/scratch/node_modules/express/lib/router/index.js:226:17)
    at /scratch/node_modules/express/lib/router/index.js:198:9
    at Function.proto.process_params (/scratch/node_modules/express/lib/router/index.js:251:12)
    at next (/scratch/node_modules/express/lib/router/index.js:189:19)
    at Layer.expressInit [as handle] (/scratch/node_modules/express/lib/middleware/init.js:23:5)
    at trim_prefix (/scratch/node_modules/express/lib/router/index.js:226:17)
    at /scratch/node_modules/express/lib/router/index.js:198:9
    at Function.proto.process_params (/scratch/node_modules/express/lib/router/index.js:251:12)
    
> curl localhost:3001?q=klm
Running request #4 within zone: RequestZone (URL:/?q=klm)
Transaction succesful

Inspecting a running application

This showcase demonstrates what the inspect tool does.

demo.js:

The demo script spins up a TCP server and creates a bunch of clients that send data to the server on an interval basis.

require('zone').enable(); // enable zones

var Zone = zone.Zone;
var net = require('net');

Zone.longStackSupport = true;

zone.create(function ServerZone() {
  var server = net.createServer(function(conn) {
    conn.resume();
  });

  server.listen(3001);
});


for (var i = 0; i < 10; i++) {
  zone.create(function ConnectionZone() {
    var conn = net.connect(3001, function() {
      zone.create(function IntervalZone() {
        setInterval(function() {
          conn.write('hello');
        }, 1);
      });
    });
  });
}

console.log("Run the inspect tool to see what's going on in this process.");

inspect.js

The inspect tool outputs a snapshot of all the asynchronous action going on inside all node processes using zones. It also displays resources (like sockets and file descriptors) that by themselves do not represent future events, but are relevant to zones because these resources are automatically cleaned up when the zone returns or throws.

The output looks like a tree, because zones act as containers for asynchronous I/O and related resources.

Entries marked with a + are active sources of events that are running inside the zone. Entries not marked with a plus sign are passive resources that don't produce callbacks, but that are cleanup up when a zone returns or throws.

var isWindows = process.platform === 'win32';
var fs = require('fs');
var net = require('net');
var path = require('path');
var prefix = isWindows ? '\\\\?\\pipe'
                       : '/tmp';


var pipeNames = fs.readdirSync(prefix);

pipeNames = pipeNames.filter(function(name) {
  return /^%node-zone-debug-/.test(name);
}).map(function(name) {
  return prefix + path.sep + name;
});

if (pipeNames.length > 0)
  inspectNext();
else
  console.log('No zone processes found');


function inspectNext() {
  var pipeName = pipeNames.shift();

  if (!pipeName)
    return;

  var conn = net.connect(pipeName);
  conn.pipe(process.stdout);
  conn.on('error', function() {});
  conn.on('close', inspectNext);
}

Output:

> node inspect.js
(2194) node /Volumes/Aether/Users/kraman/Documents/strongloop/zone.kr/scratch.js
+[Zone        ] #1 Root (64 tasks, 4 external callbacks)
  +[ZoneCallback] #14 OnRead
  +[ZoneCallback] #15 OnWriteComplete
  +[ZoneCallback] #16 OnRead
  +[ZoneCallback] #17 OnWriteComplete
  +[Zone        ] #8 DebugServerZone (7 tasks, 5 external callbacks)
    +[ZoneCallback] #10 OnRead
    +[ZoneCallback] #11 OnWriteComplete
    +[ZoneCallback] #12 OnConnection
    +[ZoneCallback] #181 OnRead
    +[ZoneCallback] #182 OnWriteComplete
     [Stream      ] Pipe server 
     [Stream      ] Pipe handle 
   [Stream      ] TTY handle  (fd: 1)
   [Stream      ] TTY handle  (fd: 2)
  +[Zone        ] #18 ServerZone (23 tasks, 23 external callbacks)
    +[ZoneCallback] #20 OnRead
    +[ZoneCallback] #21 OnWriteComplete
    +[ZoneCallback] #22 OnConnection
     ...
     [Stream      ] TCP server  (:::3001)
     [Stream      ] TCP handle  (::ffff:127.0.0.1:3001 <=> ::ffff:127.0.0.1:53945)
     [Stream      ] TCP handle  (::ffff:127.0.0.1:3001 <=> ::ffff:127.0.0.1:53946)
     [Stream      ] TCP handle  (::ffff:127.0.0.1:3001 <=> ::ffff:127.0.0.1:53947)
     [Stream      ] TCP handle  (::ffff:127.0.0.1:3001 <=> ::ffff:127.0.0.1:53948)
     ...
  +[Zone        ] #23 ConnectionZone (3 tasks, 2 external callbacks)
    +[ZoneCallback] #27 OnRead
    +[ZoneCallback] #28 OnWriteComplete
     [Stream      ] TCP handle  (127.0.0.1:53945 <=> 127.0.0.1:3001)
    +[Zone        ] #153 IntervalZone (1 tasks, 1 external callbacks)
      +[ZoneCallback] #154 setInterval
  +[Zone        ] #31 ConnectionZone (3 tasks, 2 external callbacks)
    +[ZoneCallback] #35 OnRead
    +[ZoneCallback] #36 OnWriteComplete
     [Stream      ] TCP handle  (127.0.0.1:53946 <=> 127.0.0.1:3001)
    +[Zone        ] #155 IntervalZone (1 tasks, 1 external callbacks)
      +[ZoneCallback] #156 setInterval
  ...

Other examples

Other examples are available in the Zones github repository