V Platform Features

See What Is Deployed and How Components Talk

A new developer joins and asks which components the shop has, which events they publish and who calls whom. The running application answers that itself: it collects its topology and serves it as a page and as an HTTP API. Every component takes part without a declaration. What the topology is for is in the model article Introspection.

§Look at it

With the gateway running, the topology is published in two forms on the application’s hosts:

  • a page at /.introspection/, which draws the graph;
  • an HTTP API under /introspection/, which the page reads and which you can query.

Both need the system:introspection role (Roles).

Locally, the gateway and the service that collects the topology are part of sys, one of the two processes npm start keeps under PM2. Add introspection to the Context to shorten the interval at which observed calls are reported, and restart:

# context.toa.yaml
introspection:
  interval@local: 5
$ npm run restart
GET /introspection/nodes/ HTTP/1.1
host: localhost:8000
authorization: Token ...
accept: application/yaml
- id: f5f5f72d2495c71128a41f810a199452
  namespace: store
  component: orders
  version: 7bb04bba

Call an operation that calls another. Where approve of store.orders debits the customer’s wallet, approve an order, and within the interval GET /introspection/edges/ shows the call from store.orders.approve to billing.wallets.debit.

RequestAnswers
GET /introspection/nodes/every node
GET /introspection/nodes/:id/one node, with what it declares
GET /introspection/edges/every observed edge; [] when nothing has been called
GET /introspection/edges/:id/one edge

§An application without the gateway

Introspection needs the gateway, which publishes its API. An application that does not use the gateway has to turn introspection off:

# context.toa.yaml
introspection: false

§What it shows

Nodes are components, described from their manifests:

namespace: store
component: orders
entity:
  storage: '@toa.io/storages.mongodb'
  schema:
    properties:
      customer: { type: string }
      total: { type: integer }
operations:
  - endpoint: approve
    type: transition
    scope: entry
    input: …
    output: …
events:
  - label: created
  - label: approved
receivers:
  - label: fulfilment.shipments.refused
    source: fulfilment.shipments
    event: refused
    operation: cancel

An operation’s description from the manifest is carried along, so write one:

# components/store.orders/manifest.toa.yaml
operations:
  approve:
    description: Debits the customer's wallet and marks the order approved.

Event relations between components come from receivers and are there before any traffic.

Edges are calls observed while the application runs. No manifest lists calls, so an edge appears once the call has happened:

src:
  namespace: store
  component: orders
  operation: approve
dst:
  namespace: billing
  component: wallets
  operation: debit

The source of an edge is one of:

srcThe call was made by
namespace, component, operationan operation of a component
namespace, component, eventthe delivery of that event to a receiver
servicea service, such as the gateway or the command line; unknown for a caller that did not identify itself

A local call and a remote one are recorded the same way. A call is an edge whether the operation replied, returned an error or threw.

An edge is the pair it connects and nothing else. Inputs, replies and anything else the application passes between its components are not collected.

§Leave a component out

# components/billing.wallets/manifest.toa.yaml
introspection: false

The component is then not described as a node, and calls to it produce no edges.

§The page

The page is published at /.introspection/ on the hosts the Context declares for ingress, and the service behind it listens on port 8002:

# context.toa.yaml
ingress:
  hosts:
    - api.example.com
https://api.example.com/.introspection/

The host has to be one the gateway serves too, because the page reads the API on its own origin. The page itself is public, but shows nothing without an API session that has the system:introspection role.

To collect the topology without publishing the page:

# context.toa.yaml
introspection:
  ui: false

§The annotation

All keys are optional:

# context.toa.yaml
introspection:
  interval: 300
  threshold: 1024
  ui: true
  halt: false
  resources:
    cpu: [100m, 500m]
    memory: [128Mi, 256Mi]
KeyDefault
interval300Seconds between updates of the topology with newly observed calls.
threshold1024The number of distinct observed interactions that triggers an update before the interval ends.
uitruePublishes the page.
haltfalseAccepts halt signals, which stop the whole deployment: true, or bounds for what a signal may ask. See Halt.
resourcesthe Context’s resourcesWhat the introspection service may take in a deployment: a pair of request and limit for cpu and for memory. resources: ~ deploys it without any.

A new edge appears within interval seconds of the first call, not at once.

§What to use it for

  • To learn or check the structure. The graph shows the application as it is, not as a diagram drawn some time ago says it is.
  • To find a cycle before it closes. Event subscriptions that could form a circle are visible as declared relations, before a call chain is refused.
  • To decide on compositions. Components with many edges between them are candidates for sharing one.
  • To see what is unused. A declared relation with no observed edge, in an environment with real traffic, never fires.
Search
Search the documentation