mirror of
https://github.com/kennethreitz/12factor.git
synced 2026-06-05 23:10:17 +00:00
tweaks based on keith's feedback
This commit is contained in:
@@ -4,7 +4,11 @@
|
||||
The [process formation](/concurrency) is the array of processes that are used to do the app's regular business (such as handling web requests) as it runs. Separately, developers will often wish to do one-off administrative or maintenance tasks for the app, such as:
|
||||
|
||||
* Running database migrations (e.g. `manage.py syncdb` in Django, `rake db:migrate` in Rails).
|
||||
* Running a console (also known as a REPL shell) to run arbitrary code or inspect the app's models against the live database. Most languages provide a REPL by running the interpreter without any arguments (e.g. `python` or `node`) or in some cases have a separate command (e.g. `irb` for Ruby, `rails console` for Rails).
|
||||
* Running a console (also known as a [REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) shell) to run arbitrary code or inspect the app's models against the live database. Most languages provide a REPL by running the interpreter without any arguments (e.g. `python` or `erl`) or in some cases have a separate command (e.g. `irb` for Ruby, `rails console` for Rails).
|
||||
* Running one-time scripts committed into the app's repo (e.g. `php scripts/fix_bad_records.php`).
|
||||
|
||||
Twelve-factor apps are easiest to write in languages which provide a REPL shell out of the box, and which make it easy to run one-off scripts. In a local deploy, developers invoke one-off admin processes by a direct shell command inside the app's checkout directory. In a production deploy, developers can use ssh or other remote command execution mechanism provided by that deploy's execution environment to run such a process.
|
||||
One-off admin processes should be run in an identical environment as the regular [long-running processes](/processes) of the app. The run against a [release](/build-release-run), using the same [code](/codebase) and [config](/config) as any process run against that release.
|
||||
|
||||
The same [dependency isolation](/dependencies) techniques should be used on all process types. For example, if the Ruby web process uses the command `bundle exec thin start`, then a database migration should use `bundle exec rake db:migrate`. Likewise, a Python program using Virtualenv should use the vendored `bin/python` for running both the Tornado webserver and any `manage.py` admin processes.
|
||||
|
||||
Twelve-factor strongly favors languages which provide a REPL shell out of the box, and which make it easy to run one-off scripts. In a local deploy, developers invoke one-off admin processes by a direct shell command inside the app's checkout directory. In a production deploy, developers can use ssh or other remote command execution mechanism provided by that deploy's execution environment to run such a process.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
## V. Build, release, run
|
||||
### Strict separation of build stage and run stage
|
||||
|
||||
The process of turning a [codebase](/codebase) into a running app passes through three stages:
|
||||
A [codebase](/codebase) is transformed into a (non-development) deploy through three stages:
|
||||
|
||||
* The *build stage* is a transform which converts a code repo into an executable bundle known as a *build*. Using a version of the code at a commit specified by the deployment process, the build stage fetches and vendors [dependencies](/dependencies) and compiles binaries and assets.
|
||||
* The *release stage* takes the build produced by the build stage and combines it with the deploy's current [config](/config). The resulting *release* contains both the build and the config and is ready for immediate execution in the execution environment
|
||||
|
||||
@@ -11,4 +11,4 @@ This does not exclude individual processes from handling their own internal mult
|
||||
|
||||
The process model truly shines when it comes time to scale out. 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 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)).
|
||||
Twelve-factor app proceses [should never daemonize](http://dustin.github.com/2010/02/28/running-processes.html) or write PID files. It counts on the operating system's process manager (such as [Upstart](http://upstart.ubuntu.com/), a distributed process manager on a cloud platform, or a tool like [Foreman](http://blog.daviddollar.org/2011/05/06/introducing-foreman.html) in development) to manage [output streams](/logs), respond to crashed processes, and handle user-initialed restarts and shutdowns.
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
## III. Config
|
||||
### Store config in the environment
|
||||
|
||||
An app's *config* is everything that can vary between [deploys](/codebase) (staging, production, developer environments, etc). This includes:
|
||||
An app's *config* is everything that is likely to vary between [deploys](/codebase) (staging, production, developer environments, etc). This includes:
|
||||
|
||||
* Resource handles to the database, Memcached, and other [backing services](#)
|
||||
* Credentials to external services such as Amazon S3 or Twitter
|
||||
|
||||
@@ -5,7 +5,7 @@ Most programming languages offer a packaging system for distributing support lib
|
||||
|
||||
**A twelve-factor app never relies on implicit existence of system-wide packages.** It declares all dependencies, completely and exactly, via a *dependency declaration* manifest. Furthermore, it uses a *dependency isolation* tool during execution to ensure that no implicit dependencies "leak in" from the surrounding system. The full and explicit dependency specification is applied uniformly to both production and development
|
||||
|
||||
For example, [Gem Bundler](http://gembundler.com/) for Ruby offers the `Gemfile` manifest format for dependency declaration and `bundle exec` for dependency isolation. In, Python there are two separate tools for these steps -- [Pip](http://www.pip-installer.org/en/latest/) is used for declaration and [Virtualenv](http://www.virtualenv.org/en/latest/) for isolation. No matter what the toolchain, dependency declaration and isolation must always be used together -- only one or the other is not sufficient to satisfy twelve-factor.
|
||||
For example, [Gem Bundler](http://gembundler.com/) for Ruby offers the `Gemfile` manifest format for dependency declaration and `bundle exec` for dependency isolation. In, Python there are two separate tools for these steps -- [Pip](http://www.pip-installer.org/en/latest/) is used for declaration and [Virtualenv](http://www.virtualenv.org/en/latest/) for isolation. Even C has Autoconf for dependency declaration, and static linking can provide dependency isolation. No matter what the toolchain, dependency declaration and isolation must always be used together -- only one or the other is not sufficient to satisfy twelve-factor.
|
||||
|
||||
One benefit of explicit dependency declaration is that it simplifies setup for developers new to the app. The new developer can check out the app's codebase onto their development machine, requiring only the language runtime and dependency manager installed as prerequisites. They will be able to set up everything needed to run the app's code with a deterministic *build command*. For example, the build command for Ruby/Bundler is `bundle install`, while for Clojure/Leiningen it is `lein deps`.
|
||||
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@
|
||||
|
||||
*Logs* provide visibility into the behavior of a running app. In server-based environments they are commonly written to a file on disk (a "logfile"); but this is only an output format.
|
||||
|
||||
**Logs are the [stream](http://adam.heroku.com/past/2011/4/1/logs_are_streams_not_files/) of aggregated, time-ordered events collected from the output streams of all running processes and backing services.** Logs in their raw form are typically a text format with one event per line (though backtraces from exceptions may span multiple lines). Logs have no fixed beginning or end, but flow continously as long as the app is operating.
|
||||
Logs are the [stream](http://adam.heroku.com/past/2011/4/1/logs_are_streams_not_files/) of aggregated, time-ordered events collected from the output streams of all running processes and backing services. Logs in their raw form are typically a text format with one event per line (though backtraces from exceptions may span multiple lines). Logs have no fixed beginning or end, but flow continously as long as the app is operating.
|
||||
|
||||
A twelve-factor app never concerns itself with routing or storage of its output stream. It should not attempt to write to or manage logfiles. Instead, each running process writes its event stream, unbuffered, to `stdout`. During local development, the developer will view this stream in the foreground of their terminal to observe the app's behavior.
|
||||
**A twelve-factor app never concerns itself with routing or storage of its output stream.** It should not attempt to write to or manage logfiles. Instead, each running process writes its event stream, unbuffered, to `stdout`. During local development, the developer will view this stream in the foreground of their terminal to observe the app's behavior.
|
||||
|
||||
In staging or production deploys, each process' stream will be captured by the execution environment, collated together with all other streams from the app, and routed to one or more final destinations for viewing and long-term archival. These archival destinations are not visible to or configurable by the app, and instead are completely managed by the execution environment.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user