VI Shipping

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: ~
KeySays
nameWhat the application is called.
registryWhere its images are pushed. The value is a placeholder until you deploy.
amqp, mongodb, stashThe addresses of the broker, the database and the cache: the ones npm run dock starts.
atomicity.redisThe Redis through which replicas decide together.
storages.tmpA file storage kept in a temporary directory.
exposition.authoritiesThe host the gateway answers on, under the name local.
configurationValues 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.hostsThe 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 deploy refuses 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 for registry.base.
  • runtime — optional. version is the Toa release the deployed images are built on; absent, it is the release of the CLI that deploys. runtime: 1.0.0 is shorthand for it. registry and proxy are 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
KeyWhat it configuresShown in
amqpthe broker the components talk throughConnectors
mongodbthe databaseConnectors
httpwhere a component answers streamed callsStream a Reply or an Input
stashtransient shared state (Redis)Stash
storagesfile storagesStorages
expositionthe gatewayRunning the Gateway
realtimerealtime routesRealtime
configurationcomponent configuration values and secretsConfiguration
telemetrylogs, traces, metricsExporting Telemetry
introspectionthe topology and haltIntrospection
cadenceschedules and delayed callsDo Something Later
continuityresuming failed workflowsWrite a Multi-Step Workflow
convergenceregionsRun 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
KeySetsShown in
atomicity.redisone Redis address, or an odd number of independent ones, where replicas decide togetherShared Decisions
atomicity.intervalhow often a replica registers, ms, at least 100same
outbox.intervalhow often unpublished events are looked for, ms, at least 100Look After It
outbox.batchhow many are read at once, at least 1same
outbox.retentionseconds a published event is kept as a change log, 0 or moresame
inbox.retentionseconds a call is remembered for deduplication, at least 600Handle Repeated Calls
addressed.timeoutms an addressed call waits for its reply by defaultKeep Something in a Process

§Every top-level key

KeyRequiredPurpose
nameyesthe application’s name
registryyeswhere images go and how they are built
versionto deploythe version of what is deployed
descriptionnoa description
runtimenoToa version, npm registry and proxy for builds
compositionsnocomponents grouped into processes
evictednowhat this deployment leaves out
resourcesto deploydefault CPU and memory, or null
mononoreplicas and resources for --mono
ingressnohosts, class and annotations for what is reachable from outside
annotationsnoconfiguration of packages by package name
shortcut keysnoamqp, mongodb, http, stash, storages, exposition, realtime, configuration, telemetry, introspection, cadence, continuity, convergence
atomicity, outbox, inbox, addressednoruntime settings
eventsnoevents 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.

Search
Search the documentation