diff --git a/content/backing-services.md b/content/backing-services.md index da91f06..fb120b4 100644 --- a/content/backing-services.md +++ b/content/backing-services.md @@ -1,7 +1,7 @@ ## IV. Backing Services ### Treat backing services as attached resources -A *backing service* is any service the app accesses over the network as part of its normal operation. Examples include datastores (such as [MySQL](http://dev.mysql.com/) or [CouchDB](http://couchdb.apache.org/)), messaging/queueing systems (such as [RabbitMQ](http://www.rabbitmq.com/) or [Beanstalkd](http://kr.github.com/beanstalkd/)), SMTP services for outbound email (such as [Postfix](http://www.postfix.org/)), and caching systems (such as [Memcached](http://memcached.org/)). +A *backing service* is any service the app consumes over the network as part of its normal operation. Examples include datastores (such as [MySQL](http://dev.mysql.com/) or [CouchDB](http://couchdb.apache.org/)), messaging/queueing systems (such as [RabbitMQ](http://www.rabbitmq.com/) or [Beanstalkd](http://kr.github.com/beanstalkd/)), SMTP services for outbound email (such as [Postfix](http://www.postfix.org/)), and caching systems (such as [Memcached](http://memcached.org/)). Traditionally, backing services like the database are managed by the same admins as the app's deploy. In addition to these locally-managed services, the app may also have services provided and managed by third parties. Examples include SMTP services (such as [Postmark](http://postmarkapp.com/)), metrics-gathering services (such as [New Relic](http://newrelic.com/) or [Loggly](http://www.loggly.com/)), binary asset services (such as [Amazon S3](http://aws.amazon.com/s3/)), and even API-accessible consumer services (such as [Twitter](http://dev.twitter.com/), [Google Maps](http://code.google.com/apis/maps/index.html), or [Last.fm](http://www.last.fm/api)). diff --git a/content/concurrency.md b/content/concurrency.md index b72550a..ea85ab3 100644 --- a/content/concurrency.md +++ b/content/concurrency.md @@ -9,4 +9,4 @@ Any computer program, once run, is represented by one or more processes. Web ap The process model truly shines when it comes time to scale up. The [share-nothing, horizontally partitionable nature of twelve-factor app processes](/processes) means that adding more concurrency is a simple and reliable operation. The array of process types and number of processes of each type is known as the *process formation*: -Twelve-factor app proceses [should never daemonize](http://dustin.github.com/2010/02/28/running-processes.html) or write PID files. They count on the operating system's process manager ([Upstart](http://upstart.ubuntu.com/), [launchd](http://en.wikipedia.org/wiki/Launchd), or a distributed process manager on a cloud platform) to manage `stdout`, restarts after crashes, and restarts requested by the user (such as when deploying new code). +Twelve-factor app proceses [should never daemonize](http://dustin.github.com/2010/02/28/running-processes.html) or write PID files. They count on the operating system's process manager ([Upstart](http://upstart.ubuntu.com/), [launchd](http://en.wikipedia.org/wiki/Launchd), or a distributed process manager on a cloud platform) to manage the [output stream](/logs), restarts after crashes, and restarts requested by the user (such as when [deploying new code, or changing config](/build-release-run)). diff --git a/content/port-binding.md b/content/port-binding.md index 5efd20b..6fa12ba 100644 --- a/content/port-binding.md +++ b/content/port-binding.md @@ -1,12 +1,14 @@ ## VII. Port binding ### Services exported via port binding -Historically, web apps are often executed inside some kind of runtime container. For example, PHP apps might run as a module inside Apache, or Java apps might run inside Tomcat. +Traditionally, web apps are executed inside some kind of runtime container. For example, PHP apps might run as a module inside [Apache HTTPD](http://httpd.apache.org/), or Java apps might run inside [Tomcat](http://tomcat.apache.org/). -A twelve-factor app is completely self-contained and does not rely on runtime injection of a webserver into the execution environment to create a web-facing service. The web app exports HTTP as a service by binding to a port, and listening to requests coming in on that port. +**The twelve-factor app is completely self-contained** and does not rely on runtime injection of a webserver into the execution environment to create a web-facing service. The web app **exports HTTP as a service by binding to a port**, and listening to requests coming in on that port. In a local development environment, the developer visits a service URL like `http://localhost:5000/` to access the service exported by their app. In deployment, a routing layer handles routing requests from a public-facing hostname to the port-bound web processes. -This is typically implemented by using [dependency declaration](/dependencies) to add a webserver library to the app, such as [Tornado](http://www.tornadoweb.org/) for Python, [Thin](http://code.macournoyer.com/thin/) for Ruby, or [Jetty](http://jetty.codehaus.org/jetty/) for Java and other JVM-based languages. But this happens completely inside the app (known in this context as [*user space*](http://en.wikipedia.org/wiki/User_space)), and if the app developers chose to, they could write app code to accept raw TCP requests and parse the HTTP without any supporting libraries. Either way looks the same to the execution environment: the contract with the execution environment is binding to a port to serve requests, leaving the implementation details of what webserver is being used up to the web framework and/or the app's developers. +This is typically implemented by using [dependency declaration](/dependencies) to add a webserver library to the app, such as [Tornado](http://www.tornadoweb.org/) for Python, [Thin](http://code.macournoyer.com/thin/) for Ruby, or [Jetty](http://jetty.codehaus.org/jetty/) for Java and other JVM-based languages. This happens entirely in [*user space*](http://en.wikipedia.org/wiki/User_space) (within the app's code), and if the developers chose to, they could write app code to accept raw TCP requests and parse the HTTP without any supporting libraries. The contract with the execution environment is binding to a port to serve requests, leaving the implementation details of what webserver is being used up to the web framework and/or the app's developers. -HTTP is not the only service that can be exported by port binding. Nearly any kind of server software can be run via process-binds-to-a-port-to-receive-requests model. To examples include ejabberd (speaking XMPP), and Redis (speaking the Redis protocol). +HTTP is not the only service that can be exported by port binding. Nearly any kind of server software can be run via process-binds-to-a-port-to-receive-requests model. To examples include [ejabberd](http://www.ejabberd.im/) (speaking [XMPP](http://xmpp.org/)), and [Redis](http://redis.io/) (speaking the [Redis protocol](http://redis.io/topics/protocol)). + +Note also that the port-binding approach means that one app can become the [backing service](/backing-services) for another app, by providing the URL to the backing app as a resource handle in the [config](/config) for the consuming app. diff --git a/content/processes.md b/content/processes.md index 1ce8a93..fae6e41 100644 --- a/content/processes.md +++ b/content/processes.md @@ -1,15 +1,15 @@ ## VI. Processes ### Stateless processes handle application logic -The business logic of an app happens in the app code. This code gets executed in the execution environment as one or more *processes*. +The business logic of an app is codified in its [codebase](/codebase). The code is executed in the execution environment as one or more *processes*. In the simplest case, the code is a stand-alone script, the execution environment is a developer's local laptop with an installed language runtime, and the process is launched via the command line (for example, `python my_script.py`). On the other end of the spectrum, a production deploy of a sophisticated app may use many [process types, instantiated into zero or more running processes](/concurrency). -Twelve-factor processes are stateless and [share-nothing](http://en.wikipedia.org/wiki/Shared_nothing_architecture). The filesystem sitting beneath the process is either read-only (attempting a write will produce an error), or completely ephemeral (when the process terminates, all state written to disk will be discarded). Anything that needs to persist must be stored in a stateful [backing service](/backing-services), typically a database. +**Twelve-factor processes are stateless and [share-nothing](http://en.wikipedia.org/wiki/Shared_nothing_architecture).** The filesystem sitting beneath the process is either read-only (attempting a write will produce an error), or completely ephemeral (when the process terminates, all state written to disk will be discarded). Any data that needs to persist must be stored in a stateful [backing service](/backing-services), typically a database. -Process memory space and ephemeral filesystem can potentially be used as a brief, single-transaction cache. For example, downloading a large file, operating on it, and storing the results of the operation in the database. The twelve-factor app never assumes that anything cached in memory or on disk will be available on a future request or job - with many processes of each type running, chances are high that that a future request will be served by a different process. Even when running only one process, a restart (triggered by code deploy, config change, or the execution environment relocating the process to a different physical location) will wipe all state. +Process memory space and ephemeral filesystem can potentially be used as a brief, single-transaction cache. For example, downloading a large file, operating on it, and storing the results of the operation in the database. The twelve-factor app never assumes that anything cached in memory or on disk will be available on a future request or job - with many processes of each type running, chances are high that that a future request will be served by a different process. Even when running only one process, a restart (triggered by code deploy, config change, or the execution environment relocating the process to a different physical location) will wipe all filesystem and in-memory state. Asset packagers (such as [Jammit](http://documentcloud.github.com/jammit/) or [django-assetpackager](http://code.google.com/p/django-assetpackager/)) use the filesystem as a cache for compiled assets. A twelve-factor app is best served by doing this compiling during the [build stage](/build-release-run) rather than at runtime. -Some web systems rely on "sticky sessions" - that is, caching user session data in memory of the app's process and expecting future requests from the same visitor to be routed to the same process. Sticky sessions are a violation of twelve-factor and should never be used or relied upon. Session state is a good candidate for a datastore that offers time-expiration, such as Memcached or Redis. +Some web systems rely on "sticky sessions" - that is, caching user session data in memory of the app's process and expecting future requests from the same visitor to be routed to the same process. Sticky sessions are a violation of twelve-factor and should never be used or relied upon. Session state is a good candidate for a datastore that offers time-expiration, such as [Memcached](http://memcached.org/) or [Redis](http://redis.io/).