V Platform Features

Turn On a Platform Feature

The catalog needs a cache, orders need a price limit that changes without a release, and somebody wants to count approvals. None of that is code you write: each is a feature of the platform that a component switches on by naming it in its manifest. A feature is provided by an extension or a connector; the model article Extensions says what those are.

You write something in two places: the component’s manifest and the Context.

§Declare it in the manifest

A component asks for an extension with a top-level key named after it. The smallest declaration has no value:

# components/store.catalog/manifest.toa.yaml
name: catalog
namespace: store

stash: ~

operations:
  price:
    input:
      type: object
      properties:
        product: { type: string }
      required: [product]

The operations of store.catalog now find the cache on their context:

// components/store.catalog/operations/price.ts
import type { Context, PriceInput } from '../types/index.d.ts'

export async function computation (input: PriceInput, context: Context) {
  return await context.stash.get(input.product)
}

What an extension puts on the operation context is called an aspect. Most extensions take a declaration with content instead of ~; what goes in it is described in the extension’s article. This one is the order limit that Add Configuration declares:

# components/store.orders/manifest.toa.yaml
configuration:
  schema:
    properties:
      limit: { type: integer }
    required: [limit]
  defaults:
    limit: 5000

A manifest that declares something the extension does not accept is refused when the manifest is read, before anything starts.

§What every component already has

Three extensions are present without a declaration:

ExtensionOn the context
Telemetrycontext.logs, context.span, context.metrics
Fetchcontext.fetch
Introspectionnothing; the component appears in the topology

Write a telemetry or introspection key only when the component has something to say to them: the metrics it records, or that it wants to be left out of the topology.

context.atom is also there for every component. It comes from a connector and has no manifest key at all.

§Set it up in the Context

Where the cache is, how much is logged and the like are written once for the whole application, in context.toa.yaml under the same key. These declarations are called annotations:

# context.toa.yaml
stash: redis://localhost

telemetry:
  logs:
    level: info

stash is there as toa create wrote it, with the address of the Redis that npm run dock starts; telemetry is added.

The manifest says the component uses a cache; the Context says where the cache is. A component never reads an address.

§A different value per environment

Append @ and an environment’s name to any key of the Context. The plain key is what every other environment takes:

# context.toa.yaml
stash: redis://localhost
stash@production: redis://redis.internal:6379

telemetry:
  logs:
    level: debug
    level@production: info

The suffix works at any depth of an annotation, on a key that holds a value or a whole block. See Environments.

§Try it

Restart the application, which writes its types, .env and the map again, and call the operation:

$ npm run restart
$ npx toa call store.catalog.price "{ input: { product: 'a1' } }"

The reply is null until something has been stored under that key. What a restart does is in Run It and Make a Change.

§The full form

The short keys are shortcuts. A manifest groups its extensions under extensions, keyed by package reference, and a Context groups its annotations under annotations:

# components/store.catalog/manifest.toa.yaml
extensions:
  '@toa.io/extensions.stash': ~
# context.toa.yaml
annotations:
  '@toa.io/extensions.stash': redis://redis.example.com

You need the full form only for an extension without a shortcut, which means one of your own: see Write an Extension of Your Own.

§What is supplied

KeyIn the manifestIn the ContextRead
configurationschema and defaultsvalues per componentAdd Configuration, Keep Settings and Secrets out of the Code, Change a Setting without Redeploying
(fetch)——Call an External Service
stash~the Redis addressCache Something All Replicas Share
state~—Keep Something in a Process
telemetrymetricslogs, traces, metrics, readinessWrite Logs, Follow a Request, Count Things, Send Telemetry to Grafana
introspectionfalse to opt outcollection, pageSee What Is Deployed
exposition, realtimeresources, routesauthorities, optionsExposing, Realtime
storagesnamed file storagesprovidersStorages
cadencepulses, schedulesoptionsRun Work on a Schedule, Do Something Later
continuitycontinuous effects—Write a Multi-Step Workflow
convergence—regionsRegions

Connectors are named in other places of the manifest and annotated the same way in the Context:

KeyWhat it isRead
atomicityContext only; context.atomCoordinate Replicas
mongodbthe database of the default storageConnectors
amqpthe message brokerConnectors
httpaddresses for streamed callsConnectors

Addresses and credentials for all of them are written one way, described in Addresses and Credentials.

§Ports that are taken

Some extensions run a process of their own, a service, and each service that listens takes a fixed port. Do not use them for anything you run in the same process:

PortTaken by
8000the gateway
8001the readiness probe of a composition
8002the introspection page
8003the configuration page
8004the readiness probe of the gateway
8005streamed calls to a component

Two services that claim the same port in one process are refused when the deployment is exported:

Port 8001 is claimed by both the readiness probe and the readiness probe of 'exposition-gateway'
Search
Search the documentation