Permalink
Browse files

Updates the documentation with what the next version of chain will be

  • Loading branch information...
1 parent 21a4c1c commit 9973894bb049d26bdf37e75c62c056b289e028d7 Daniel Neighman committed Jan 17, 2010
Showing with 34 additions and 87 deletions.
  1. +16 −55 API.textile
  2. +9 −9 README.textile
  3. +2 −6 REQUIREMENTS.textile
  4. +7 −17 SPEC.textile
View
@@ -4,32 +4,33 @@ For the purposes of this document, the "chain" variable is the imported Chain ob
h1. Moving around the Chain
+Moving from one link to another must not block. Chain takes care of this for you by calling the next Link for you and ensuring that it's not blocking.
+
h2. Sending the request forward
To send the request from one link to another:
<pre><code>// Simple pass it forward:
-env.send(nextApp);
+env.next();
// Pass it forward with a callback:
-env.send(nextApp, function(){
+env.next(function(){
/* do stuff here */
})
-// Manually pass it forward to another Link:
-otherLink.emit("request", env);
+// pass it forward to a known link:
+env.next(someLink);
+
+// pass it forward to a known link with a callback:
+env.next(someLink, function(){ /* stuff */ }
</code></pre>
h2. Sending the request back through the chain
When you recieve a request you can add a function to be called "on the way out" so that you can modify / affect the response after the endpoint has done it's thing.
-<pre><code>//First register a callback
-env.send(nextApp, function(){
- // do stuff
- env.done();
-});
-
+<pre><code>
+//First register a callback as above
// Send the request back one link:
env.done();
</code></pre>
@@ -83,7 +84,7 @@ env.onDone(function(){
})
// Implicitly adding to the onDone stack when sending the request forward
-env.send(nextApp, function(){
+env.next(function(){
// an onDone callback. Will be called if the request makes it back this far
env.done();
})
@@ -103,51 +104,11 @@ env.onFinish(function(){
h1. Making a Link
-There are a number of ways to make a link. At it's heart, a link is simply an object that listens to itself for a "request" event. The event provides a single argument, the Chain Environment object.
-
-h2. From a function
-
-Chains builder can handle functions and will turn them into links for you.
-
-<pre><code>// Link from a function using an explicit make
- chain.Builder.make([ function(env){ /* do stuff */ }]);
-
- // creating a link from a function as part of a builder stack
- var builder = new chain.Builder();
- builder.use(function(env){ /* do stuff */} );
-</code></pre>
-
-h2. From an object
-
-When you make a link from an object, you should have an onRequest method that receives a single env argument.
-
-<pre><code>// Make a link from an object using chain.Link
-var myLink = new chain.Link("My Links Name", myObj);
-
-// Make a new link using a builder stack
-var builder = new chain.Builder();
-builder
- .use(new chain.Link(myObj))
-</code></pre>
-
-
-h2. Manually
-
-Setup your object to add a listener to itself for the "request" event.
-
-<pre><code>// a manual Link
-function someLink(){
- process.mixin(this, process.EventEmitter);
- var self = this;
- self.addListener("request", function(env){
- self.handlerFunction.call(self, env);
- });
-}
-</code></pre>
+There are any number of ways to make a link. At it's heart a link is an object that implements an onRequest(env) method. If there is a downstream link, it should attach that to the 'nextLink' attribute.
h1. Constructing a Chain
-When you construct a chain, you're basically getting the builder to add a nextApp attribute to each chain that provides a default next link. The link itself can choose to either use that link as the next place, choose another place to send the request, or simply respond to the client and finish the request.
+When you construct a chain, you're basically getting the builder to add a nextApp attribute to each link that provides a default nextLink. The link itself can choose to either let the env use that link as the next link in the chain, choose another link to send the request to, or simply respond to the client and finish the request.
h2. Using an array
<pre><code>// Making a chain from an array of functions / links
@@ -160,8 +121,8 @@ h2. Using a configurable Builder instance
var builder = new chain.Builder();
builder
.use(function(env){ /* wrapped in an object. this.nextApp available */})
- .use(new chain.Link("My Link", someObj)
- .useConstructor(myConstructor, optionsObject);
+ .use(someObj)
+ .use(myConstructor, any, argument, list); // calls Object.create.apply(Object, argumentsFromUse)
var app = builder.build();
</code></pre>
View
@@ -1,10 +1,12 @@
h1. Chain
-Chain is a convention for building web applications. Why Another One? Events.
+Chain is a convention for building web applications. Why Another One? Asyncronous Processing.
The conventions to date for making web applications are callstack based.
<pre>
+// Conventional Callstack Based Systems
+
function
-> function
-> function
@@ -17,23 +19,21 @@ function
For any rubyists this is great, it's how rack works. Call a method and return a value. Easy. This is a callstack structure. Any exception raised or thrown in downstream methods can be caught and dealt with. You know what you're getting, and the request is assured to pass through so you can modify it when it comes back up the stack. I've written a lot of Rack middleware and think it's great in Ruby.
-Node and JavaScript provide a rich event based structure for building applications. Node is an event loop. It's built for events. Node will take a request from the event queue, and process it for as long as it holds the callstack which is until the function finishes.
+Node and JavaScript provide a rich asyncronous based structure for building applications. Node is an event loop. It's built for events and async programming. Node will take a request from the event queue, and process it for as long as it holds the callstack which is until the function finishes.
-A callstack based approach is therefore flawed inside Node.js. Inside an event loop we should be doing small pieces of work and then putting the next piece on the queue. In this way, we get concurrency. Whilst you may not be interested in concurrency for multiple requests, you can perform many different tasks via events on the event loop. This type of concurrency is very valuable.
+A callstack based approach is therefore flawed inside Node.js. Inside an event loop we should be doing small pieces of work and then putting the next piece on the queue. In this way, we get concurrency. Whilst you may not be interested in concurrency for multiple requests, you can perform many different tasks by splitting the request into pieces for the event loop. This type of concurrency is very valuable.
-Chain, then, is a convention for designing applications for the web inside node.js. There's some code thrown in to help do this. Chain forces the use of events between links (middleware) by using events as a way to pass the request forward. It also uses callbacks if you're interested in modifying the output on the way "back up".
+Chain, then, is a convention for designing applications for the web inside node.js. There's some code thrown in to help do this. Chain requires the use of events between links (middleware) but doesn't need the developer to think too much about it. The chain environment knows how to call links asyncronously and will let you construct your application and hapily go where you tell it to. It keeps things efficient by only providing the response to links that register callbacks.
Very simply:
-Each link should listen to itself for a "request" event, from which it will receive exactly 1 argument. The Chain.Environment instance.
+Each link should supply an 'onRequest' function. This receives exactly 1 argument. The chain environment.
-* To pass the request forward use environment.send(nextApp)
+* To pass the request forward use environment.next();
* To finish and pass back up the stack use environment.done()
* To finish the request just respond to the client directly (use sparingly)
-To start your application use
-
-Chain.run(app)
+See the spec document for more detailed information.
See the examples for more information.
View
@@ -6,11 +6,7 @@ A "Link" is a piece of the application that can be developed in a focused, reaso
Chaining has proven it's worth in many systems and allows decoupled components to work together through a minimal interface.
-By using an event to push the request forward through the chain, callstacks are minimised, and are eliminated between components. This is important to allow many requests to get a slice of the processor. Considering that the event loop has no threads, any one request that holds the attention of the event loop for it's entire request means that no other request, or out of request process can use the processor till it's finished. By forcing components to use events to pass the reqest around it gives up control of the event loop so that many things may be processed in a much more timely manner. Imagine iterating through a huge array inside a browser. Although there's no IO wait occuring and CPU utilisation is maximised. The event loop is also stalled waiting for the calcs to finish. By spliting things into smaller chunks, we can be more responsive on the server.
-
-Although chain uses an event to push the request forward, it does so by having each link setup a "request" event listener on itself. Setting up static listeners on objects to "listen" for a request object on something upstream means that the path through the application becomes static. A router, or other piece of kit cannt determine where to send the request next. It also becomes possible that there will be multiple listeners on a link meaning that there is potential for conflict. By having a link listen to itself for the request object, there is no potential for conflict, and each link may contain the logic required to pass the request onto the next stage.
-
-Likewise there are no event listeners setup for the request coming back through the chain. This is for similar reasons, but also, so that each link can register it's interest only if required.
+By using a non blocking transition to push the request forward through the chain, callstacks are minimised, and are eliminated between components. This is important to allow many requests to get a slice of the processor. Considering that the event loop has no threads, any one request that holds the attention of the event loop for it's entire request means that no other request, or out of request process can use the processor till it's finished. By forcing components to use async transitions to pass the reqest around it gives up control of the event loop so that many things may be processed in a much more timely manner. It's easier to rely on links being async if they're all async. Imagine iterating through a huge array inside a browser. Although there's no IO wait occuring and CPU utilisation is maximised. The event loop is also stalled waiting for the calcs to finish. By spliting things into smaller chunks, we can be more responsive on the server.
Ryah: "With no concurrency, comes great concurrency"
@@ -60,7 +56,7 @@ h2. Building A Chain
* Join links together to provide a default path through the application
** These may not be used by the links but by giving a default path through the chain, you're setting up the application as you expect it to run in default cases.
-
+* Only Links can be added to a Link. Chains are constructed one link at a time.
h1. Streaming
It's easy to stream in Chain. Then environment gives you access to the raw response object. You can stream by using the raw response object, and if you finsih the response with response.finish(), you can.
View
@@ -1,16 +1,17 @@
h1. Chain Spec
-Chain is a simple specification and framework for building web applications in the node.js engine. node.js is deliberately simple and does not attempt to over specify how an application must function logically other than the mechanism it should use. Chain links multiple application components, hereafter referred to as "links" together by giving a standard way to pass requests.
+Chain is a simple specification and framework for building web applications in the node.js engine. node.js is deliberately simple and does not attempt to over specify how an application must function logically other than the mechanism it should use. Chain links multiple application components, hereafter referred to as "links" together by giving a standard way to pass requests between each other.
-Chain specifies a default chain structure for links, based purely on events to move from one link to another. This has the benefit of minimising call-stack dependent applications, and allowing a consistent way to call links from other applications and links, thereby maximising re-usability.
+Chain specifies a default chain structure for links, based on each link containing a reference to the next link, 'nextLink', so that the environment knows where to go next if required. A link in a chain is a single instance of an object or object type.
h2. Applications
A Chain compatible application has the following characteristics
-* Each link MUST listen to itself for a "request" event. The first, and only, argument of which must be THE Chain.Environment instance for the request.
-* The Chain.Environment instance MUST be passed on. An application may not receive one instance of the Chain.Environment and pass a different instance to the next application
-* If an application is finished but does not respond to the client directly, it should call the _done_ method on the environment instance before finsihing the method.
+* Each link MUST provide an onRequest method that recieves one argument, the chain environment.
+* The Chain.Environment instance MUST be passed on. An link may not receive one instance of the Chain.Environment and pass a different instance to the next link
+* Transitions between links must not block. The env.next() method must be non-blocking
+* If an application is finished but does not respond to the client directly, it should call the done() method on the environment instance before finsihing the method.
h2. Chain.Environment
@@ -23,22 +24,11 @@ The Chain.Environment instance is the common thread throughout the request. The
* env.beforeHeaders - Add a callback to run just before the headers are sent to the client. This can be used to encode the session into the cookie and other such functionality. Optionally return an array with the arguments for response.sendHeader
* env.beforeSendBody - Add a filter to the send body method. By supplying a function that accepts the same arguments as response.sendBody you can modify the chunck prior to it being sent to the client. These can be queued for multi stage filtering. To change the arguments, return an array of the arguments to pass to sendBody
* env.done - The trigger to fire the next onDone callback. Each callback, if it has not completed the request, should call env.done() to run the next onDone callback in the queue.
+* env.next - This function must move to the next link in the chain, or the specified link if one is given. It must be non-blocking
* env.headers
* env.status
* env.body
-h2. Global Links
-
-Chain may store global level links. These are made available so that all applications may access them. You may add an application to the collection if it is to act in a global capacity. These are available at
-
-Chain.Links
-
-Examples may be (these may not be implemented)
-Chain.Links.Errors
-Chain.Links.Layouts
-Chain.Links.Auditing
-Chain.Links.Logging
-
h2. Chain Events
Chain is an event emitter and will emit events as a central message dispatch. Chain will emit events on various stages of the build. The event should be a generic event type followed by a specified type. Any link can also have Chain broadcast events

0 comments on commit 9973894

Please sign in to comment.