Describe the Application
The shop works on your machine. To run it anywhere else, something has to say what the
application is called, what it connects to, how its components are grouped into processes and how
it is deployed. That is context.toa.yaml, the Context. toa create wrote yours; shipping the application is a matter of
adding to it.
§Where it starts
This is the Context toa create store wrote:
# context.toa.yaml
name: store
registry: registry.example.com/store
amqp: amqp://localhost
mongodb: mongodb://localhost
stash: redis://localhost
atomicity:
redis: redis://localhost
storages:
tmp:
provider: tmp
directory: store
exposition:
authorities:
local: localhost:8000
configuration:
identity.tokens:
keys:
- id: key0
key: $IDENTITY_TOKENS_ENCRYPTION_KEY0
ingress:
hosts: [localhost]
resources: ~ | Key | Says |
|---|---|
name | What the application is called. |
registry | Where its images are pushed. The value is a placeholder until you deploy. |
amqp, mongodb, stash | The addresses of the broker, the database and the cache: the ones npm run dock starts. |
atomicity.redis | The Redis through which replicas decide together. |
storages.tmp | A file storage kept in a temporary directory. |
exposition.authorities | The host the gateway answers on, under the name local. |
configuration | Values per component. The one entry is the key the gateway encrypts tokens with, as a reference to a secret; npm run env generates its local value. |
ingress.hosts | The hosts under which the gateway is reachable from outside. |
resources: ~ | No CPU and memory are stated for what is deployed; see Resources. |
name and registry are required by every command; the rest is what a local run asks for.
The components of a Context are the directories under components/ beside the file. Nothing
lists them.
An unknown top-level key is refused. A misspelled key fails every command that reads the Context, naming the key.
Every key, at any depth, may carry an @<environment> suffix to give a value for one environment
only: mongodb@production: mongodb://db.internal. See Give Each Environment Its Values.
§Name and version
name: store
version: 1.4.0
description: A small shop name— letters, digits and underscores in words joined by hyphens, starting with a letter. The deployed release and the application’s database are called by it:store.version— the version of what is deployed. A local run does not need it;toa deployrefuses a Context without one.description— optional.
§Images
registry:
base: registry.example.com/store
platforms: [linux/amd64]
credentials: registry-credentials
services: published
build:
arguments: [NPM_TOKEN]
run: apk add --no-cache ffmpeg
runtime:
version: 1.0.0
registry: https://npm.example.com
proxy: http://proxy.example.com:3128 registry— where images are pushed and how they are built.registry: <string>is shorthand forregistry.base.runtime— optional.versionis the Toa release the deployed images are built on; absent, it is the release of the CLI that deploys.runtime: 1.0.0is shorthand for it.registryandproxyare the npm registry and proxy an image build installs from.
Every option is shown in Build Images.
§Processes
compositions:
- name: core
components: [store.orders, billing.wallets]
services: [exposition]
replicas: 3
evicted:
components: [pictures]
resources:
cpu: [200m, 1]
memory: [256Mi, 1Gi]
mono:
replicas: 2 compositions— which components run together as one process, how many replicas, with what resources.evicted— components and services this deployment leaves out.resources— the default CPU and memory of every workload that states none of its own.mono— replicas and resources of the single-image deployment.
All four are shown in Decide What Runs Together.
§Ingress
ingress:
hosts: [api.example.com]
class: nginx
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 16m
default: true The hosts under which the gateway and the built-in pages are reachable from outside the cluster. See Deploy.
§Connectors and extensions
Every other key configures a connector or an extension:
amqp: amqp://rmq.example.com
mongodb: mongodb://mongo.example.com
stash: redis://redis.example.com
exposition:
authorities:
local: api.example.com
configuration:
store.orders:
limit: 100000 | Key | What it configures | Shown in |
|---|---|---|
amqp | the broker the components talk through | Connectors |
mongodb | the database | Connectors |
http | where a component answers streamed calls | Stream a Reply or an Input |
stash | transient shared state (Redis) | Stash |
storages | file storages | Storages |
exposition | the gateway | Running the Gateway |
realtime | realtime routes | Realtime |
configuration | component configuration values and secrets | Configuration |
telemetry | logs, traces, metrics | Exporting Telemetry |
introspection | the topology and halt | Introspection |
cadence | schedules and delayed calls | Do Something Later |
continuity | resuming failed workflows | Write a Multi-Step Workflow |
convergence | regions | Run in More Than One Region |
These keys are shortcuts for package names. A package without a shortcut is configured under annotations, by its name:
annotations:
'@toa.io/extensions.stash': redis://redis.example.com §Addresses
amqp, mongodb and stash take addresses. One address serves everything:
mongodb: mongodb://mongo.example.com To give a namespace or one component its own, write a map. A component takes the most specific
key that matches its <namespace>.<name>; . is the default:
mongodb:
.: mongodb://mongo.example.com # everything else
billing: mongodb://billing.mongo.example.com # `billing.wallets`, `billing.ledger`, …
billing.ledger: mongodb://ledger.example.com # `billing.ledger` alone Without a . key, a component that matches nothing is refused by name. A component without a
namespace is keyed by its name, accounts; default is the key of all such components.
A key may hold several addresses, as a list or a range; [0..31] expands to redis00 … redis31:
stash:
.:
- redis://cache.example.com
- redis://redis[0..31].example.com The broker has two sections. amqp: <address> is shorthand for amqp.context; amqp.sources holds the brokers that events of other applications come from, keyed by source:
amqp:
context: amqp://rmq.example.com
sources:
warehouse: amqp://rmq.warehouse.example.com An address never carries a user name or a password. They are supplied as secrets; see Supply Secrets. Addresses and Credentials has the rest.
§Resources of extension services
Some extensions run a process of their own: the gateway (exposition), the configuration values
service (configuration), the topology explorer (introspection), the scheduler (cadence).
The gateway, the values service and the explorer take resources inside their own key, in the
same form as the Context’s:
exposition:
resources:
cpu: [200m, 2]
memory: [200Mi, 1Gi] Without it the service takes the Context’s resources.
§Events another application reads
store.orders announces approved, and a warehouse system outside the
application listens. A deployed component publishes an event only when a receiver in the application consumes it, so an event read from outside
has to be named:
events:
- store.orders.approved Each entry is <namespace>.<component>.<event>, or <component>.<event> for a component
without a namespace: accounts.created. Without the entry and without a receiver, a
deployment does not publish approved at all. A local run, toa mono, and a composition
booted in a test publish every event, so the difference shows only after deploying. Announce a Change covers declaring events.
§Runtime settings
All optional.
atomicity:
redis: redis://redis.example.com
interval: 1000
outbox:
interval: 5000
batch: 100
retention: 86400
inbox:
retention: 3600
addressed:
timeout: 30000 | Key | Sets | Shown in |
|---|---|---|
atomicity.redis | one Redis address, or an odd number of independent ones, where replicas decide together | Shared Decisions |
atomicity.interval | how often a replica registers, ms, at least 100 | same |
outbox.interval | how often unpublished events are looked for, ms, at least 100 | Look After It |
outbox.batch | how many are read at once, at least 1 | same |
outbox.retention | seconds a published event is kept as a change log, 0 or more | same |
inbox.retention | seconds a call is remembered for deduplication, at least 600 | Handle Repeated Calls |
addressed.timeout | ms an addressed call waits for its reply by default | Keep Something in a Process |
§Every top-level key
| Key | Required | Purpose |
|---|---|---|
name | yes | the application’s name |
registry | yes | where images go and how they are built |
version | to deploy | the version of what is deployed |
description | no | a description |
runtime | no | Toa version, npm registry and proxy for builds |
compositions | no | components grouped into processes |
evicted | no | what this deployment leaves out |
resources | to deploy | default CPU and memory, or null |
mono | no | replicas and resources for --mono |
ingress | no | hosts, class and annotations for what is reachable from outside |
annotations | no | configuration of packages by package name |
| shortcut keys | no | amqp, mongodb, http, stash, storages, exposition, realtime, configuration, telemetry, introspection, cadence, continuity, convergence |
atomicity, outbox, inbox, addressed | no | runtime settings |
events | no | events consumed outside the application |
§A complete example
The generated Context, grown into one that also describes production. The shop has four
components by then, and limit is the setting Add Configuration declares:
# context.toa.yaml
name: store
version: 1.4.0
registry:
base@local: localhost:5000
base@production: registry.example.com/store
platforms@local: ~
resources:
cpu: [200m, 1]
memory: [256Mi, 1Gi]
compositions:
- name: core
components: [store.orders, billing.wallets, store.catalog]
replicas: 3
- name: media
components: [pictures]
amqp: amqp://localhost
amqp@production: amqp://rmq.internal.example.com
mongodb: mongodb://localhost
mongodb@production: mongodb://mongo.internal.example.com
stash: redis://localhost
stash@production: redis://redis.internal.example.com
atomicity:
redis: redis://localhost
redis@production: redis://redis.internal.example.com
storages:
tmp:
provider: tmp
directory: store
exposition:
authorities:
local: localhost:8000
local@production: api.example.com
ingress:
hosts: [localhost]
hosts@production: [api.example.com]
configuration:
identity.tokens:
keys:
- id: key0
key: $IDENTITY_TOKENS_ENCRYPTION_KEY0
store.orders:
limit: 100000
limit@local: 10000 One file describes the shop on a developer’s machine and in production.