added some clarification docs
This commit is contained in:
parent
6566c2af5c
commit
3f7bde8d30
|
@ -0,0 +1,129 @@
|
|||
# Landline library and application structure
|
||||
|
||||
## File layout
|
||||
|
||||
- `/landline/lib/*.rb` - core of the library
|
||||
- `/landline/lib/dsl/` - module namespaces for use by executable contexts
|
||||
- `/landline/lib/path/` - nodes that extend the Path class (traversable
|
||||
node/setup execution context)
|
||||
- `/landline/lib/probe/` - nodes that extend the Probe class (executable
|
||||
nodes/per-request execution context)
|
||||
- `/landline/lib/template/` - template engine adapters
|
||||
- `/landline/lib/util/` - utility classes and modules
|
||||
- `/landline/lib/pattern_matching/` - classes that implement path pattern
|
||||
matching (i.e. globs, regex and static traversal paths)
|
||||
|
||||
## Architecture overview
|
||||
|
||||
The following chapter defines information that pertains to the overall
|
||||
structure and interaction of landline's core abstractions - Nodes, Paths
|
||||
and Probes.
|
||||
|
||||
For context: Node is an element of the path tree, and is another name for a
|
||||
Probe (which is a leaf of the tree) or a path (which is an internal vertex
|
||||
of the tree)
|
||||
|
||||
```plaintext
|
||||
Path +-> Path +-> Probe
|
||||
| |
|
||||
| +-> Probe
|
||||
+-> Probe
|
||||
|
|
||||
|-> Path -> Probe
|
||||
```
|
||||
|
||||
### Execution contexts
|
||||
|
||||
In Sinatra, which this library takes most of its influence from, every
|
||||
request creates its own instance of the Sinatra application. This seemed
|
||||
like an excessive measure to solve a trivial problem of race conditions on a
|
||||
shared execution context, so to solve that, Landline introduces per-request
|
||||
execution contexts, which have a life time that spans the duration of
|
||||
request processing.
|
||||
|
||||
In short, there are two distinct execution contexts:
|
||||
|
||||
- Per-request execution context, which is used by blocks that process the
|
||||
request and which is bound to that given request
|
||||
- Setup execution context, in which the Landline node tree is constructed
|
||||
|
||||
For every Path-like node, the supplied block is executed in the setup
|
||||
context bound to that path.
|
||||
|
||||
For every Probe-like node, the supplied block is executed in the per-request
|
||||
context of the request that is passed to the probe.
|
||||
|
||||
These execution contexts also affect the receivers of the instance variable
|
||||
write and read operations. Additionally, the two types have different
|
||||
sets of available methods, and every DSL method has a description attached
|
||||
which describes in which context that method can be used (this is due to the
|
||||
limitations of the YARD parser and due to the need of showing method
|
||||
descriptions in the IDE)
|
||||
|
||||
### Request traversal
|
||||
|
||||
Requests in Landline traverse through a series of paths that determine
|
||||
which route the request would take. All nodes are organized in a tree
|
||||
structure, where the root of the tree is a Server object that handles
|
||||
things likes localized jumps, request/response conversion and response
|
||||
finalization, and root-level error/`die()` handling.
|
||||
|
||||
Every path-like node can be supplied with callbacks that perform
|
||||
the following functions:
|
||||
|
||||
- filters - callbacks that filter incoming request objects
|
||||
- preprocessors - callbacks that don't usually affect the routing decision
|
||||
but can modify requests before they come through
|
||||
- postprocessors - callbacks that execute either when a request exits a
|
||||
given path after not finding any suitable probe-like node or when a
|
||||
response to a request is being finalized
|
||||
- pipeline - single callback that is injected in the execution stack that
|
||||
can be used to catch throws and exceptions
|
||||
|
||||
(see `/examples/logging.ru`, `/examples/norxondor_gorgonax/config.ru`)
|
||||
|
||||
The execution contexts for every callback (except pipeline) are shared with
|
||||
those of the probe-like execution contexts, meaning that an instance
|
||||
variable written to in a filter or a preprocessor can be accessed from the
|
||||
probe node or a postprocessor callback.
|
||||
|
||||
Once all preprocessors and filters are finished successfully, the request
|
||||
is passed to all subsequent graph elements (either other Paths or Probes)
|
||||
to check whether a given Node accepts that element.
|
||||
|
||||
If the subtree of the path contains at least one probe that accepts the
|
||||
request, that probe finishes processing the request and either exits
|
||||
the tree immediately by throwing the `:finish` signal with a response
|
||||
or by returning a valid (not nil) response from the `process` method,
|
||||
in which case the response ascends from the probe back to the root.
|
||||
|
||||
If none of the subsequent elements of a path accepted the request, the
|
||||
path executes `die(404)` if `bounce` is not enabled, and if `bounce` is
|
||||
enabled, the request exits from the path and proceeds to sibling
|
||||
(adjacent) paths. (see `/examples/dirbounce.ru`)
|
||||
|
||||
A probe can finish the request by either throwing a response, by executing a
|
||||
jump to another path, by explicitly dying with a status code or by throwing
|
||||
an exception (which effectively causes `die(500)`)
|
||||
(see `/examples/errorpages.ru`, `/examples/jumps.ru`)
|
||||
|
||||
If a jump is executed, the path of the request is rewritten locally, and the
|
||||
request is fed through the server again for processing. This is effectively
|
||||
a localized redirect which retains accumulated request processing
|
||||
information (i.e. instance variables)
|
||||
(see `/examples/jumps.ru`)
|
||||
|
||||
The tree can be changed at runtime, but it's generally not advisable to
|
||||
depend on that fact. If, eventually, some solution will be found to
|
||||
optimizing trees into linear routing paths, and if that solution is proven
|
||||
to improve performance, this statement might become false.
|
||||
|
||||
```plaintext
|
||||
+--------------------------------------+
|
||||
v |
|
||||
run (obj) -> App#call -> Server#call +-> Path#go -> ... -> Probe#go +
|
||||
| | (if app acts as a wrapper for another
|
||||
<-----------------------+ | Rack server and if response is 404
|
||||
(returns back to Rack server | with x-cascade header set)
|
||||
if no jumps occured) +-> passthrough#call
|
||||
```
|
Loading…
Reference in New Issue